Skip to content

Commit

Permalink
Merge pull request #21 from ls1intum/server-tests
Browse files Browse the repository at this point in the history
Writing tests for all server modules
  • Loading branch information
niclasheun authored Dec 6, 2024
2 parents d95ca47 + 14f956d commit 8f13331
Show file tree
Hide file tree
Showing 27 changed files with 1,892 additions and 29 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/go-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Go Test

on:
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
directory: [ 'server' ]

steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: 1.22
cache-dependency-path: "**/*.sum"
- name: Install dependencies
run: cd ${{ matrix.directory }} && go mod download
- name: Test with Go
run: cd ${{ matrix.directory }} && go test ./... -json > TestResults-${{ matrix.directory }}.json
- name: Upload Go test results
uses: actions/upload-artifact@v4
with:
name: Go-results-${{ matrix.directory }}
path: ./${{ matrix.directory }}/TestResults-${{ matrix.directory }}.json
3 changes: 2 additions & 1 deletion clients/shared_library/interfaces/course_phase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ export interface CoursePhase {
id: string
course_id: string
name: string
meta_data: Array<JSON>
//meta_data: Array<JSON> This DTO is used for getting all courses
// in all courses we do not send the phase meta data
is_initial_phase: boolean
sequence_order: number
course_phase_type_id: string
Expand Down
1 change: 1 addition & 0 deletions server/application/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package application
3 changes: 2 additions & 1 deletion server/course/courseParticipation/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import (
func setupCourseParticipationRouter(router *gin.RouterGroup) {
// incoming path should be /course/:uuid/
courseParticipation := router.Group("/courses/:uuid/participations")
courseParticipation.GET("/", getCourseParticipationsForCourse)
courseParticipation.GET("", getCourseParticipationsForCourse)
courseParticipation.POST("/enroll", createCourseParticipation)
}

// TODO: in future think about how to integrate / create "passed" students from previous phases
func getCourseParticipationsForCourse(c *gin.Context) {
id, err := uuid.Parse(c.Param("uuid"))
if err != nil {
Expand Down
112 changes: 112 additions & 0 deletions server/course/courseParticipation/router_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package courseParticipation

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

"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/niclasheun/prompt2.0/course/courseParticipation/courseParticipationDTO"
"github.com/niclasheun/prompt2.0/testutils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

type RouterTestSuite struct {
suite.Suite
router *gin.Engine
ctx context.Context
cleanup func()
courseParticipationService CourseParticipationService
}

func (suite *RouterTestSuite) SetupSuite() {
suite.ctx = context.Background()

// Set up PostgreSQL container
testDB, cleanup, err := testutils.SetupTestDB(suite.ctx, "../../database_dumps/course_participation_test.sql")
if err != nil {
log.Fatalf("Failed to set up test database: %v", err)
}

suite.cleanup = cleanup
suite.courseParticipationService = CourseParticipationService{
queries: *testDB.Queries,
conn: testDB.Conn,
}
CourseParticipationServiceSingleton = &suite.courseParticipationService

suite.router = setupRouter()
}

func (suite *RouterTestSuite) TearDownSuite() {
suite.cleanup()
}

func setupRouter() *gin.Engine {
router := gin.Default()
api := router.Group("/api")
setupCourseParticipationRouter(api)
return router
}

func (suite *RouterTestSuite) TestGetCourseParticipationsForCourse() {
courseID := "3f42d322-e5bf-4faa-b576-51f2cab14c2e"

req := httptest.NewRequest(http.MethodGet, "/api/courses/"+courseID+"/participations", nil)
w := httptest.NewRecorder()

suite.router.ServeHTTP(w, req)

assert.Equal(suite.T(), http.StatusOK, w.Code)

var participations []courseParticipationDTO.GetCourseParticipation
err := json.Unmarshal(w.Body.Bytes(), &participations)
assert.NoError(suite.T(), err)
assert.Greater(suite.T(), len(participations), 0, "Expected participations for the course")

expectedStudentIDs := []uuid.UUID{
uuid.MustParse("3d1f3b00-87f3-433b-a713-178c4050411a"),
uuid.MustParse("7dc1c4e8-4255-4874-80a0-0c12b958744b"),
uuid.MustParse("500db7ed-2eb2-42d0-82b3-8750e12afa8b"),
}

for i, participation := range participations {
assert.Equal(suite.T(), uuid.MustParse(courseID), participation.CourseID, "Expected CourseID to match")
assert.Equal(suite.T(), expectedStudentIDs[i], participation.StudentID, "Expected StudentID to match")
}
}

func (suite *RouterTestSuite) TestCreateCourseParticipation() {
courseID := "918977e1-2d27-4b55-9064-8504ff027a1a"
newParticipation := courseParticipationDTO.CreateCourseParticipation{
StudentID: uuid.MustParse("3d1f3b00-87f3-433b-a713-178c4050411a"),
}

body, _ := json.Marshal(newParticipation)
req := httptest.NewRequest(http.MethodPost, "/api/courses/"+courseID+"/participations/enroll", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()

suite.router.ServeHTTP(w, req)

assert.Equal(suite.T(), http.StatusOK, w.Code)

var createdParticipation courseParticipationDTO.GetCourseParticipation
err := json.Unmarshal(w.Body.Bytes(), &createdParticipation)
assert.NoError(suite.T(), err)

// Validate the created participation
assert.Equal(suite.T(), uuid.MustParse(courseID), createdParticipation.CourseID, "Expected CourseID to match")
assert.Equal(suite.T(), newParticipation.StudentID, createdParticipation.StudentID, "Expected StudentID to match")
assert.NotEqual(suite.T(), uuid.Nil, createdParticipation.ID, "Expected a valid UUID for the new participation")
}

func TestRouterTestSuite(t *testing.T) {
suite.Run(t, new(RouterTestSuite))
}
97 changes: 97 additions & 0 deletions server/course/courseParticipation/service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package courseParticipation

import (
"context"
"testing"

"github.com/google/uuid"
"github.com/niclasheun/prompt2.0/course/courseParticipation/courseParticipationDTO"
"github.com/niclasheun/prompt2.0/testutils"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

type CourseParticipationTestSuite struct {
suite.Suite
ctx context.Context
cleanup func()
courseParticipationService CourseParticipationService
}

func (suite *CourseParticipationTestSuite) SetupSuite() {
suite.ctx = context.Background()

// Set up PostgreSQL container
testDB, cleanup, err := testutils.SetupTestDB(suite.ctx, "../../database_dumps/course_participation_test.sql")
if err != nil {
log.Fatalf("Failed to set up test database: %v", err)
}

suite.cleanup = cleanup
suite.courseParticipationService = CourseParticipationService{
queries: *testDB.Queries,
conn: testDB.Conn,
}
CourseParticipationServiceSingleton = &suite.courseParticipationService
}

func (suite *CourseParticipationTestSuite) TearDownSuite() {
suite.cleanup()
}

func (suite *CourseParticipationTestSuite) TestGetAllCourseParticipationsForCourse() {
courseID := uuid.MustParse("3f42d322-e5bf-4faa-b576-51f2cab14c2e")
participations, err := GetAllCourseParticipationsForCourse(suite.ctx, courseID)

assert.NoError(suite.T(), err)
assert.Greater(suite.T(), len(participations), 0, "Expected participations for the course")

expectedStudentIDs := []uuid.UUID{
uuid.MustParse("3d1f3b00-87f3-433b-a713-178c4050411a"),
uuid.MustParse("7dc1c4e8-4255-4874-80a0-0c12b958744b"),
uuid.MustParse("500db7ed-2eb2-42d0-82b3-8750e12afa8b"),
}

for i, participation := range participations {
assert.Equal(suite.T(), courseID, participation.CourseID, "Expected CourseID to match")
assert.Equal(suite.T(), expectedStudentIDs[i], participation.StudentID, "Expected StudentID to match")
}
}

func (suite *CourseParticipationTestSuite) TestGetAllCourseParticipationsForStudent() {
studentID := uuid.MustParse("7dc1c4e8-4255-4874-80a0-0c12b958744b")
participations, err := GetAllCourseParticipationsForStudent(suite.ctx, studentID)

assert.NoError(suite.T(), err)
assert.Greater(suite.T(), len(participations), 0, "Expected participations for the student")

expectedCourseIDs := []uuid.UUID{
uuid.MustParse("3f42d322-e5bf-4faa-b576-51f2cab14c2e"),
uuid.MustParse("918977e1-2d27-4b55-9064-8504ff027a1a"),
}

for i, participation := range participations {
assert.Equal(suite.T(), studentID, participation.StudentID, "Expected StudentID to match")
assert.Equal(suite.T(), expectedCourseIDs[i], participation.CourseID, "Expected CourseID to match")
}
}

func (suite *CourseParticipationTestSuite) TestCreateCourseParticipation() {
newParticipation := courseParticipationDTO.CreateCourseParticipation{
CourseID: uuid.MustParse("918977e1-2d27-4b55-9064-8504ff027a1a"),
StudentID: uuid.MustParse("3d1f3b00-87f3-433b-a713-178c4050411a"),
}

createdParticipation, err := CreateCourseParticipation(suite.ctx, newParticipation)
assert.NoError(suite.T(), err)

// Verify the created participation
assert.Equal(suite.T(), newParticipation.CourseID, createdParticipation.CourseID, "Expected CourseID to match")
assert.Equal(suite.T(), newParticipation.StudentID, createdParticipation.StudentID, "Expected StudentID to match")
assert.NotEqual(suite.T(), uuid.Nil, createdParticipation.ID, "Expected a valid UUID for the new participation")
}

func TestCourseParticipationTestSuite(t *testing.T) {
suite.Run(t, new(CourseParticipationTestSuite))
}
62 changes: 62 additions & 0 deletions server/course/courseParticipation/validation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package courseParticipation

import (
"testing"

"github.com/google/uuid"
"github.com/niclasheun/prompt2.0/course/courseParticipation/courseParticipationDTO"
"github.com/stretchr/testify/assert"
)

func TestValidate(t *testing.T) {
tests := []struct {
name string
input courseParticipationDTO.CreateCourseParticipation
expectedError string
}{
{
name: "valid course participation",
input: courseParticipationDTO.CreateCourseParticipation{
CourseID: uuid.New(),
StudentID: uuid.New(),
},
expectedError: "",
},
{
name: "missing course ID",
input: courseParticipationDTO.CreateCourseParticipation{
CourseID: uuid.Nil,
StudentID: uuid.New(),
},
expectedError: "validation error: course id is required",
},
{
name: "missing student ID",
input: courseParticipationDTO.CreateCourseParticipation{
CourseID: uuid.New(),
StudentID: uuid.Nil,
},
expectedError: "validation error: student id is required",
},
{
name: "missing both course ID and student ID",
input: courseParticipationDTO.CreateCourseParticipation{
CourseID: uuid.Nil,
StudentID: uuid.Nil,
},
expectedError: "validation error: course id is required",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := Validate(tt.input)
if tt.expectedError == "" {
assert.NoError(t, err)
} else {
assert.Error(t, err)
assert.EqualError(t, err, tt.expectedError)
}
})
}
}
Loading

0 comments on commit 8f13331

Please sign in to comment.