Skip to content

Commit

Permalink
Merge pull request #81 from CS3219-AY2425S1/question-tests-create-upd…
Browse files Browse the repository at this point in the history
…ate-delete

Additional Integration tests for question service
  • Loading branch information
tituschewxj authored Nov 13, 2024
2 parents e5642a7 + 014d5b8 commit abf4605
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 49 deletions.
11 changes: 10 additions & 1 deletion apps/question-service/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@ require (
google.golang.org/grpc v1.67.1
)

require github.com/joho/godotenv v1.5.1
require (
github.com/joho/godotenv v1.5.1
github.com/stretchr/testify v1.9.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

require (
cloud.google.com/go v0.115.1 // indirect
Expand Down
1 change: 1 addition & 0 deletions apps/question-service/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
65 changes: 65 additions & 0 deletions apps/question-service/tests/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package tests

import (
"context"
"log"
"os"
"question-service/handlers"
"question-service/utils"
"testing"

"cloud.google.com/go/firestore"
)

var service *handlers.Service
var ctx = context.Background()

func TestMain(m *testing.M) {
// Set FIRESTORE_EMULATOR_HOST environment variable.
err := os.Setenv("FIRESTORE_EMULATOR_HOST", "127.0.0.1:8080")
if err != nil {
log.Fatalf("could not set env %v", err)
}
// Create client.
client, err := firestore.NewClient(ctx, "my-project-id")
service = &handlers.Service{Client: client}

if err != nil {
log.Fatalf("could not create client %v", err)
}
defer client.Close()

m.Run()
os.Exit(0)
}

// Sets up the firestore emulator with the sample questions
// This repopulates the db
// Returns the docref of one of the questions if a test need it
func setupDb(t *testing.T) string {
// Repopulate document
utils.Populate(service.Client, false)

coll := service.Client.Collection("questions")
if coll == nil {
t.Fatalf("Failed to get CollectionRef")
}
docRef, err := coll.DocumentRefs(ctx).Next()
if err != nil {
t.Fatalf("Failed to get DocRef: %v", err)
}
return docRef.ID
}

func getCount(t *testing.T) int64 {
counterDocRef, err := service.Client.Collection("counters").Doc("questions").Get(context.Background())
if err != nil {
t.Fatal(err)
}
fields := counterDocRef.Data()
if err != nil {
t.Fatal(err)
}
count := fields["count"].(int64)
return count
}
144 changes: 144 additions & 0 deletions apps/question-service/tests/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package tests

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

"question-service/models"

"github.com/stretchr/testify/assert"
)

// tests partially generated using Github Copilot

func createCreateRequestWithData(_ *testing.T, body []byte) *http.Request {
req := httptest.NewRequest(http.MethodPost, "http://localhost:12345/questions", bytes.NewBuffer(body))

return req
}

func TestCreateQuestion(t *testing.T) {
t.Run("Create new question", func(t *testing.T) {
var err error

newQuestion := models.Question{
Title: "New Question",
Description: "New Description",
Complexity: models.Medium,
Categories: []string{"Category1"},

DocRefID: "a-doc-ref-id",
}

setupDb(t)
beforeCount := getCount(t)

w := httptest.NewRecorder()
data, err := json.Marshal(newQuestion)
assert.NoError(t, err)
req := createCreateRequestWithData(t, data)
service.CreateQuestion(w, req)
afterCount := getCount(t)
// Check response
assert.Equal(t, http.StatusOK, w.Code)
var response models.Question
err = json.NewDecoder(w.Body).Decode(&response)
assert.NoError(t, err)
assert.Equal(t, newQuestion.Title, response.Title)
assert.Equal(t, newQuestion.Description, response.Description)
assert.Equal(t, newQuestion.Complexity, response.Complexity)
assert.Equal(t, newQuestion.Categories, response.Categories)
assert.Equal(t, beforeCount+1, afterCount)
})

t.Run("Create question with missing title", func(t *testing.T) {
newQuestion := models.Question{
Description: "New Description",
Complexity: models.Medium,
Categories: []string{"Category1"},
}

setupDb(t)
beforeCount := getCount(t)

w := httptest.NewRecorder()
data, _ := json.Marshal(newQuestion)
req := createCreateRequestWithData(t, data)
service.CreateQuestion(w, req)

// Check response
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, w.Body.String(), "Title is required")
assert.Equal(t, beforeCount, getCount(t))
})

t.Run("Create question with duplicate title", func(t *testing.T) {
newQuestion := models.Question{
Title: "Duplicate Title",
Description: "New Description",
Complexity: models.Medium,
Categories: []string{"Category1"},
}

setupDb(t)

// Create the first question
w := httptest.NewRecorder()
data, _ := json.Marshal(newQuestion)
req := createCreateRequestWithData(t, data)
service.CreateQuestion(w, req)
assert.Equal(t, http.StatusOK, w.Code)

// Try to create the second question with the same title
w = httptest.NewRecorder()
req = createCreateRequestWithData(t, data)
service.CreateQuestion(w, req)

// Check response
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, w.Body.String(), "Question title already exists")
})

t.Run("Create question with empty description", func(t *testing.T) {
newQuestion := models.Question{
Title: "New Question",
Description: "",
Complexity: models.Medium,
Categories: []string{"Category1"},
}

setupDb(t)

w := httptest.NewRecorder()
data, _ := json.Marshal(newQuestion)
req := createCreateRequestWithData(t, data)
service.CreateQuestion(w, req)

// Check response
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, w.Body.String(), "Description is required")
})

t.Run("Create question with nil title", func(t *testing.T) {
newQuestion := models.Question{
// Title: "New Question",
Description: "New Description",
Complexity: models.Medium,
Categories: []string{"Category1"},
}

setupDb(t)

w := httptest.NewRecorder()
data, _ := json.Marshal(newQuestion)
req := createCreateRequestWithData(t, data)
service.CreateQuestion(w, req)

// Check response
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, w.Body.String(), "Title is required")
})
}
47 changes: 47 additions & 0 deletions apps/question-service/tests/delete_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package tests

import (
"context"
"net/http"
"net/http/httptest"
"testing"

"github.com/go-chi/chi/v5"
"github.com/stretchr/testify/assert"
)

// tests partially generated using Github Copilot

func createDeleteRequestWithId(docRefID string) *http.Request {
rctx := chi.NewRouteContext()
rctx.URLParams.Add("docRefID", docRefID)

req := httptest.NewRequest(http.MethodDelete, "/questions/"+docRefID, nil)
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx))
return req
}

func TestDeleteQuestion(t *testing.T) {

t.Run("Delete existing question", func(t *testing.T) {
docRefID := setupDb(t)
req := createDeleteRequestWithId(docRefID)
res := httptest.NewRecorder()

service.DeleteQuestion(res, req)

assert.Equal(t, http.StatusOK, res.Code)
assert.Equal(t, res.Body.String(), "Question with ID "+docRefID+" deleted successfully")
})

t.Run("Delete non-existing question", func(t *testing.T) {
nonExistentDocRefID := "non-existent-id"
req := createDeleteRequestWithId(nonExistentDocRefID)
res := httptest.NewRecorder()

service.DeleteQuestion(res, req)

assert.Equal(t, http.StatusNotFound, res.Code)
assert.Equal(t, res.Body.String(), "Question not found\n")
})
}
51 changes: 3 additions & 48 deletions apps/question-service/tests/read_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,15 @@ package tests

import (
"context"
"log"
"net/http"
"net/http/httptest"
"os"
"question-service/handlers"
"question-service/utils"
"strings"
"testing"

"cloud.google.com/go/firestore"
"github.com/go-chi/chi/v5"
)

var service *handlers.Service
var ctx = context.Background()

func TestMain(m *testing.M) {
// Set FIRESTORE_EMULATOR_HOST environment variable.
err := os.Setenv("FIRESTORE_EMULATOR_HOST", "127.0.0.1:8080")
if err != nil {
log.Fatalf("could not set env %v", err)
}
// Create client.
client, err := firestore.NewClient(ctx, "my-project-id")
service = &handlers.Service{Client: client}

if err != nil {
log.Fatalf("could not create client %v", err)
}
defer client.Close()

m.Run()
os.Exit(0)
}

// Sets up the firestore emulator with the sample questions
// This repopulates the db
// Returns the docref of one of the questions if a test need it
func setupDb(t *testing.T) string {
// Repopulate document
utils.Populate(service.Client, false)

coll := service.Client.Collection("questions")
if coll == nil {
t.Fatalf("Failed to get CollectionRef")
}
docRef, err := coll.DocumentRefs(ctx).Next()
if err != nil {
t.Fatalf("Failed to get DocRef: %v", err)
}
return docRef.ID
}

func ReadRequestWithId(id string) *http.Request {
func readRequestWithId(id string) *http.Request {
// adds chi context
// https://stackoverflow.com/questions/54580582/testing-chi-routes-w-path-variables
rctx := chi.NewRouteContext()
Expand All @@ -69,7 +24,7 @@ func Test_Read(t *testing.T) {
id := setupDb(t)

res := httptest.NewRecorder()
req := ReadRequestWithId(id)
req := readRequestWithId(id)

service.ReadQuestion(res, req)

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

res := httptest.NewRecorder()
req := ReadRequestWithId("invalid-docref")
req := readRequestWithId("invalid-docref")

service.ReadQuestion(res, req)

Expand Down
Loading

0 comments on commit abf4605

Please sign in to comment.