Skip to content

Commit abf4605

Browse files
authored
Merge pull request #81 from CS3219-AY2425S1/question-tests-create-update-delete
Additional Integration tests for question service
2 parents e5642a7 + 014d5b8 commit abf4605

File tree

7 files changed

+358
-49
lines changed

7 files changed

+358
-49
lines changed

apps/question-service/go.mod

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,16 @@ require (
1010
google.golang.org/grpc v1.67.1
1111
)
1212

13-
require github.com/joho/godotenv v1.5.1
13+
require (
14+
github.com/joho/godotenv v1.5.1
15+
github.com/stretchr/testify v1.9.0
16+
)
17+
18+
require (
19+
github.com/davecgh/go-spew v1.1.1 // indirect
20+
github.com/pmezard/go-difflib v1.0.0 // indirect
21+
gopkg.in/yaml.v3 v3.0.1 // indirect
22+
)
1423

1524
require (
1625
cloud.google.com/go v0.115.1 // indirect

apps/question-service/go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
203203
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
204204
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
205205
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
206+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
206207
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
207208
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
208209
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package tests
2+
3+
import (
4+
"context"
5+
"log"
6+
"os"
7+
"question-service/handlers"
8+
"question-service/utils"
9+
"testing"
10+
11+
"cloud.google.com/go/firestore"
12+
)
13+
14+
var service *handlers.Service
15+
var ctx = context.Background()
16+
17+
func TestMain(m *testing.M) {
18+
// Set FIRESTORE_EMULATOR_HOST environment variable.
19+
err := os.Setenv("FIRESTORE_EMULATOR_HOST", "127.0.0.1:8080")
20+
if err != nil {
21+
log.Fatalf("could not set env %v", err)
22+
}
23+
// Create client.
24+
client, err := firestore.NewClient(ctx, "my-project-id")
25+
service = &handlers.Service{Client: client}
26+
27+
if err != nil {
28+
log.Fatalf("could not create client %v", err)
29+
}
30+
defer client.Close()
31+
32+
m.Run()
33+
os.Exit(0)
34+
}
35+
36+
// Sets up the firestore emulator with the sample questions
37+
// This repopulates the db
38+
// Returns the docref of one of the questions if a test need it
39+
func setupDb(t *testing.T) string {
40+
// Repopulate document
41+
utils.Populate(service.Client, false)
42+
43+
coll := service.Client.Collection("questions")
44+
if coll == nil {
45+
t.Fatalf("Failed to get CollectionRef")
46+
}
47+
docRef, err := coll.DocumentRefs(ctx).Next()
48+
if err != nil {
49+
t.Fatalf("Failed to get DocRef: %v", err)
50+
}
51+
return docRef.ID
52+
}
53+
54+
func getCount(t *testing.T) int64 {
55+
counterDocRef, err := service.Client.Collection("counters").Doc("questions").Get(context.Background())
56+
if err != nil {
57+
t.Fatal(err)
58+
}
59+
fields := counterDocRef.Data()
60+
if err != nil {
61+
t.Fatal(err)
62+
}
63+
count := fields["count"].(int64)
64+
return count
65+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package tests
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"net/http"
7+
"net/http/httptest"
8+
"testing"
9+
10+
"question-service/models"
11+
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
// tests partially generated using Github Copilot
16+
17+
func createCreateRequestWithData(_ *testing.T, body []byte) *http.Request {
18+
req := httptest.NewRequest(http.MethodPost, "http://localhost:12345/questions", bytes.NewBuffer(body))
19+
20+
return req
21+
}
22+
23+
func TestCreateQuestion(t *testing.T) {
24+
t.Run("Create new question", func(t *testing.T) {
25+
var err error
26+
27+
newQuestion := models.Question{
28+
Title: "New Question",
29+
Description: "New Description",
30+
Complexity: models.Medium,
31+
Categories: []string{"Category1"},
32+
33+
DocRefID: "a-doc-ref-id",
34+
}
35+
36+
setupDb(t)
37+
beforeCount := getCount(t)
38+
39+
w := httptest.NewRecorder()
40+
data, err := json.Marshal(newQuestion)
41+
assert.NoError(t, err)
42+
req := createCreateRequestWithData(t, data)
43+
service.CreateQuestion(w, req)
44+
afterCount := getCount(t)
45+
// Check response
46+
assert.Equal(t, http.StatusOK, w.Code)
47+
var response models.Question
48+
err = json.NewDecoder(w.Body).Decode(&response)
49+
assert.NoError(t, err)
50+
assert.Equal(t, newQuestion.Title, response.Title)
51+
assert.Equal(t, newQuestion.Description, response.Description)
52+
assert.Equal(t, newQuestion.Complexity, response.Complexity)
53+
assert.Equal(t, newQuestion.Categories, response.Categories)
54+
assert.Equal(t, beforeCount+1, afterCount)
55+
})
56+
57+
t.Run("Create question with missing title", func(t *testing.T) {
58+
newQuestion := models.Question{
59+
Description: "New Description",
60+
Complexity: models.Medium,
61+
Categories: []string{"Category1"},
62+
}
63+
64+
setupDb(t)
65+
beforeCount := getCount(t)
66+
67+
w := httptest.NewRecorder()
68+
data, _ := json.Marshal(newQuestion)
69+
req := createCreateRequestWithData(t, data)
70+
service.CreateQuestion(w, req)
71+
72+
// Check response
73+
assert.Equal(t, http.StatusBadRequest, w.Code)
74+
assert.Contains(t, w.Body.String(), "Title is required")
75+
assert.Equal(t, beforeCount, getCount(t))
76+
})
77+
78+
t.Run("Create question with duplicate title", func(t *testing.T) {
79+
newQuestion := models.Question{
80+
Title: "Duplicate Title",
81+
Description: "New Description",
82+
Complexity: models.Medium,
83+
Categories: []string{"Category1"},
84+
}
85+
86+
setupDb(t)
87+
88+
// Create the first question
89+
w := httptest.NewRecorder()
90+
data, _ := json.Marshal(newQuestion)
91+
req := createCreateRequestWithData(t, data)
92+
service.CreateQuestion(w, req)
93+
assert.Equal(t, http.StatusOK, w.Code)
94+
95+
// Try to create the second question with the same title
96+
w = httptest.NewRecorder()
97+
req = createCreateRequestWithData(t, data)
98+
service.CreateQuestion(w, req)
99+
100+
// Check response
101+
assert.Equal(t, http.StatusBadRequest, w.Code)
102+
assert.Contains(t, w.Body.String(), "Question title already exists")
103+
})
104+
105+
t.Run("Create question with empty description", func(t *testing.T) {
106+
newQuestion := models.Question{
107+
Title: "New Question",
108+
Description: "",
109+
Complexity: models.Medium,
110+
Categories: []string{"Category1"},
111+
}
112+
113+
setupDb(t)
114+
115+
w := httptest.NewRecorder()
116+
data, _ := json.Marshal(newQuestion)
117+
req := createCreateRequestWithData(t, data)
118+
service.CreateQuestion(w, req)
119+
120+
// Check response
121+
assert.Equal(t, http.StatusBadRequest, w.Code)
122+
assert.Contains(t, w.Body.String(), "Description is required")
123+
})
124+
125+
t.Run("Create question with nil title", func(t *testing.T) {
126+
newQuestion := models.Question{
127+
// Title: "New Question",
128+
Description: "New Description",
129+
Complexity: models.Medium,
130+
Categories: []string{"Category1"},
131+
}
132+
133+
setupDb(t)
134+
135+
w := httptest.NewRecorder()
136+
data, _ := json.Marshal(newQuestion)
137+
req := createCreateRequestWithData(t, data)
138+
service.CreateQuestion(w, req)
139+
140+
// Check response
141+
assert.Equal(t, http.StatusBadRequest, w.Code)
142+
assert.Contains(t, w.Body.String(), "Title is required")
143+
})
144+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package tests
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"net/http/httptest"
7+
"testing"
8+
9+
"github.com/go-chi/chi/v5"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
// tests partially generated using Github Copilot
14+
15+
func createDeleteRequestWithId(docRefID string) *http.Request {
16+
rctx := chi.NewRouteContext()
17+
rctx.URLParams.Add("docRefID", docRefID)
18+
19+
req := httptest.NewRequest(http.MethodDelete, "/questions/"+docRefID, nil)
20+
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
21+
return req
22+
}
23+
24+
func TestDeleteQuestion(t *testing.T) {
25+
26+
t.Run("Delete existing question", func(t *testing.T) {
27+
docRefID := setupDb(t)
28+
req := createDeleteRequestWithId(docRefID)
29+
res := httptest.NewRecorder()
30+
31+
service.DeleteQuestion(res, req)
32+
33+
assert.Equal(t, http.StatusOK, res.Code)
34+
assert.Equal(t, res.Body.String(), "Question with ID "+docRefID+" deleted successfully")
35+
})
36+
37+
t.Run("Delete non-existing question", func(t *testing.T) {
38+
nonExistentDocRefID := "non-existent-id"
39+
req := createDeleteRequestWithId(nonExistentDocRefID)
40+
res := httptest.NewRecorder()
41+
42+
service.DeleteQuestion(res, req)
43+
44+
assert.Equal(t, http.StatusNotFound, res.Code)
45+
assert.Equal(t, res.Body.String(), "Question not found\n")
46+
})
47+
}

apps/question-service/tests/read_test.go

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,15 @@ package tests
22

33
import (
44
"context"
5-
"log"
65
"net/http"
76
"net/http/httptest"
8-
"os"
9-
"question-service/handlers"
10-
"question-service/utils"
117
"strings"
128
"testing"
139

14-
"cloud.google.com/go/firestore"
1510
"github.com/go-chi/chi/v5"
1611
)
1712

18-
var service *handlers.Service
19-
var ctx = context.Background()
20-
21-
func TestMain(m *testing.M) {
22-
// Set FIRESTORE_EMULATOR_HOST environment variable.
23-
err := os.Setenv("FIRESTORE_EMULATOR_HOST", "127.0.0.1:8080")
24-
if err != nil {
25-
log.Fatalf("could not set env %v", err)
26-
}
27-
// Create client.
28-
client, err := firestore.NewClient(ctx, "my-project-id")
29-
service = &handlers.Service{Client: client}
30-
31-
if err != nil {
32-
log.Fatalf("could not create client %v", err)
33-
}
34-
defer client.Close()
35-
36-
m.Run()
37-
os.Exit(0)
38-
}
39-
40-
// Sets up the firestore emulator with the sample questions
41-
// This repopulates the db
42-
// Returns the docref of one of the questions if a test need it
43-
func setupDb(t *testing.T) string {
44-
// Repopulate document
45-
utils.Populate(service.Client, false)
46-
47-
coll := service.Client.Collection("questions")
48-
if coll == nil {
49-
t.Fatalf("Failed to get CollectionRef")
50-
}
51-
docRef, err := coll.DocumentRefs(ctx).Next()
52-
if err != nil {
53-
t.Fatalf("Failed to get DocRef: %v", err)
54-
}
55-
return docRef.ID
56-
}
57-
58-
func ReadRequestWithId(id string) *http.Request {
13+
func readRequestWithId(id string) *http.Request {
5914
// adds chi context
6015
// https://stackoverflow.com/questions/54580582/testing-chi-routes-w-path-variables
6116
rctx := chi.NewRouteContext()
@@ -69,7 +24,7 @@ func Test_Read(t *testing.T) {
6924
id := setupDb(t)
7025

7126
res := httptest.NewRecorder()
72-
req := ReadRequestWithId(id)
27+
req := readRequestWithId(id)
7328

7429
service.ReadQuestion(res, req)
7530

@@ -82,7 +37,7 @@ func Test_ReadNotFound(t *testing.T) {
8237
setupDb(t)
8338

8439
res := httptest.NewRecorder()
85-
req := ReadRequestWithId("invalid-docref")
40+
req := readRequestWithId("invalid-docref")
8641

8742
service.ReadQuestion(res, req)
8843

0 commit comments

Comments
 (0)