From b6f9dbfdccb584b33cff36569a0a4e5e7ae919db Mon Sep 17 00:00:00 2001 From: Yasuyuki Takeo Date: Fri, 23 Aug 2024 06:21:05 +0900 Subject: [PATCH] Refactor swipe manager test parallel safe --- backend/Makefile | 9 +- .../swipe_manager_usecase_test.go | 677 +++++++++--------- backend/testutils/database.go | 3 +- 3 files changed, 346 insertions(+), 343 deletions(-) diff --git a/backend/Makefile b/backend/Makefile index 4208d37..dcc3eab 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -35,11 +35,18 @@ fmt: ## Format code go fmt ./...; \ printf "${GREEN} Code formatted.\n\n"; \ +.PHONY: test-ci +test: ## Run tests for CI + printf "${GREEN}Run all tests\n\n${WHITE}"; \ + go clean -cache -testcache -i -r; \ + go test -cover -race -json -v ./... ; \ + printf "${GREEN}Done\n"; \ + .PHONY: test test: ## Run tests printf "${GREEN}Run all tests\n\n${WHITE}"; \ go clean -cache -testcache -i -r; \ - go test -cover -race -json -v ./... ; \ + go test -race -v ./... ; \ printf "${GREEN}Done\n"; \ # Directories to exclude from coverage (use | to separate multiple directories) diff --git a/backend/pkg/usecases/swipe_manager/swipe_manager_usecase_test.go b/backend/pkg/usecases/swipe_manager/swipe_manager_usecase_test.go index 3bfbc8a..08fcd66 100644 --- a/backend/pkg/usecases/swipe_manager/swipe_manager_usecase_test.go +++ b/backend/pkg/usecases/swipe_manager/swipe_manager_usecase_test.go @@ -9,423 +9,420 @@ import ( repo "backend/pkg/repository" "backend/testutils" "context" + "github.com/labstack/echo/v4" + "log" "math/rand" "strconv" "testing" "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" "gorm.io/gorm" ) -type SwipeManagerTestSuite struct { - suite.Suite - db *gorm.DB - sv services.Services - cleanup func() - userService services.UserService - cardGroupService services.CardGroupService - cardService services.CardService - roleService services.RoleService - swipeRecordService services.SwipeRecordService -} +var db *gorm.DB +var e *echo.Echo +var sv services.Services +var userService services.UserService +var cardGroupService services.CardGroupService +var cardService services.CardService +var roleService services.RoleService +var swipeRecordService services.SwipeRecordService var migrationFilePath = "../../../db/migrations" -func (suite *SwipeManagerTestSuite) SetupSuite() { +func TestMain(m *testing.M) { ctx := context.Background() + pg, cleanup, err := testutils.SetupTestDB(ctx, "user", "password", "flamingo") if err != nil { - suite.T().Fatalf("Failed to setup test database: %+v", err) - } - suite.cleanup = func() { - cleanup(migrationFilePath) + log.Fatalf("Failed to setup test database: %+v", err) } + defer cleanup(migrationFilePath) if err := pg.RunGooseMigrationsUp(migrationFilePath); err != nil { - suite.T().Fatalf("failed to run migrations: %+v", err) + log.Fatalf("failed to run migrations: %+v", err) } - suite.db = pg.GetDB() - suite.sv = services.New(suite.db) - suite.userService = suite.sv.(services.UserService) - suite.cardGroupService = suite.sv.(services.CardGroupService) - suite.cardService = suite.sv.(services.CardService) - suite.roleService = suite.sv.(services.RoleService) - suite.swipeRecordService = suite.sv.(services.SwipeRecordService) -} + db = pg.GetDB() + sv = services.New(db) + + userService = sv.(services.UserService) + cardGroupService = sv.(services.CardGroupService) + cardService = sv.(services.CardService) + roleService = sv.(services.RoleService) + swipeRecordService = sv.(services.SwipeRecordService) -func (suite *SwipeManagerTestSuite) TearDownSuite() { - suite.cleanup() + m.Run() } -func (suite *SwipeManagerTestSuite) TestUpdateRecords() { +func TestUpdateRecords(t *testing.T) { + t.Helper() + t.Parallel() ctx := context.Background() usecase := &swipeManagerUsecase{ - services: suite.sv, + services: sv, } - suite.Run("Normal_UpdateIntervalDays", func() { - // Arrange - card, _, user, err := testutils.CreateUserCardAndCardGroup(ctx, - suite.userService, suite.cardGroupService, suite.roleService, suite.cardService) - newSwipeRecord := model.NewSwipeRecord{ - CardID: card.ID, - CardGroupID: card.CardGroupID, - UserID: user.ID, - Mode: services.KNOWN, - Created: time.Now().UTC(), - Updated: time.Now().UTC(), - } - - // Act - err = usecase.updateRecords(ctx, newSwipeRecord, GOOD) - - // Assert - assert.NoError(suite.T(), err) - updatedCard, _ := suite.cardService.GetCardByID(ctx, card.ID) - assert.Greater(suite.T(), updatedCard.IntervalDays, card.IntervalDays) - }) - - suite.Run("Normal_UpdateCardGroupUserState", func() { - // Arrange - card, cardGroup, user, err := testutils.CreateUserCardAndCardGroup(ctx, - suite.userService, suite.cardGroupService, suite.roleService, suite.cardService) - newSwipeRecord := model.NewSwipeRecord{ - CardID: card.ID, - CardGroupID: cardGroup.ID, - UserID: user.ID, - Mode: services.KNOWN, - Created: time.Now().UTC(), - Updated: time.Now().UTC(), - } - - // Act - err = usecase.updateRecords(ctx, newSwipeRecord, DIFFICULT) - - // Assert - assert.NoError(suite.T(), err) - cardGroupUser, _ := suite.cardGroupService.GetCardgroupUser(ctx, - newSwipeRecord.CardGroupID, newSwipeRecord.UserID) - assert.Equal(suite.T(), DIFFICULT, cardGroupUser.State) - }) - - suite.Run("Normal_CreateSwipeRecord", func() { - // Arrange - card, _, user, err := testutils.CreateUserCardAndCardGroup(ctx, - suite.userService, suite.cardGroupService, suite.roleService, suite.cardService) - newSwipeRecord := model.NewSwipeRecord{ - CardID: card.ID, - CardGroupID: card.CardGroupID, - UserID: user.ID, - Mode: services.KNOWN, - Created: time.Now().UTC(), - Updated: time.Now().UTC(), - } - - // Act - err = usecase.updateRecords(ctx, newSwipeRecord, EASY) - - // Assert - assert.NoError(suite.T(), err) - swipeRecords, _ := suite.sv.GetSwipeRecordsByUserAndOrder(ctx, newSwipeRecord.UserID, repo.DESC, config.Cfg.FLBatchDefaultAmount) - assert.NotEmpty(suite.T(), swipeRecords) - }) - - suite.Run("Normal_DifficultStateStrategy", func() { - // Arrange - card, _, user, err := testutils.CreateUserCardAndCardGroup(ctx, - suite.userService, suite.cardGroupService, suite.roleService, suite.cardService) - assert.NoError(suite.T(), err) - - // Generate 10 SwipeRecords - savedSwipeRecord := model.NewSwipeRecord{} - var swipeRecords []*repository.SwipeRecord - for i := 0; i < config.Cfg.FLBatchDefaultAmount; i++ { - mode := services.MAYBE - if i >= 5 { - mode = services.UNKNOWN // Set Mode to UNKNOWN for records 6 to 10 - } - + testutils.RunServersTest(t, db, func(t *testing.T) { + t.Run("Normal_UpdateIntervalDays", func(t *testing.T) { + // Arrange + card, _, user, err := testutils.CreateUserCardAndCardGroup(ctx, + userService, cardGroupService, roleService, cardService) newSwipeRecord := model.NewSwipeRecord{ CardID: card.ID, CardGroupID: card.CardGroupID, UserID: user.ID, - Mode: mode, + Mode: services.KNOWN, Created: time.Now().UTC(), Updated: time.Now().UTC(), } - createdSwipeRecord, err := suite.swipeRecordService.CreateSwipeRecord(ctx, - newSwipeRecord) - assert.NoError(suite.T(), err) - - savedSwipeRecord = newSwipeRecord - swipeRecords = append(swipeRecords, services.ConvertToGormSwipeRecord(*createdSwipeRecord)) - } - - // Act - strategy, mode, err := usecase.getStrategy(ctx, savedSwipeRecord, swipeRecords) - - // Assert - assert.NoError(suite.T(), err) - assert.IsType(suite.T(), &difficultStateStrategy{}, strategy) - assert.Equal(suite.T(), DIFFICULT, mode) - - // Make sure if cards are returned - cards, err := usecase.ExecuteStrategy(ctx, savedSwipeRecord, strategy) - assert.NotEmpty(suite.T(), cards) - }) - suite.Run("Normal_DefaultStateStrategy", func() { - // Arrange - card, _, user, err := testutils.CreateUserCardAndCardGroup(ctx, - suite.userService, suite.cardGroupService, suite.roleService, suite.cardService) - assert.NoError(suite.T(), err) - - // Generate SwipeRecords - savedSwipeRecord := model.NewSwipeRecord{ - CardID: card.ID, - CardGroupID: card.CardGroupID, - UserID: user.ID, - Mode: services.UNKNOWN, - Created: time.Now().UTC(), - Updated: time.Now().UTC(), - } - - var swipeRecords []*repository.SwipeRecord - - // Act - strategy, mode, err := usecase.getStrategy(ctx, savedSwipeRecord, swipeRecords) - - // Assert - assert.NoError(suite.T(), err) - assert.IsType(suite.T(), &defaultStateStrategy{}, strategy) - assert.Equal(suite.T(), DEFAULT, mode) - - // Make sure if cards are returned - cards, err := usecase.ExecuteStrategy(ctx, savedSwipeRecord, strategy) - assert.NotEmpty(suite.T(), cards) - assert.Equal(suite.T(), 1, len(cards)) - }) + // Act + err = usecase.updateRecords(ctx, newSwipeRecord, GOOD) - suite.Run("Normal_GoodStateStrategy", func() { - // Arrange - card, cardGroup, user, err := testutils.CreateUserCardAndCardGroup(ctx, - suite.userService, suite.cardGroupService, suite.roleService, suite.cardService) - assert.NoError(suite.T(), err) - - // Generate 10 SwipeRecords - savedSwipeRecord := model.NewSwipeRecord{} - var swipeRecords []*repository.SwipeRecord - knownCount := 0 - rng := rand.New(rand.NewSource(time.Now().UnixNano())) // Create a new random number generator - - for i := 0; i < config.Cfg.FLBatchDefaultAmount; i++ { - mode := services.UNKNOWN // Set default mode to UNKNOWN - - input := model.NewCard{ - Front: "Test Front" + strconv.Itoa(i), - Back: "Test Back" + strconv.Itoa(i), - ReviewDate: time.Now().UTC(), - CardgroupID: cardGroup.ID, + // Assert + assert.NoError(t, err) + updatedCard, _ := cardService.GetCardByID(ctx, card.ID) + assert.Greater(t, updatedCard.IntervalDays, card.IntervalDays) + }) + + t.Run("Normal_UpdateCardGroupUserState", func(t *testing.T) { + // Arrange + card, cardGroup, user, err := testutils.CreateUserCardAndCardGroup(ctx, + userService, cardGroupService, roleService, cardService) + newSwipeRecord := model.NewSwipeRecord{ + CardID: card.ID, + CardGroupID: cardGroup.ID, + UserID: user.ID, + Mode: services.KNOWN, + Created: time.Now().UTC(), + Updated: time.Now().UTC(), } - _, err := suite.cardService.CreateCard(ctx, input) - - // Randomly set 5 records to KNOWN - if knownCount <= 5 && rng.Intn(config.Cfg. - FLBatchDefaultAmount-knownCount) <= (5-knownCount) { - mode = services.KNOWN - knownCount++ - } + // Act + err = usecase.updateRecords(ctx, newSwipeRecord, DIFFICULT) + // Assert + assert.NoError(t, err) + cardGroupUser, _ := cardGroupService.GetCardgroupUser(ctx, + newSwipeRecord.CardGroupID, newSwipeRecord.UserID) + assert.Equal(t, DIFFICULT, cardGroupUser.State) + }) + + t.Run("Normal_CreateSwipeRecord", func(t *testing.T) { + // Arrange + card, _, user, err := testutils.CreateUserCardAndCardGroup(ctx, + userService, cardGroupService, roleService, cardService) newSwipeRecord := model.NewSwipeRecord{ CardID: card.ID, CardGroupID: card.CardGroupID, UserID: user.ID, - Mode: mode, + Mode: services.KNOWN, Created: time.Now().UTC(), Updated: time.Now().UTC(), } - createdSwipeRecord, err := suite.swipeRecordService.CreateSwipeRecord(ctx, - newSwipeRecord) - assert.NoError(suite.T(), err) - savedSwipeRecord = newSwipeRecord - swipeRecords = append(swipeRecords, services.ConvertToGormSwipeRecord(*createdSwipeRecord)) - } + // Act + err = usecase.updateRecords(ctx, newSwipeRecord, EASY) + + // Assert + assert.NoError(t, err) + swipeRecords, _ := sv.GetSwipeRecordsByUserAndOrder(ctx, newSwipeRecord.UserID, repo.DESC, config.Cfg.FLBatchDefaultAmount) + assert.NotEmpty(t, swipeRecords) + }) + + t.Run("Normal_DifficultStateStrategy", func(t *testing.T) { + // Arrange + card, _, user, err := testutils.CreateUserCardAndCardGroup(ctx, + userService, cardGroupService, roleService, cardService) + assert.NoError(t, err) + + // Generate 10 SwipeRecords + savedSwipeRecord := model.NewSwipeRecord{} + var swipeRecords []*repository.SwipeRecord + for i := 0; i < config.Cfg.FLBatchDefaultAmount; i++ { + mode := services.MAYBE + if i >= 5 { + mode = services.UNKNOWN // Set Mode to UNKNOWN for records 6 to 10 + } + + newSwipeRecord := model.NewSwipeRecord{ + CardID: card.ID, + CardGroupID: card.CardGroupID, + UserID: user.ID, + Mode: mode, + Created: time.Now().UTC(), + Updated: time.Now().UTC(), + } + createdSwipeRecord, err := swipeRecordService.CreateSwipeRecord(ctx, + newSwipeRecord) + assert.NoError(t, err) + + savedSwipeRecord = newSwipeRecord + swipeRecords = append(swipeRecords, services.ConvertToGormSwipeRecord(*createdSwipeRecord)) + } - // Act - if 5 <= knownCount { + // Act strategy, mode, err := usecase.getStrategy(ctx, savedSwipeRecord, swipeRecords) // Assert - assert.NoError(suite.T(), err) - assert.IsType(suite.T(), &goodStateStrategy{}, strategy) - assert.Equal(suite.T(), GOOD, mode) + assert.NoError(t, err) + assert.IsType(t, &difficultStateStrategy{}, strategy) + assert.Equal(t, DIFFICULT, mode) // Make sure if cards are returned cards, err := usecase.ExecuteStrategy(ctx, savedSwipeRecord, strategy) - assert.NotEmpty(suite.T(), cards) - assert.Equal(suite.T(), config.Cfg.FLBatchDefaultAmount, len(cards)) - } else { - logger.Logger.Info("Skip test due to the random data does not hit" + - " the count.") - } - }) + assert.NotEmpty(t, cards) + }) - suite.Run("Normal_EasyStateStrategy", func() { - // Arrange - card, cardGroup, user, err := testutils.CreateUserCardAndCardGroup(ctx, - suite.userService, suite.cardGroupService, suite.roleService, suite.cardService) - assert.NoError(suite.T(), err) - - // Generate 10 SwipeRecords - savedSwipeRecord := model.NewSwipeRecord{} - var swipeRecords []*repository.SwipeRecord - for i := 0; i < config.Cfg.FLBatchDefaultAmount; i++ { - mode := services.MAYBE - if i < 5 { - mode = services.KNOWN // Set Mode to KNOWN for all records - } + t.Run("Normal_DefaultStateStrategy", func(t *testing.T) { + // Arrange + card, _, user, err := testutils.CreateUserCardAndCardGroup(ctx, + userService, cardGroupService, roleService, cardService) + assert.NoError(t, err) - input := model.NewCard{ - Front: "Front " + strconv.Itoa(i), - Back: "Back " + strconv.Itoa(i), - ReviewDate: time.Now().UTC(), - CardgroupID: cardGroup.ID, - } - createdCard, err := suite.cardService.CreateCard(ctx, input) - assert.NoError(suite.T(), err) - - newSwipeRecord := model.NewSwipeRecord{ - CardID: createdCard.ID, + // Generate SwipeRecords + savedSwipeRecord := model.NewSwipeRecord{ + CardID: card.ID, CardGroupID: card.CardGroupID, UserID: user.ID, - Mode: mode, + Mode: services.UNKNOWN, Created: time.Now().UTC(), Updated: time.Now().UTC(), } - createdSwipeRecord, err := suite.swipeRecordService.CreateSwipeRecord(ctx, - newSwipeRecord) - assert.NoError(suite.T(), err) - - savedSwipeRecord = newSwipeRecord - swipeRecords = append(swipeRecords, services.ConvertToGormSwipeRecord(*createdSwipeRecord)) - } - - // Act - strategy, mode, err := usecase.getStrategy(ctx, savedSwipeRecord, swipeRecords) - - // Assert - assert.NoError(suite.T(), err) - assert.IsType(suite.T(), &easyStateStrategy{}, strategy) - assert.Equal(suite.T(), EASY, mode) - - // Make sure if cards are returned - cards, err := usecase.ExecuteStrategy(ctx, savedSwipeRecord, strategy) - assert.NotEmpty(suite.T(), cards) - assert.Equal(suite.T(), config.Cfg.FLBatchDefaultAmount, len(cards)) - }) - suite.Run("Normal_InWhileStateStrategy", func() { - // Arrange - _, cardGroup, user, err := testutils.CreateUserCardAndCardGroup(ctx, - suite.userService, suite.cardGroupService, suite.roleService, suite.cardService) - assert.NoError(suite.T(), err) - - // Set date to two months ago - twoMonthsAgo := time.Now().AddDate(0, -2, 0).UTC() - - // Generate sufficient SwipeRecords for the strategy to be applicable - savedSwipeRecord := model.NewSwipeRecord{} - var swipeRecords []*repository.SwipeRecord - for i := 0; i < config.Cfg.FLBatchDefaultAmount; i++ { - input := model.NewCard{ - Front: "Front " + strconv.Itoa(i), - Back: "Back " + strconv.Itoa(i), - ReviewDate: time.Now().UTC(), - CardgroupID: cardGroup.ID, - } - createdCard, err := suite.cardService.CreateCard(ctx, input) - assert.NoError(suite.T(), err) + var swipeRecords []*repository.SwipeRecord - mode := services.KNOWN // Ensuring all records are KNOWN + // Act + strategy, mode, err := usecase.getStrategy(ctx, savedSwipeRecord, swipeRecords) - newSwipeRecord := model.NewSwipeRecord{ - CardID: createdCard.ID, - CardGroupID: cardGroup.ID, - UserID: user.ID, - Mode: mode, - Created: twoMonthsAgo, - Updated: twoMonthsAgo, - } - createdSwipeRecord, err := suite.swipeRecordService.CreateSwipeRecord(ctx, - newSwipeRecord) - assert.NoError(suite.T(), err) + // Assert + assert.NoError(t, err) + assert.IsType(t, &defaultStateStrategy{}, strategy) + assert.Equal(t, DEFAULT, mode) - savedSwipeRecord = newSwipeRecord - swipeRecords = append(swipeRecords, services.ConvertToGormSwipeRecord(*createdSwipeRecord)) - } + // Make sure if cards are returned + cards, err := usecase.ExecuteStrategy(ctx, savedSwipeRecord, strategy) + assert.NotEmpty(t, cards) + assert.Equal(t, 1, len(cards)) + }) + + t.Run("Normal_GoodStateStrategy", func(t *testing.T) { + // Arrange + card, cardGroup, user, err := testutils.CreateUserCardAndCardGroup(ctx, + userService, cardGroupService, roleService, cardService) + assert.NoError(t, err) + + // Generate 10 SwipeRecords + savedSwipeRecord := model.NewSwipeRecord{} + var swipeRecords []*repository.SwipeRecord + knownCount := 0 + rng := rand.New(rand.NewSource(time.Now().UnixNano())) // Create a new random number generator + + for i := 0; i < config.Cfg.FLBatchDefaultAmount; i++ { + mode := services.UNKNOWN // Set default mode to UNKNOWN + + input := model.NewCard{ + Front: "Test Front" + strconv.Itoa(i), + Back: "Test Back" + strconv.Itoa(i), + ReviewDate: time.Now().UTC(), + CardgroupID: cardGroup.ID, + } + + _, err := cardService.CreateCard(ctx, input) + + // Randomly set 5 records to KNOWN + if knownCount <= 5 && rng.Intn(config.Cfg. + FLBatchDefaultAmount-knownCount) <= (5-knownCount) { + mode = services.KNOWN + knownCount++ + } + + newSwipeRecord := model.NewSwipeRecord{ + CardID: card.ID, + CardGroupID: card.CardGroupID, + UserID: user.ID, + Mode: mode, + Created: time.Now().UTC(), + Updated: time.Now().UTC(), + } + createdSwipeRecord, err := swipeRecordService.CreateSwipeRecord(ctx, + newSwipeRecord) + assert.NoError(t, err) + + savedSwipeRecord = newSwipeRecord + swipeRecords = append(swipeRecords, services.ConvertToGormSwipeRecord(*createdSwipeRecord)) + } - // Act - strategy, mode, err := usecase.getStrategy(ctx, savedSwipeRecord, swipeRecords) + // Act + if 5 <= knownCount { + strategy, mode, err := usecase.getStrategy(ctx, savedSwipeRecord, swipeRecords) + + // Assert + assert.NoError(t, err) + assert.IsType(t, &goodStateStrategy{}, strategy) + assert.Equal(t, GOOD, mode) + + // Make sure if cards are returned + cards, err := usecase.ExecuteStrategy(ctx, savedSwipeRecord, strategy) + assert.NotEmpty(t, cards) + assert.Equal(t, config.Cfg.FLBatchDefaultAmount, len(cards)) + } else { + logger.Logger.Info("Skip test due to the random data does not hit" + + " the count.") + } + }) + + t.Run("Normal_EasyStateStrategy", func(t *testing.T) { + // Arrange + card, cardGroup, user, err := testutils.CreateUserCardAndCardGroup(ctx, + userService, cardGroupService, roleService, cardService) + assert.NoError(t, err) + + // Generate 10 SwipeRecords + savedSwipeRecord := model.NewSwipeRecord{} + var swipeRecords []*repository.SwipeRecord + for i := 0; i < config.Cfg.FLBatchDefaultAmount; i++ { + mode := services.MAYBE + if i < 5 { + mode = services.KNOWN // Set Mode to KNOWN for all records + } + + input := model.NewCard{ + Front: "Front " + strconv.Itoa(i), + Back: "Back " + strconv.Itoa(i), + ReviewDate: time.Now().UTC(), + CardgroupID: cardGroup.ID, + } + createdCard, err := cardService.CreateCard(ctx, input) + assert.NoError(t, err) + + newSwipeRecord := model.NewSwipeRecord{ + CardID: createdCard.ID, + CardGroupID: card.CardGroupID, + UserID: user.ID, + Mode: mode, + Created: time.Now().UTC(), + Updated: time.Now().UTC(), + } + createdSwipeRecord, err := swipeRecordService.CreateSwipeRecord(ctx, + newSwipeRecord) + assert.NoError(t, err) + + savedSwipeRecord = newSwipeRecord + swipeRecords = append(swipeRecords, services.ConvertToGormSwipeRecord(*createdSwipeRecord)) + } - // Assert - assert.NoError(suite.T(), err) - assert.IsType(suite.T(), &inWhileStateStrategy{}, strategy) - assert.Equal(suite.T(), INWHILE, mode) + // Act + strategy, mode, err := usecase.getStrategy(ctx, savedSwipeRecord, swipeRecords) - // Make sure if cards are returned - cards, err := usecase.ExecuteStrategy(ctx, savedSwipeRecord, strategy) - assert.Equal(suite.T(), config.Cfg.FLBatchDefaultAmount, len(cards)) - }) + // Assert + assert.NoError(t, err) + assert.IsType(t, &easyStateStrategy{}, strategy) + assert.Equal(t, EASY, mode) - suite.Run("Normal_DetermineCardAmount", func() { - // Arrange - createdGroup, _, _ := testutils.CreateUserAndCardGroup(ctx, suite.userService, suite.cardGroupService, suite.roleService) - - // Create 15 dummy cards with the same cardgroup_id and store them in a slice - var cards []*model.Card - for i := 0; i < 15; i++ { - input := model.NewCard{ - Front: "Front " + strconv.Itoa(i), - Back: "Back " + strconv.Itoa(i), - ReviewDate: time.Now().UTC(), - CardgroupID: createdGroup.ID, // Use the same CardGroup ID for all cards + // Make sure if cards are returned + cards, err := usecase.ExecuteStrategy(ctx, savedSwipeRecord, strategy) + assert.NotEmpty(t, cards) + assert.Equal(t, config.Cfg.FLBatchDefaultAmount, len(cards)) + }) + + t.Run("Normal_InWhileStateStrategy", func(t *testing.T) { + // Arrange + _, cardGroup, user, err := testutils.CreateUserCardAndCardGroup(ctx, + userService, cardGroupService, roleService, cardService) + assert.NoError(t, err) + + // Set date to two months ago + twoMonthsAgo := time.Now().AddDate(0, -2, 0).UTC() + + // Generate sufficient SwipeRecords for the strategy to be applicable + savedSwipeRecord := model.NewSwipeRecord{} + var swipeRecords []*repository.SwipeRecord + for i := 0; i < config.Cfg.FLBatchDefaultAmount; i++ { + input := model.NewCard{ + Front: "Front " + strconv.Itoa(i), + Back: "Back " + strconv.Itoa(i), + ReviewDate: time.Now().UTC(), + CardgroupID: cardGroup.ID, + } + createdCard, err := cardService.CreateCard(ctx, input) + assert.NoError(t, err) + + mode := services.KNOWN // Ensuring all records are KNOWN + + newSwipeRecord := model.NewSwipeRecord{ + CardID: createdCard.ID, + CardGroupID: cardGroup.ID, + UserID: user.ID, + Mode: mode, + Created: twoMonthsAgo, + Updated: twoMonthsAgo, + } + createdSwipeRecord, err := swipeRecordService.CreateSwipeRecord(ctx, + newSwipeRecord) + assert.NoError(t, err) + + savedSwipeRecord = newSwipeRecord + swipeRecords = append(swipeRecords, services.ConvertToGormSwipeRecord(*createdSwipeRecord)) } - card, err := suite.cardService.CreateCard(ctx, input) - assert.NoError(suite.T(), err) - // Convert the created card to model.Card and append to the slice - cards = append(cards, card) - } + // Act + strategy, mode, err := usecase.getStrategy(ctx, savedSwipeRecord, swipeRecords) + + // Assert + assert.NoError(t, err) + assert.IsType(t, &inWhileStateStrategy{}, strategy) + assert.Equal(t, INWHILE, mode) + + // Make sure if cards are returned + cards, err := usecase.ExecuteStrategy(ctx, savedSwipeRecord, strategy) + assert.Equal(t, config.Cfg.FLBatchDefaultAmount, len(cards)) + }) + + t.Run("Normal_DetermineCardAmount", func(t *testing.T) { + // Arrange + createdGroup, _, _ := testutils.CreateUserAndCardGroup(ctx, userService, cardGroupService, roleService) + + // Create 15 dummy cards with the same cardgroup_id and store them in a slice + var cards []*model.Card + for i := 0; i < 15; i++ { + input := model.NewCard{ + Front: "Front " + strconv.Itoa(i), + Back: "Back " + strconv.Itoa(i), + ReviewDate: time.Now().UTC(), + CardgroupID: createdGroup.ID, // Use the same CardGroup ID for all cards + } + card, err := cardService.CreateCard(ctx, input) + assert.NoError(t, err) + + // Convert the created card to model.Card and append to the slice + cards = append(cards, card) + } - amountOfKnownWords := 5 + amountOfKnownWords := 5 - // Act - cardAmount, err := usecase.DetermineCardAmount(cards, amountOfKnownWords) + // Act + cardAmount, err := usecase.DetermineCardAmount(cards, amountOfKnownWords) - // Assert - assert.NoError(suite.T(), err) - assert.Equal(suite.T(), 5, cardAmount) - }) + // Assert + assert.NoError(t, err) + assert.Equal(t, 5, cardAmount) + }) - suite.Run("Error_NoCardsAvailable", func() { - // Arrange - var cards []*model.Card - amountOfKnownWords := 5 + t.Run("Error_NoCardsAvailable", func(t *testing.T) { + // Arrange + var cards []*model.Card + amountOfKnownWords := 5 - // Act - cardAmount, err := usecase.DetermineCardAmount(cards, amountOfKnownWords) + // Act + cardAmount, err := usecase.DetermineCardAmount(cards, amountOfKnownWords) - // Assert - assert.NoError(suite.T(), err) - assert.Equal(suite.T(), 0, cardAmount) + // Assert + assert.NoError(t, err) + assert.Equal(t, 0, cardAmount) + }) }) -} -func TestSwipeManagerTestSuite(t *testing.T) { - suite.Run(t, new(SwipeManagerTestSuite)) } diff --git a/backend/testutils/database.go b/backend/testutils/database.go index 7b2ffb0..7150470 100644 --- a/backend/testutils/database.go +++ b/backend/testutils/database.go @@ -19,8 +19,7 @@ import ( // SetupTestDB sets up a Postgres test container and returns the connection and a cleanup function. func SetupTestDB(ctx context.Context, user, password, dbName string) (repository.Repository, func(migrationFilePath string), error) { req := testcontainers.ContainerRequest{ - Image: "postgres:16", - ExposedPorts: []string{"5432/tcp"}, + Image: "postgres:16", Env: map[string]string{ "POSTGRES_USER": user, "POSTGRES_PASSWORD": password,