Skip to content

Commit

Permalink
Implement swipe and mode management logic
Browse files Browse the repository at this point in the history
  • Loading branch information
yasuflatland-lf committed Aug 21, 2024
1 parent 60a37ab commit 752c426
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
repository "backend/graph/db"
"backend/graph/model"
"backend/graph/services"
"backend/pkg/config"
"backend/pkg/logger"
"golang.org/x/net/context"
)

type difficultStateStrategy struct {
swipeManagerUsecase SwipeManagerUsecase
amountOfSwipes int
}

type DifficultStateStrategy interface {
Expand All @@ -19,6 +21,7 @@ type DifficultStateStrategy interface {
func NewDifficultStateStrategy(swipeManagerUsecase SwipeManagerUsecase) DifficultStateStrategy {
return &difficultStateStrategy{
swipeManagerUsecase: swipeManagerUsecase,
amountOfSwipes: config.Cfg.FLBatchDefaultAmount,
}
}

Expand All @@ -28,6 +31,11 @@ func (d *difficultStateStrategy) Run(ctx context.Context, newSwipeRecord model.N
}

func (d *difficultStateStrategy) IsApplicable(ctx context.Context, newSwipeRecord model.NewSwipeRecord, latestSwipeRecords []*repository.SwipeRecord) bool {
// It needs to be certain amount of data for this mode.
if len(latestSwipeRecords) < d.amountOfSwipes {
return false
}

// If the last 5 records indicate other than "known", configure difficult
unknownCount := 0
for i := 0; i < 5 && i < len(latestSwipeRecords); i++ {
Expand Down
5 changes: 5 additions & 0 deletions backend/pkg/usecases/swipe_manager/easy_state_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ func (e *easyStateStrategy) Run(ctx context.Context, newSwipeRecord model.NewSwi
}

func (e *easyStateStrategy) IsApplicable(ctx context.Context, newSwipeRecord model.NewSwipeRecord, latestSwipeRecords []*repository.SwipeRecord) bool {
// It needs to be certain amount of data for this mode.
if len(latestSwipeRecords) < e.amaountOfUnKnownWords {
return false
}

// Check if the last 5 records indicate "easy"
knownCount := 0
for i := 0; i < 5 && i < len(latestSwipeRecords); i++ {
Expand Down
10 changes: 9 additions & 1 deletion backend/pkg/usecases/swipe_manager/good_state_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import (
repository "backend/graph/db"
"backend/graph/model"
"backend/graph/services"
"backend/pkg/config"
"backend/pkg/logger"
"golang.org/x/net/context"
)

// GoodStateStrategy implements the SwipeManagerUsecase interface
type goodStateStrategy struct {
swipeManagerUsecase SwipeManagerUsecase
amountOfSwipes int
}

type GoodStateStrategy interface {
Expand All @@ -21,6 +23,7 @@ type GoodStateStrategy interface {
func NewGoodStateStrategy(swipeManagerUsecase SwipeManagerUsecase) GoodStateStrategy {
return &goodStateStrategy{
swipeManagerUsecase: swipeManagerUsecase,
amountOfSwipes: config.Cfg.FLBatchDefaultAmount,
}
}

Expand All @@ -30,9 +33,14 @@ func (g *goodStateStrategy) Run(ctx context.Context, newSwipeRecord model.NewSwi
}

func (g *goodStateStrategy) IsApplicable(ctx context.Context, newSwipeRecord model.NewSwipeRecord, latestSwipeRecords []*repository.SwipeRecord) bool {
// It needs to be certain amount of data for this mode.
if len(latestSwipeRecords) < g.amountOfSwipes {
return false
}

// Check if 5 out of the last 10 records are "known"
knownCount := 0
for i := 0; i < 10 && i < len(latestSwipeRecords); i++ {
for i := 0; i < g.amountOfSwipes && i < len(latestSwipeRecords); i++ {
if latestSwipeRecords[i].Mode == services.KNOWN {
knownCount++
}
Expand Down
5 changes: 5 additions & 0 deletions backend/pkg/usecases/swipe_manager/inwhile_state_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ func (d *inWhileStateStrategy) Run(ctx context.Context, newSwipeRecord model.New
}

func (d *inWhileStateStrategy) IsApplicable(ctx context.Context, newSwipeRecord model.NewSwipeRecord, latestSwipeRecords []*repository.SwipeRecord) bool {
// It needs to be certain amount of data for this mode.
if len(latestSwipeRecords) < d.amountOfKnownWords {
return false
}

// Fetch latest swipe card
swipeRecords, err := d.swipeManagerUsecase.Srv().GetSwipeRecordsByUserAndOrder(
ctx, newSwipeRecord.UserID, repo.DESC, 1)
Expand Down
4 changes: 2 additions & 2 deletions backend/pkg/usecases/swipe_manager/swipe_manager_usecase.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ func (s *swipeManagerUsecase) getStrategy(
strategy SwipeStrategy
mode int
}{
{NewInWhileStateStrategy(s), INWHILE},
{NewDifficultStateStrategy(s), DIFFICULT},
{NewGoodStateStrategy(s), GOOD},
{NewEasyStateStrategy(s), EASY},
{NewInWhileStateStrategy(s), INWHILE},
{NewGoodStateStrategy(s), GOOD},
{NewDefaultStateStrategy(s), DEFAULT}, // Default strategy, placed last
}

Expand Down
159 changes: 159 additions & 0 deletions backend/pkg/usecases/swipe_manager/swipe_manager_usecase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
repo "backend/pkg/repository"
"backend/testutils"
"context"
"math/rand"
"strconv"
"testing"
"time"
Expand Down Expand Up @@ -171,6 +172,164 @@ func (suite *SwipeManagerTestSuite) TestUpdateRecords() {
assert.Equal(suite.T(), DIFFICULT, mode)
})

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)

// Additional assertions can be added here if necessary to validate the behavior of the strategy
})

suite.Run("Normal_GoodStateStrategy", 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
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

// 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 := suite.swipeRecordService.CreateSwipeRecord(ctx,
newSwipeRecord)
assert.NoError(suite.T(), err)

savedSwipeRecord = newSwipeRecord
swipeRecords = append(swipeRecords, services.ConvertToGormSwipeRecord(*createdSwipeRecord))
}

// Act
if 5 <= knownCount {
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)
}
})

suite.Run("Normal_EasyStateStrategy", 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.KNOWN // Set Mode to KNOWN for all records
}

newSwipeRecord := model.NewSwipeRecord{
CardID: card.ID,
CardGroupID: card.CardGroupID,
UserID: user.ID,
Mode: mode,
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)
})

suite.Run("Normal_InWhileStateStrategy", func() {
// Arrange
card, _, 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++ {
mode := services.KNOWN // Ensuring all records are KNOWN

newSwipeRecord := model.NewSwipeRecord{
CardID: card.ID,
CardGroupID: card.CardGroupID,
UserID: user.ID,
Mode: mode,
Created: twoMonthsAgo,
Updated: twoMonthsAgo,
}
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(), &inWhileStateStrategy{}, strategy)
assert.Equal(suite.T(), INWHILE, mode)
})

suite.Run("Normal_DetermineCardAmount", func() {
// Arrange
createdGroup, _, _ := testutils.CreateUserAndCardGroup(ctx, suite.userService, suite.cardGroupService, suite.roleService)
Expand Down

0 comments on commit 752c426

Please sign in to comment.