package system import ( "context" "errors" "testing" "time" ) type securityUpdateRepo struct { current *SecurityConfig backfillErr error callOrder []string backfillAt time.Time persistedCopy *SecurityConfig } func (r *securityUpdateRepo) SecurityConfig(context.Context) (*SecurityConfig, error) { r.callOrder = append(r.callOrder, "get") copy := *r.current return ©, nil } func (r *securityUpdateRepo) SaveSecurityConfig(_ context.Context, value *SecurityConfig) error { r.callOrder = append(r.callOrder, "save") value.UpdatedAt = value.UpdatedAt.Add(time.Second) copy := *value r.persistedCopy = © return nil } func (r *securityUpdateRepo) BackfillPasswordUpdatedAt(_ context.Context, at time.Time) error { r.callOrder = append(r.callOrder, "backfill") r.backfillAt = at return r.backfillErr } func TestUpdateSecurityKeepsSavedConfigWhenPasswordBackfillFails(t *testing.T) { createdAt := time.Date(2026, time.August, 16, 12, 0, 0, 0, time.Local) backfillErr := errors.New("backfill failed") repo := &securityUpdateRepo{ current: &SecurityConfig{ID: 1, CreatedAt: createdAt, UpdatedAt: createdAt, PwdExpireEnable: false}, backfillErr: backfillErr, } uc := NewSecurityUsecase(repo, nil, nil, nil) next := &SecurityConfig{ID: 99, PwdExpireEnable: true, PwdExpireDays: 30} err := uc.UpdateSecurity(context.Background(), next) if !errors.Is(err, backfillErr) { t.Fatalf("UpdateSecurity() error = %v, want %v", err, backfillErr) } if got := repo.callOrder; len(got) != 3 || got[0] != "get" || got[1] != "save" || got[2] != "backfill" { t.Fatalf("call order = %v, want [get save backfill]", got) } if repo.persistedCopy == nil || repo.persistedCopy.ID != 1 || !repo.persistedCopy.PwdExpireEnable { t.Fatalf("persisted config = %+v", repo.persistedCopy) } if repo.backfillAt.IsZero() { t.Fatal("password timestamp backfill was not attempted") } cached, currentErr := uc.Current(context.Background()) if currentErr != nil { t.Fatalf("Current() error = %v", currentErr) } if !cached.PwdExpireEnable || cached.ID != 1 { t.Fatalf("effective config = %+v, want newly saved config", cached) } if got := repo.callOrder; len(got) != 3 { t.Fatalf("Current() unexpectedly reloaded repository: %v", got) } } func TestUpdateSecurityDoesNotBackfillWithoutDisabledToEnabledTransition(t *testing.T) { repo := &securityUpdateRepo{current: &SecurityConfig{ID: 1, PwdExpireEnable: true}} uc := NewSecurityUsecase(repo, nil, nil, nil) if err := uc.UpdateSecurity(context.Background(), &SecurityConfig{PwdExpireEnable: true}); err != nil { t.Fatalf("UpdateSecurity() error = %v", err) } if got := repo.callOrder; len(got) != 2 || got[0] != "get" || got[1] != "save" { t.Fatalf("call order = %v, want [get save]", got) } } func TestSecurityReadsPersistedValueWhileCurrentUsesCache(t *testing.T) { repo := &securityUpdateRepo{current: &SecurityConfig{ID: 1, LimitCount: 10}} uc := NewSecurityUsecase(repo, nil, nil, nil) cached, err := uc.Current(context.Background()) if err != nil { t.Fatal(err) } if cached.LimitCount != 10 { t.Fatalf("initial cached limit = %d", cached.LimitCount) } repo.current.LimitCount = 20 current, err := uc.Current(context.Background()) if err != nil { t.Fatal(err) } if current.LimitCount != 10 { t.Fatalf("Current() bypassed cache: %d", current.LimitCount) } fresh, err := uc.Security(context.Background()) if err != nil { t.Fatal(err) } if fresh.LimitCount != 20 { t.Fatalf("Security() returned stale value: %d", fresh.LimitCount) } }