package verification import ( "context" "errors" "testing" "time" "git.sendico.io/tech/sxchnge/bff/pkg/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/v2/bson" ) func TestCreate_BlankContextRefAllowed(t *testing.T) { db := newTestVerificationDB(t) ctx := context.Background() accountRef := bson.NewObjectID() _, err := db.Create(ctx, contextReq(accountRef, "")) require.NoError(t, err) } func TestCreate_OldContextDoesNotBlockNewContext(t *testing.T) { db := newTestVerificationDB(t) ctx := context.Background() accountRef := bson.NewObjectID() oldRaw, err := db.Create(ctx, contextReq(accountRef, "ctx-old")) require.NoError(t, err) newRaw, err := db.Create(ctx, contextReq(accountRef, "ctx-new").WithCooldown(time.Minute)) require.NoError(t, err) assert.NotEqual(t, oldRaw, newRaw) oldTok, err := db.Consume(ctx, accountRef, model.PurposePasswordReset, "ctx-old", oldRaw) require.NoError(t, err) assert.Equal(t, "ctx-old", oldTok.ContextRef) newTok, err := db.Consume(ctx, accountRef, model.PurposePasswordReset, "ctx-new", newRaw) require.NoError(t, err) assert.Equal(t, "ctx-new", newTok.ContextRef) } func TestConsume_OTPForOneContextCannotConfirmAnotherContext(t *testing.T) { db := newTestVerificationDB(t) ctx := context.Background() accountRef := bson.NewObjectID() raw, err := db.Create(ctx, contextReq(accountRef, "ctx-a")) require.NoError(t, err) _, err = db.Consume(ctx, accountRef, model.PurposePasswordReset, "ctx-b", raw) require.Error(t, err) assert.True(t, errors.Is(err, ErrTokenNotFound)) tok, err := db.Consume(ctx, accountRef, model.PurposePasswordReset, "ctx-a", raw) require.NoError(t, err) assert.Equal(t, "ctx-a", tok.ContextRef) } func TestCreate_ContextIdempotencyReplayWorksOnlyWithinSameContext(t *testing.T) { db := newTestVerificationDB(t) ctx := context.Background() accountRef := bson.NewObjectID() firstReq := contextReq(accountRef, "ctx-a"). WithCooldown(time.Minute). WithIdempotencyKey("same-key") firstRaw, err := db.Create(ctx, firstReq) require.NoError(t, err) require.NotEmpty(t, firstRaw) replayReq := contextReq(accountRef, "ctx-a"). WithCooldown(time.Minute). WithIdempotencyKey("same-key") replayRaw, err := db.Create(ctx, replayReq) require.NoError(t, err) assert.Equal(t, firstRaw, replayRaw) conflictingReq := contextReq(accountRef, "ctx-b"). WithIdempotencyKey("same-key") _, err = db.Create(ctx, conflictingReq) require.Error(t, err) assert.True(t, errors.Is(err, ErrIdempotencyConflict)) } func TestCreate_ContextRefStoredForAnyPurpose(t *testing.T) { db := newTestVerificationDB(t) ctx := context.Background() accountRef := bson.NewObjectID() raw, err := db.Create(ctx, req(accountRef, model.PurposePasswordReset, "", time.Hour).WithContextRef("ctx")) require.NoError(t, err) tok, err := db.Consume(ctx, accountRef, model.PurposePasswordReset, "ctx", raw) require.NoError(t, err) assert.Equal(t, "ctx", tok.ContextRef) }