|
|
|
|
@ -29,6 +29,7 @@ type inMemoryRepo struct {
|
|
|
|
|
attempts []*domain.SessionAttempt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// newInMemoryRepo is a test helper.
|
|
|
|
|
func newInMemoryRepo() *inMemoryRepo {
|
|
|
|
|
return &inMemoryRepo{
|
|
|
|
|
sessions: map[string]*domain.GameSession{},
|
|
|
|
|
@ -36,8 +37,10 @@ func newInMemoryRepo() *inMemoryRepo {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EnsureSchema is a test helper.
|
|
|
|
|
func (r *inMemoryRepo) EnsureSchema(ctx context.Context) error { return nil }
|
|
|
|
|
|
|
|
|
|
// CreateSession is a test helper.
|
|
|
|
|
func (r *inMemoryRepo) CreateSession(ctx context.Context, session *domain.GameSession) (*domain.GameSession, error) {
|
|
|
|
|
session.ID = "sess-1"
|
|
|
|
|
now := time.Now().UTC()
|
|
|
|
|
@ -48,6 +51,7 @@ func (r *inMemoryRepo) CreateSession(ctx context.Context, session *domain.GameSe
|
|
|
|
|
return &cp, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetSessionByID is a test helper.
|
|
|
|
|
func (r *inMemoryRepo) GetSessionByID(ctx context.Context, id string) (*domain.GameSession, error) {
|
|
|
|
|
s, ok := r.sessions[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
@ -57,6 +61,7 @@ func (r *inMemoryRepo) GetSessionByID(ctx context.Context, id string) (*domain.G
|
|
|
|
|
return &cp, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetActiveSessionByPlayerID is a test helper.
|
|
|
|
|
func (r *inMemoryRepo) GetActiveSessionByPlayerID(ctx context.Context, playerID string) (*domain.GameSession, error) {
|
|
|
|
|
for _, s := range r.sessions {
|
|
|
|
|
if s.PlayerID == playerID && s.Status == domain.StatusActive {
|
|
|
|
|
@ -67,6 +72,7 @@ func (r *inMemoryRepo) GetActiveSessionByPlayerID(ctx context.Context, playerID
|
|
|
|
|
return nil, domain.ErrSessionNotFound
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdateSession is a test helper.
|
|
|
|
|
func (r *inMemoryRepo) UpdateSession(ctx context.Context, session *domain.GameSession) (*domain.GameSession, error) {
|
|
|
|
|
cp := *session
|
|
|
|
|
cp.UpdatedAt = time.Now().UTC()
|
|
|
|
|
@ -74,14 +80,17 @@ func (r *inMemoryRepo) UpdateSession(ctx context.Context, session *domain.GameSe
|
|
|
|
|
return &cp, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateAttempt is a test helper.
|
|
|
|
|
func (r *inMemoryRepo) CreateAttempt(ctx context.Context, attempt *domain.SessionAttempt) error {
|
|
|
|
|
cp := *attempt
|
|
|
|
|
r.attempts = append(r.attempts, &cp)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateEvent is a test helper.
|
|
|
|
|
func (r *inMemoryRepo) CreateEvent(ctx context.Context, event *domain.SessionEvent) error { return nil }
|
|
|
|
|
|
|
|
|
|
// ListQuestionIDsForSession is a test helper.
|
|
|
|
|
func (r *inMemoryRepo) ListQuestionIDsForSession(ctx context.Context, sessionID string) ([]string, error) {
|
|
|
|
|
seen := map[string]bool{}
|
|
|
|
|
ids := make([]string, 0)
|
|
|
|
|
@ -103,6 +112,7 @@ type fakeQuestionBank struct {
|
|
|
|
|
questions []appsession.SessionQuestion
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetRandomQuestion is a test helper.
|
|
|
|
|
func (f *fakeQuestionBank) GetRandomQuestion(
|
|
|
|
|
ctx context.Context,
|
|
|
|
|
exclusions []string,
|
|
|
|
|
@ -122,6 +132,7 @@ func (f *fakeQuestionBank) GetRandomQuestion(
|
|
|
|
|
return nil, domain.ErrSessionNotFound
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetQuestionByID is a test helper.
|
|
|
|
|
func (f *fakeQuestionBank) GetQuestionByID(ctx context.Context, id string) (*appsession.SessionQuestion, error) {
|
|
|
|
|
for _, q := range f.questions {
|
|
|
|
|
if q.ID == id {
|
|
|
|
|
@ -132,6 +143,7 @@ func (f *fakeQuestionBank) GetQuestionByID(ctx context.Context, id string) (*app
|
|
|
|
|
return nil, domain.ErrSessionNotFound
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ValidateAnswer is a test helper.
|
|
|
|
|
func (f *fakeQuestionBank) ValidateAnswer(
|
|
|
|
|
ctx context.Context,
|
|
|
|
|
questionID, answer string,
|
|
|
|
|
@ -145,6 +157,7 @@ func (f *fakeQuestionBank) ValidateAnswer(
|
|
|
|
|
// fakeUserClient returns a verified user profile for tests.
|
|
|
|
|
type fakeUserClient struct{}
|
|
|
|
|
|
|
|
|
|
// GetUserProfile is a test helper.
|
|
|
|
|
func (f *fakeUserClient) GetUserProfile(
|
|
|
|
|
ctx context.Context,
|
|
|
|
|
userID, bearerToken string,
|
|
|
|
|
@ -162,6 +175,7 @@ type fakeStateStore struct {
|
|
|
|
|
locks map[string]bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// newFakeStateStore is a test helper.
|
|
|
|
|
func newFakeStateStore() *fakeStateStore {
|
|
|
|
|
return &fakeStateStore{
|
|
|
|
|
active: map[string]string{},
|
|
|
|
|
@ -169,25 +183,38 @@ func newFakeStateStore() *fakeStateStore {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetActiveSession is a test helper.
|
|
|
|
|
func (s *fakeStateStore) GetActiveSession(ctx context.Context, playerID string) (string, bool) {
|
|
|
|
|
id, ok := s.active[playerID]
|
|
|
|
|
return id, ok
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetActiveSession is a test helper.
|
|
|
|
|
func (s *fakeStateStore) SetActiveSession(ctx context.Context, playerID, sessionID string, ttl time.Duration) error {
|
|
|
|
|
s.active[playerID] = sessionID
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ClearActiveSession is a test helper.
|
|
|
|
|
func (s *fakeStateStore) ClearActiveSession(ctx context.Context, playerID string) error {
|
|
|
|
|
delete(s.active, playerID)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetTimer is a test helper.
|
|
|
|
|
func (s *fakeStateStore) SetTimer(ctx context.Context, sessionID string, expiresAt time.Time, ttl time.Duration) error {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetTimer is a test helper.
|
|
|
|
|
func (s *fakeStateStore) GetTimer(ctx context.Context, sessionID string) (time.Time, bool) {
|
|
|
|
|
return time.Time{}, false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ClearTimer is a test helper.
|
|
|
|
|
func (s *fakeStateStore) ClearTimer(ctx context.Context, sessionID string) error { return nil }
|
|
|
|
|
|
|
|
|
|
// AcquireLock is a test helper.
|
|
|
|
|
func (s *fakeStateStore) AcquireLock(ctx context.Context, sessionID string, ttl time.Duration) bool {
|
|
|
|
|
if s.locks[sessionID] {
|
|
|
|
|
return false
|
|
|
|
|
@ -195,6 +222,8 @@ func (s *fakeStateStore) AcquireLock(ctx context.Context, sessionID string, ttl
|
|
|
|
|
s.locks[sessionID] = true
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ReleaseLock is a test helper.
|
|
|
|
|
func (s *fakeStateStore) ReleaseLock(ctx context.Context, sessionID string) {
|
|
|
|
|
delete(s.locks, sessionID)
|
|
|
|
|
}
|
|
|
|
|
@ -343,6 +372,7 @@ func TestMetricsEndpoint(t *testing.T) {
|
|
|
|
|
assertStatus(t, resp, http.StatusOK, "metrics failed")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// mustJSONRequest is a test helper.
|
|
|
|
|
func mustJSONRequest(
|
|
|
|
|
t *testing.T,
|
|
|
|
|
app *fiber.App,
|
|
|
|
|
@ -369,6 +399,7 @@ func mustJSONRequest(
|
|
|
|
|
return sharedhttpx.MustTest(t, app, req)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// assertStatus is a test helper.
|
|
|
|
|
func assertStatus(t *testing.T, resp *http.Response, want int, msg string) {
|
|
|
|
|
t.Helper()
|
|
|
|
|
if resp.StatusCode != want {
|
|
|
|
|
@ -376,6 +407,7 @@ func assertStatus(t *testing.T, resp *http.Response, want int, msg string) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// decodeDataMap is a test helper.
|
|
|
|
|
func decodeDataMap(t *testing.T, resp *http.Response) map[string]any {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
@ -389,6 +421,7 @@ func decodeDataMap(t *testing.T, resp *http.Response) map[string]any {
|
|
|
|
|
return payload.Data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// asMap is a test helper.
|
|
|
|
|
func asMap(t *testing.T, v any) map[string]any {
|
|
|
|
|
t.Helper()
|
|
|
|
|
m, ok := v.(map[string]any)
|
|
|
|
|
@ -398,6 +431,7 @@ func asMap(t *testing.T, v any) map[string]any {
|
|
|
|
|
return m
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// asString is a test helper.
|
|
|
|
|
func asString(t *testing.T, v any) string {
|
|
|
|
|
t.Helper()
|
|
|
|
|
s, ok := v.(string)
|
|
|
|
|
@ -407,6 +441,7 @@ func asString(t *testing.T, v any) string {
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// decodeAny is a test helper.
|
|
|
|
|
func decodeAny(t *testing.T, resp *http.Response) map[string]any {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|
|