From 86e4cbfe464f234450385c627713231f6a00d18c Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Mon, 9 Sep 2024 21:37:11 +0900 Subject: [PATCH 1/8] fix: enable editing contest.TimeEnd to nil --- internal/handler/project_test.go | 24 +++++++++++++++---- .../infrastructure/repository/contest_impl.go | 21 +++++++++------- .../infrastructure/repository/contest_test.go | 15 ++++++++++++ 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/internal/handler/project_test.go b/internal/handler/project_test.go index 8655d621..256bff72 100644 --- a/internal/handler/project_test.go +++ b/internal/handler/project_test.go @@ -219,12 +219,12 @@ func TestProjectHandler_CreateProject(t *testing.T) { tests := []struct { name string - setup func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody schema.Project, path string) + setup func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody *schema.Project, path string) statusCode int }{ { name: "Success", - setup: func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody schema.Project, path string) { + setup: func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody *schema.Project, path string) { duration := random.Duration() reqBody = makeCreateProjectRequest( t, @@ -258,7 +258,7 @@ func TestProjectHandler_CreateProject(t *testing.T) { Link: args.Link.ValueOrZero(), Members: nil, } - expectedResBody = schema.Project{ + expectedResBody = &schema.Project{ Duration: schema.ConvertDuration(want.Duration), Id: want.ID, Name: want.Name, @@ -268,6 +268,22 @@ func TestProjectHandler_CreateProject(t *testing.T) { }, statusCode: http.StatusCreated, }, + { + name: "UnexpectedError", + setup: func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody *schema.Project, path string) { + duration := random.Duration() + reqBody = makeCreateProjectRequest( + t, + random.AlphaNumeric(), + schema.ConvertDuration(duration).Since, + schema.ConvertDuration(duration).Until, + random.AlphaNumeric(), + random.RandURLString(), + ) + return reqBody, nil, "/api/v1/projects" + }, + statusCode: http.StatusInternalServerError, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -281,7 +297,7 @@ func TestProjectHandler_CreateProject(t *testing.T) { // Assertion assert.Equal(t, tt.statusCode, statusCode) - assert.Equal(t, resBody, res) + assert.Equal(t, resBody, *res) }) } } diff --git a/internal/infrastructure/repository/contest_impl.go b/internal/infrastructure/repository/contest_impl.go index 11af9beb..5b3139e6 100644 --- a/internal/infrastructure/repository/contest_impl.go +++ b/internal/infrastructure/repository/contest_impl.go @@ -2,6 +2,7 @@ package repository import ( "context" + "time" "github.com/gofrs/uuid" "github.com/traPtitech/traPortfolio/internal/domain" @@ -94,6 +95,16 @@ func (r *ContestRepository) CreateContest(ctx context.Context, args *repository. } func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UUID, args *repository.UpdateContestArgs) error { + origin := &model.Contest{} + if err := r.h. + WithContext(ctx). + Where(&model.Contest{ID: contestID}). + First(origin). + Error; err != nil { + return err + } + untilEmpty := origin.Until.Equal(time.Time{}) + changes := map[string]interface{}{} if v, ok := args.Name.V(); ok { changes["name"] = v @@ -107,7 +118,7 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU if v, ok := args.Since.V(); ok { changes["since"] = v } - if v, ok := args.Until.V(); ok { + if v, ok := args.Until.V(); ok == untilEmpty || v != origin.Until { changes["until"] = v } @@ -117,14 +128,6 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU var c model.Contest err := r.h.WithContext(ctx).Transaction(func(tx *gorm.DB) error { - if err := tx. - WithContext(ctx). - Where(&model.Contest{ID: contestID}). - First(&model.Contest{}). - Error; err != nil { - return err - } - if err := tx. WithContext(ctx). Model(&model.Contest{ID: contestID}). diff --git a/internal/infrastructure/repository/contest_test.go b/internal/infrastructure/repository/contest_test.go index 571cb467..59f5e527 100644 --- a/internal/infrastructure/repository/contest_test.go +++ b/internal/infrastructure/repository/contest_test.go @@ -3,6 +3,7 @@ package repository import ( "context" "testing" + "time" "github.com/gofrs/uuid" "github.com/samber/lo" @@ -12,6 +13,7 @@ import ( "github.com/traPtitech/traPortfolio/internal/infrastructure/external/mock_external" "go.uber.org/mock/gomock" + "github.com/traPtitech/traPortfolio/internal/pkgs/optional" "github.com/traPtitech/traPortfolio/internal/pkgs/random" "github.com/traPtitech/traPortfolio/internal/usecases/repository" ) @@ -92,6 +94,7 @@ func Test_UpdateContest(t *testing.T) { t.Run("update no fields", func(t *testing.T) { args := &repository.UpdateContestArgs{} + args.Until = optional.New(contest.TimeEnd, contest.TimeEnd == time.Time{}) err := repo.UpdateContest(context.Background(), contest.ID, args) assert.NoError(t, err) @@ -100,6 +103,18 @@ func Test_UpdateContest(t *testing.T) { assert.Equal(t, contest, gotContest) }) + + t.Run("update until to nil", func(t *testing.T) { + argWithUntil := random.CreateContestArgs() + argWithUntil.Until = random.UpdateContestArgs().Since + contest, err := repo.CreateContest(context.Background(), argWithUntil) + assert.NoError(t, err) + + argWithoutUntil := random.UpdateContestArgs() + argWithoutUntil.Until = optional.Of[time.Time]{} + err = repo.UpdateContest(context.Background(), contest.ID, argWithoutUntil) + assert.NoError(t, err) + }) } func Test_DeleteContest(t *testing.T) { From 66542eccbb3b42d3588ac72b0609db220e1848a3 Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Mon, 9 Sep 2024 22:43:18 +0900 Subject: [PATCH 2/8] fix: enable editing project.Until to nil --- .../infrastructure/repository/project_impl.go | 23 +++++++++++++++---- .../infrastructure/repository/project_test.go | 8 +++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/internal/infrastructure/repository/project_impl.go b/internal/infrastructure/repository/project_impl.go index 086a6148..a0a88f38 100644 --- a/internal/infrastructure/repository/project_impl.go +++ b/internal/infrastructure/repository/project_impl.go @@ -125,6 +125,15 @@ func (r *ProjectRepository) CreateProject(ctx context.Context, args *repository. } func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UUID, args *repository.UpdateProjectArgs) error { + origin := &model.Project{} + if err := r.h. + WithContext(ctx). + Where(&model.Project{ID: projectID}). + First(origin). + Error; err != nil { + return err + } + changes := map[string]interface{}{} if v, ok := args.Name.V(); ok { changes["name"] = v @@ -141,10 +150,16 @@ func (r *ProjectRepository) UpdateProject(ctx context.Context, projectID uuid.UU changes["since_semester"] = ss } } - if uy, ok := args.UntilYear.V(); ok { - if us, ok := args.UntilSemester.V(); ok { - changes["until_year"] = uy - changes["until_semester"] = us + untilYear, validYear := args.UntilYear.V() + untilSemester, validSemester := args.UntilSemester.V() + if validYear == validSemester { + originUntil := domain.YearWithSemester{Year: origin.UntilYear, Semester: origin.UntilSemester} + argUntil := domain.YearWithSemester{Year: int(args.UntilYear.ValueOrZero()), Semester: int(args.UntilSemester.ValueOrZero())} + originValid := originUntil.IsValid() + // Untilが未定かどうかの状態が異なるか、Untilが異なる場合に更新 + if validYear != originValid || (validYear && argUntil != originUntil) { + changes["until_year"] = untilYear + changes["until_semester"] = untilSemester } } diff --git a/internal/infrastructure/repository/project_test.go b/internal/infrastructure/repository/project_test.go index 1b5cae16..aa9c7f2b 100644 --- a/internal/infrastructure/repository/project_test.go +++ b/internal/infrastructure/repository/project_test.go @@ -101,8 +101,12 @@ func TestProjectRepository_UpdateProject(t *testing.T) { project1.Duration.Since.Semester = int(ss) } } - if uy, ok := arg1.UntilYear.V(); ok { - if us, ok := arg1.UntilSemester.V(); ok { + uy, validYear := arg1.UntilYear.V() + us, validSemester := arg1.UntilSemester.V() + if validYear == validSemester { + originUntil, originValid := project1.Duration.Until.V() + argUntil := domain.YearWithSemester{Year: int(uy), Semester: int(us)} + if validYear != originValid || (validYear && argUntil != originUntil) { project1.Duration.Until = optional.From(domain.YearWithSemester{ Year: int(uy), Semester: int(us), From 3ed44f0aeff054835685af5dd7d29d31eaac42d5 Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Mon, 9 Sep 2024 22:46:39 +0900 Subject: [PATCH 3/8] remove: delete unknown test --- internal/handler/project_test.go | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/internal/handler/project_test.go b/internal/handler/project_test.go index 256bff72..8655d621 100644 --- a/internal/handler/project_test.go +++ b/internal/handler/project_test.go @@ -219,12 +219,12 @@ func TestProjectHandler_CreateProject(t *testing.T) { tests := []struct { name string - setup func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody *schema.Project, path string) + setup func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody schema.Project, path string) statusCode int }{ { name: "Success", - setup: func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody *schema.Project, path string) { + setup: func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody schema.Project, path string) { duration := random.Duration() reqBody = makeCreateProjectRequest( t, @@ -258,7 +258,7 @@ func TestProjectHandler_CreateProject(t *testing.T) { Link: args.Link.ValueOrZero(), Members: nil, } - expectedResBody = &schema.Project{ + expectedResBody = schema.Project{ Duration: schema.ConvertDuration(want.Duration), Id: want.ID, Name: want.Name, @@ -268,22 +268,6 @@ func TestProjectHandler_CreateProject(t *testing.T) { }, statusCode: http.StatusCreated, }, - { - name: "UnexpectedError", - setup: func(mr MockRepository) (reqBody *schema.CreateProjectRequest, expectedResBody *schema.Project, path string) { - duration := random.Duration() - reqBody = makeCreateProjectRequest( - t, - random.AlphaNumeric(), - schema.ConvertDuration(duration).Since, - schema.ConvertDuration(duration).Until, - random.AlphaNumeric(), - random.RandURLString(), - ) - return reqBody, nil, "/api/v1/projects" - }, - statusCode: http.StatusInternalServerError, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -297,7 +281,7 @@ func TestProjectHandler_CreateProject(t *testing.T) { // Assertion assert.Equal(t, tt.statusCode, statusCode) - assert.Equal(t, resBody, *res) + assert.Equal(t, resBody, res) }) } } From 16ab8f67b871a991c9b2bf6fcaa6881b57b5f426 Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Mon, 9 Sep 2024 22:55:40 +0900 Subject: [PATCH 4/8] fix: delete changes from test case "without changes" --- integration_tests/handler/contest_test.go | 6 +++++- integration_tests/handler/project_test.go | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/integration_tests/handler/contest_test.go b/integration_tests/handler/contest_test.go index fb3a134c..1f951280 100644 --- a/integration_tests/handler/contest_test.go +++ b/integration_tests/handler/contest_test.go @@ -291,7 +291,11 @@ func TestEditContest(t *testing.T) { "204 without change": { http.StatusNoContent, mockdata.ContestID3(), - schema.EditContestRequest{}, + schema.EditContestRequest{ + Duration: &schema.Duration{ + Until: &until, // Untilはnilにすると「未定」に変更される + }, + }, nil, }, "400 invalid contestID": { diff --git a/integration_tests/handler/project_test.go b/integration_tests/handler/project_test.go index e4870488..33b68279 100644 --- a/integration_tests/handler/project_test.go +++ b/integration_tests/handler/project_test.go @@ -242,7 +242,11 @@ func TestEditProject(t *testing.T) { "204 without changes": { http.StatusNoContent, mockdata.ProjectID2(), - schema.EditProjectRequest{}, + schema.EditProjectRequest{ + Duration: &schema.YearWithSemesterDuration{ + Until: duration.Until, // Untilはnilにすると「未定」に変更される + }, + }, nil, }, "400 invalid projectID": { From db1c2d45043688fcc21a49a7d15fff4e7d5054ea Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Thu, 12 Sep 2024 21:36:23 +0900 Subject: [PATCH 5/8] fix: null-since duration rejected by validator --- integration_tests/handler/contest_test.go | 2 ++ integration_tests/handler/project_test.go | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/integration_tests/handler/contest_test.go b/integration_tests/handler/contest_test.go index 1f951280..6554c3b7 100644 --- a/integration_tests/handler/contest_test.go +++ b/integration_tests/handler/contest_test.go @@ -293,6 +293,8 @@ func TestEditContest(t *testing.T) { mockdata.ContestID3(), schema.EditContestRequest{ Duration: &schema.Duration{ + // DurationのValidationで落とされるのでSinceも埋める + Since: mockdata.CloneMockContests()[2].Since, Until: &until, // Untilはnilにすると「未定」に変更される }, }, diff --git a/integration_tests/handler/project_test.go b/integration_tests/handler/project_test.go index cb90c76b..26f5f092 100644 --- a/integration_tests/handler/project_test.go +++ b/integration_tests/handler/project_test.go @@ -255,6 +255,11 @@ func TestEditProject(t *testing.T) { mockdata.ProjectID2(), schema.EditProjectRequest{ Duration: &schema.YearWithSemesterDuration{ + // DurationのValidationで落とされるのでSinceも埋める + Since: schema.YearWithSemester{ + Year: mockdata.CloneMockProjects()[1].SinceYear, + Semester: schema.Semester(mockdata.CloneMockProjects()[1].SinceSemester), + }, Until: duration.Until, // Untilはnilにすると「未定」に変更される }, }, From 822d70e5762bed922ae15d87f0607d6a6b45f29b Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Mon, 16 Sep 2024 21:37:53 +0900 Subject: [PATCH 6/8] update: add err contest test --- internal/infrastructure/repository/contest_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/infrastructure/repository/contest_test.go b/internal/infrastructure/repository/contest_test.go index 5ec94cf4..d1532de0 100644 --- a/internal/infrastructure/repository/contest_test.go +++ b/internal/infrastructure/repository/contest_test.go @@ -145,6 +145,11 @@ func Test_UpdateContest(t *testing.T) { err = repo.UpdateContest(context.Background(), contest.ID, argWithoutUntil) assert.NoError(t, err) }) + + t.Run("update failed: not contest id", func(t *testing.T) { + err = repo.UpdateContest(context.Background(), random.UUID(), &repository.UpdateContestArgs{}) + assert.Error(t, err) + }) } func Test_DeleteContest(t *testing.T) { From 3a12ce0f4e762ef5c19d50ff859be148368a1d20 Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Sat, 14 Dec 2024 21:49:36 +0900 Subject: [PATCH 7/8] fix: wrong duration in some test case --- integration_tests/handler/contest_test.go | 3 ++- integration_tests/handler/project_test.go | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/integration_tests/handler/contest_test.go b/integration_tests/handler/contest_test.go index 6554c3b7..b5278205 100644 --- a/integration_tests/handler/contest_test.go +++ b/integration_tests/handler/contest_test.go @@ -292,10 +292,11 @@ func TestEditContest(t *testing.T) { http.StatusNoContent, mockdata.ContestID3(), schema.EditContestRequest{ + // Untilはnilにすると「未定」に変更されるので変更なしとはいえDurationは必要 Duration: &schema.Duration{ // DurationのValidationで落とされるのでSinceも埋める Since: mockdata.CloneMockContests()[2].Since, - Until: &until, // Untilはnilにすると「未定」に変更される + Until: &mockdata.CloneMockContests()[2].Until, }, }, nil, diff --git a/integration_tests/handler/project_test.go b/integration_tests/handler/project_test.go index 26f5f092..640fa7e3 100644 --- a/integration_tests/handler/project_test.go +++ b/integration_tests/handler/project_test.go @@ -254,13 +254,17 @@ func TestEditProject(t *testing.T) { http.StatusNoContent, mockdata.ProjectID2(), schema.EditProjectRequest{ + // Untilはnilにすると「未定」に変更されるので変更なしとはいえDurationは必要 Duration: &schema.YearWithSemesterDuration{ // DurationのValidationで落とされるのでSinceも埋める Since: schema.YearWithSemester{ Year: mockdata.CloneMockProjects()[1].SinceYear, Semester: schema.Semester(mockdata.CloneMockProjects()[1].SinceSemester), }, - Until: duration.Until, // Untilはnilにすると「未定」に変更される + Until: &schema.YearWithSemester{ + Year: mockdata.CloneMockProjects()[1].UntilYear, + Semester: schema.Semester(mockdata.CloneMockProjects()[1].UntilSemester), + }, }, }, nil, From 0c1df6d9857c329d34413c0c6ed2c6719f25979a Mon Sep 17 00:00:00 2001 From: Tennessine699 Date: Sat, 14 Dec 2024 22:36:07 +0900 Subject: [PATCH 8/8] fix: check contest timeEnd nil --- internal/infrastructure/repository/contest_impl.go | 2 +- internal/infrastructure/repository/contest_test.go | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/internal/infrastructure/repository/contest_impl.go b/internal/infrastructure/repository/contest_impl.go index 82c90c34..ccff53b8 100644 --- a/internal/infrastructure/repository/contest_impl.go +++ b/internal/infrastructure/repository/contest_impl.go @@ -131,7 +131,7 @@ func (r *ContestRepository) UpdateContest(ctx context.Context, contestID uuid.UU if v, ok := args.Since.V(); ok { changes["since"] = v } - if v, ok := args.Until.V(); ok == untilEmpty || v != origin.Until { + if v, ok := args.Until.V(); ok == untilEmpty || !v.Equal(origin.Until) { changes["until"] = v } diff --git a/internal/infrastructure/repository/contest_test.go b/internal/infrastructure/repository/contest_test.go index d1532de0..628c43f1 100644 --- a/internal/infrastructure/repository/contest_test.go +++ b/internal/infrastructure/repository/contest_test.go @@ -124,7 +124,7 @@ func Test_UpdateContest(t *testing.T) { t.Run("update no fields", func(t *testing.T) { args := &repository.UpdateContestArgs{} - args.Until = optional.New(contest.TimeEnd, contest.TimeEnd == time.Time{}) + args.Until = optional.New(contest.TimeEnd, contest.TimeEnd.Equal(time.Time{})) err := repo.UpdateContest(context.Background(), contest.ID, args) assert.NoError(t, err) @@ -136,7 +136,8 @@ func Test_UpdateContest(t *testing.T) { t.Run("update until to nil", func(t *testing.T) { argWithUntil := random.CreateContestArgs() - argWithUntil.Until = random.UpdateContestArgs().Since + // CreateContestArgsのUntilは5割で"未定"なのでsinceの1時間後を代入する + argWithUntil.Until = optional.From(argWithUntil.Since.Add(time.Hour)) contest, err := repo.CreateContest(context.Background(), argWithUntil) assert.NoError(t, err) @@ -144,6 +145,10 @@ func Test_UpdateContest(t *testing.T) { argWithoutUntil.Until = optional.Of[time.Time]{} err = repo.UpdateContest(context.Background(), contest.ID, argWithoutUntil) assert.NoError(t, err) + + contest, err = repo.GetContest(context.Background(), contest.ID) + assert.NoError(t, err) + assert.Equal(t, contest.TimeEnd, time.Time{}) }) t.Run("update failed: not contest id", func(t *testing.T) {