github.com/quickfeed/quickfeed@v0.0.0-20240507093252-ed8ca812a09c/database/gormdb_assignment_test.go (about) 1 package database_test 2 3 import ( 4 "testing" 5 6 "github.com/google/go-cmp/cmp" 7 "github.com/quickfeed/quickfeed/internal/qtest" 8 "github.com/quickfeed/quickfeed/kit/score" 9 "github.com/quickfeed/quickfeed/qf" 10 "google.golang.org/protobuf/proto" 11 "google.golang.org/protobuf/testing/protocmp" 12 "google.golang.org/protobuf/types/known/timestamppb" 13 "gorm.io/gorm" 14 ) 15 16 func TestGormDBGetAssignment(t *testing.T) { 17 db, cleanup := qtest.TestDB(t) 18 defer cleanup() 19 20 if _, err := db.GetAssignmentsByCourse(10); err != gorm.ErrRecordNotFound { 21 t.Errorf("have error '%v' wanted '%v'", err, gorm.ErrRecordNotFound) 22 } 23 24 if _, err := db.GetAssignment(&qf.Assignment{ID: 10}); err != gorm.ErrRecordNotFound { 25 t.Errorf("have error '%v' wanted '%v'", err, gorm.ErrRecordNotFound) 26 } 27 } 28 29 func TestGormDBCreateAssignmentNoRecord(t *testing.T) { 30 db, cleanup := qtest.TestDB(t) 31 defer cleanup() 32 33 assignment := qf.Assignment{ 34 CourseID: 1, 35 Name: "Lab 1", 36 } 37 38 // Should fail as course 1 does not exist. 39 if err := db.CreateAssignment(&assignment); err != gorm.ErrRecordNotFound { 40 t.Errorf("have error '%v' wanted '%v'", err, gorm.ErrRecordNotFound) 41 } 42 } 43 44 func TestGormDBCreateAssignment(t *testing.T) { 45 db, cleanup := qtest.TestDB(t) 46 defer cleanup() 47 48 admin := qtest.CreateFakeUser(t, db) 49 qtest.CreateCourse(t, db, admin, &qf.Course{}) 50 51 gotAssignment := &qf.Assignment{ 52 CourseID: 1, 53 Order: 1, 54 } 55 56 if err := db.CreateAssignment(gotAssignment); err != nil { 57 t.Fatal(err) 58 } 59 60 assignments, err := db.GetAssignmentsByCourse(1) 61 if err != nil { 62 t.Fatal(err) 63 } 64 wantAssignment := assignments[0] 65 66 if len(assignments) != 1 { 67 t.Fatalf("have size %v wanted %v", len(assignments), 1) 68 } 69 70 if diff := cmp.Diff(wantAssignment, gotAssignment, protocmp.Transform()); diff != "" { 71 t.Errorf("CreateAssignment() mismatch (-wantAssignment, +gotAssignment):\n%s", diff) 72 } 73 74 if _, err = db.GetAssignment(&qf.Assignment{ID: 1}); err != nil { 75 t.Errorf("failed to get existing assignment by ID: %s", err) 76 } 77 } 78 79 func TestUpdateAssignment(t *testing.T) { 80 db, cleanup := qtest.TestDB(t) 81 defer cleanup() 82 83 course := &qf.Course{} 84 admin := qtest.CreateFakeUser(t, db) 85 qtest.CreateCourse(t, db, admin, course) 86 87 if err := db.CreateAssignment(&qf.Assignment{ 88 CourseID: course.ID, 89 Name: "lab1", 90 Deadline: qtest.Timestamp(t, "2022-11-11T23:59:00"), 91 AutoApprove: false, 92 Order: 1, 93 IsGroupLab: false, 94 }); err != nil { 95 t.Fatal(err) 96 } 97 98 if err := db.CreateAssignment(&qf.Assignment{ 99 CourseID: course.ID, 100 Name: "lab2", 101 Deadline: qtest.Timestamp(t, "2022-11-11T23:59:00"), 102 AutoApprove: false, 103 Order: 2, 104 IsGroupLab: true, 105 }); err != nil { 106 t.Fatal(err) 107 } 108 109 assignments, err := db.GetAssignmentsByCourse(course.ID) 110 if err != nil { 111 t.Error(err) 112 } 113 114 wantAssignments := make([]*qf.Assignment, len(assignments)) 115 for i, a := range assignments { 116 // test setting various zero-value entries to check that we can read back the same value 117 a.Deadline = ×tamppb.Timestamp{} 118 a.ScoreLimit = 0 119 a.Reviewers = 0 120 a.AutoApprove = !a.AutoApprove 121 a.IsGroupLab = !a.IsGroupLab 122 wantAssignments[i] = (proto.Clone(assignments[i])).(*qf.Assignment) 123 } 124 125 err = db.UpdateAssignments(assignments) 126 if err != nil { 127 t.Error(err) 128 } 129 gotAssignments, err := db.GetAssignmentsByCourse(course.ID) 130 if err != nil { 131 t.Error(err) 132 } 133 134 for i := range gotAssignments { 135 if diff := cmp.Diff(wantAssignments[i], gotAssignments[i], protocmp.Transform()); diff != "" { 136 t.Errorf("UpdateAssignments() mismatch (-want +got):\n%s", diff) 137 } 138 } 139 } 140 141 func TestGetCourseSubmissions(t *testing.T) { 142 db, cleanup := qtest.TestDB(t) 143 defer cleanup() 144 145 // create teacher, course, user (student) and assignment 146 user, course, assignment := setupCourseAssignment(t, db) 147 148 wantStruct := &qf.Submission{ 149 AssignmentID: assignment.ID, 150 UserID: user.ID, 151 Score: 42, 152 Reviews: []*qf.Review{}, 153 BuildInfo: &score.BuildInfo{ 154 BuildDate: qtest.Timestamp(t, "2021-01-21T18:00:00"), 155 SubmissionDate: qtest.Timestamp(t, "2021-01-21T18:00:00"), 156 BuildLog: "what do you say", 157 ExecTime: 50, 158 }, 159 Scores: []*score.Score{ 160 {TestName: "TestBigNum", MaxScore: 100, Score: 60, Weight: 10}, 161 {TestName: "TestDigNum", MaxScore: 100, Score: 70, Weight: 10}, 162 }, 163 } 164 if err := db.CreateSubmission(wantStruct); err != nil { 165 t.Fatal(err) 166 } 167 submissions, err := db.GetCourseSubmissions(course.ID, qf.SubmissionRequest_ALL) 168 if err != nil { 169 t.Fatal(err) 170 } 171 wantStruct.BuildInfo = nil 172 wantAssignment := (proto.Clone(assignment)).(*qf.Assignment) 173 wantAssignment.Submissions = append(wantAssignment.Submissions, wantStruct) 174 if diff := cmp.Diff(wantAssignment.Submissions, submissions, protocmp.Transform()); diff != "" { 175 t.Errorf("GetCourseSubmissions() mismatch (-want +got):\n%s", diff) 176 } 177 178 // Submission with Review 179 wantReview := &qf.Submission{ 180 AssignmentID: assignment.ID, 181 UserID: user.ID, 182 Score: 45, 183 Reviews: []*qf.Review{ 184 { 185 ReviewerID: 1, Feedback: "SGTM!", Score: 42, Ready: true, 186 GradingBenchmarks: []*qf.GradingBenchmark{ 187 { 188 Heading: "Ding Dong", Comment: "Communication", 189 Criteria: []*qf.GradingCriterion{ 190 {Points: 50, Description: "Loads of ding"}, 191 }, 192 }, 193 }, 194 }, 195 }, 196 } 197 if err := db.CreateSubmission(wantReview); err != nil { 198 t.Fatal(err) 199 } 200 submissions, err = db.GetCourseSubmissions(course.ID, qf.SubmissionRequest_ALL) 201 if err != nil { 202 t.Fatal(err) 203 } 204 wantAssignment = (proto.Clone(assignment)).(*qf.Assignment) 205 wantAssignment.Submissions = append(wantAssignment.Submissions, wantStruct, wantReview) 206 if diff := cmp.Diff(wantAssignment.Submissions, submissions, protocmp.Transform()); diff != "" { 207 t.Errorf("GetCourseSubmissions() mismatch (-want +got):\n%s", diff) 208 } 209 } 210 211 func TestUpdateBenchmarks(t *testing.T) { 212 db, cleanup := qtest.TestDB(t) 213 defer cleanup() 214 215 course := &qf.Course{} 216 admin := qtest.CreateFakeUser(t, db) 217 qtest.CreateCourse(t, db, admin, course) 218 219 assignment := &qf.Assignment{ 220 CourseID: course.ID, 221 Name: "Assignment 1", 222 Deadline: qtest.Timestamp(t, "2021-12-12T19:00:00"), 223 AutoApprove: false, 224 Order: 1, 225 IsGroupLab: false, 226 } 227 if err := db.CreateAssignment(assignment); err != nil { 228 t.Fatal(err) 229 } 230 231 benchmarks := []*qf.GradingBenchmark{ 232 { 233 ID: 1, 234 AssignmentID: assignment.ID, 235 Heading: "Test benchmark 1", 236 Criteria: []*qf.GradingCriterion{ 237 { 238 ID: 1, 239 Description: "Criterion 1", 240 BenchmarkID: 1, 241 Points: 5, 242 }, 243 { 244 ID: 2, 245 Description: "Criterion 2", 246 BenchmarkID: 1, 247 Points: 10, 248 }, 249 }, 250 }, 251 { 252 ID: 2, 253 AssignmentID: assignment.ID, 254 Heading: "Test benchmark 2", 255 Criteria: []*qf.GradingCriterion{ 256 { 257 ID: 3, 258 Description: "Criterion 3", 259 BenchmarkID: 2, 260 Points: 1, 261 }, 262 }, 263 }, 264 } 265 266 for _, bm := range benchmarks { 267 if err := db.CreateBenchmark(bm); err != nil { 268 t.Fatal(err) 269 } 270 } 271 272 gotAssignments, err := db.GetAssignmentsByCourse(course.ID) 273 if err != nil { 274 t.Error(err) 275 } 276 277 assignment.GradingBenchmarks = benchmarks 278 for i := range gotAssignments { 279 if diff := cmp.Diff(assignment, gotAssignments[i], protocmp.Transform()); diff != "" { 280 t.Errorf("UpdateAssignments() mismatch (-want +got):\n%s", diff) 281 } 282 } 283 284 for _, bm := range benchmarks { 285 bm.Heading = "Updated heading" 286 if err := db.UpdateBenchmark(bm); err != nil { 287 t.Fatal(err) 288 } 289 for _, c := range bm.Criteria { 290 c.Description = "Updated description" 291 if err := db.UpdateCriterion(c); err != nil { 292 t.Fatal(err) 293 } 294 } 295 } 296 assignment.GradingBenchmarks = benchmarks 297 gotAssignments, err = db.GetAssignmentsByCourse(course.ID) 298 if err != nil { 299 t.Error(err) 300 } 301 for i := range gotAssignments { 302 if diff := cmp.Diff(assignment, gotAssignments[i], protocmp.Transform()); diff != "" { 303 t.Errorf("UpdateAssignments() mismatch (-want +got):\n%s", diff) 304 } 305 } 306 }