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 = &timestamppb.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  }