package service import ( "context" "errors" "sync/atomic" "testing" "time" "github.com/Wei-Shaw/sub2api/internal/config" "github.com/stretchr/testify/require" ) type billingCacheWorkerStub struct { balanceUpdates int64 subscriptionUpdates int64 } func (b *billingCacheWorkerStub) GetUserBalance(ctx context.Context, userID int64) (float64, error) { return 0, errors.New("not implemented") } func (b *billingCacheWorkerStub) SetUserBalance(ctx context.Context, userID int64, balance float64) error { atomic.AddInt64(&b.balanceUpdates, 1) return nil } func (b *billingCacheWorkerStub) DeductUserBalance(ctx context.Context, userID int64, amount float64) error { atomic.AddInt64(&b.balanceUpdates, 1) return nil } func (b *billingCacheWorkerStub) InvalidateUserBalance(ctx context.Context, userID int64) error { return nil } func (b *billingCacheWorkerStub) GetSubscriptionCache(ctx context.Context, userID, groupID int64) (*SubscriptionCacheData, error) { return nil, errors.New("not implemented") } func (b *billingCacheWorkerStub) SetSubscriptionCache(ctx context.Context, userID, groupID int64, data *SubscriptionCacheData) error { atomic.AddInt64(&b.subscriptionUpdates, 1) return nil } func (b *billingCacheWorkerStub) UpdateSubscriptionUsage(ctx context.Context, userID, groupID int64, cost float64) error { atomic.AddInt64(&b.subscriptionUpdates, 1) return nil } func (b *billingCacheWorkerStub) InvalidateSubscriptionCache(ctx context.Context, userID, groupID int64) error { return nil } func TestBillingCacheServiceQueueHighLoad(t *testing.T) { cache := &billingCacheWorkerStub{} svc := NewBillingCacheService(cache, nil, nil, &config.Config{}) t.Cleanup(svc.Stop) start := time.Now() for i := 0; i < cacheWriteBufferSize*2; i++ { svc.QueueDeductBalance(1, 1) } require.Less(t, time.Since(start), 2*time.Second) svc.QueueUpdateSubscriptionUsage(1, 2, 1.5) require.Eventually(t, func() bool { return atomic.LoadInt64(&cache.balanceUpdates) > 0 }, 2*time.Second, 10*time.Millisecond) require.Eventually(t, func() bool { return atomic.LoadInt64(&cache.subscriptionUpdates) > 0 }, 2*time.Second, 10*time.Millisecond) }