Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
@@ -0,0 +1,205 @@
package vidser
import (
"errors"
"fmt"
"testing"
"time"
"91porn-server/common/stderr"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)
func TestDecideFreeWatchConsume(t *testing.T) {
tests := []struct {
name string
state freeWatchConsumeState
wantCan bool
wantConsume bool
wantRemaining uint64
}{
{
name: "eligible video consumes",
state: freeWatchConsumeState{watchCount: 3, totalCount: 3},
wantCan: true,
wantConsume: true,
wantRemaining: 3,
},
{
name: "already viewed is idempotent",
state: freeWatchConsumeState{viewedToday: true, watchCount: 2, totalCount: 3},
wantCan: true,
wantRemaining: 2,
},
{
name: "vip does not consume",
state: freeWatchConsumeState{isVIP: true, watchCount: 2, totalCount: 3},
wantCan: true,
wantRemaining: 2,
},
{
name: "publisher does not consume",
state: freeWatchConsumeState{isPublisher: true, watchCount: 2, totalCount: 3},
wantCan: true,
wantRemaining: 2,
},
{
name: "free area does not consume",
state: freeWatchConsumeState{freeArea: true, watchCount: 2, totalCount: 3},
wantCan: true,
wantRemaining: 2,
},
{
name: "coin video does not consume",
state: freeWatchConsumeState{paidVideo: true, watchCount: 2, totalCount: 3},
wantCan: true,
wantRemaining: 2,
},
{
name: "no remaining count denies new video",
state: freeWatchConsumeState{watchCount: 0, totalCount: 3},
wantCan: false,
},
{
name: "count is clamped to configured total",
state: freeWatchConsumeState{watchCount: 8, totalCount: 3},
wantCan: true,
wantConsume: true,
wantRemaining: 3,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := decideFreeWatchConsume(tt.state)
if got.isCan != tt.wantCan || got.shouldConsume != tt.wantConsume || got.watchCount != tt.wantRemaining {
t.Fatalf("decision = %+v, want isCan=%v shouldConsume=%v watchCount=%d",
got, tt.wantCan, tt.wantConsume, tt.wantRemaining)
}
})
}
}
func TestFreeWatchConsumeKeyScope(t *testing.T) {
oid := primitive.NewObjectID()
day := time.Date(2026, 7, 28, 0, 0, 0, 0, time.Local)
key := freeWatchConsumeKey(1001, oid, day)
if key != freeWatchConsumeKey(1001, oid, day) {
t.Fatal("same user, video and day must produce the same consume key")
}
if key == freeWatchConsumeKey(1002, oid, day) {
t.Fatal("consume key must be scoped by user")
}
if key == freeWatchConsumeKey(1001, primitive.NewObjectID(), day) {
t.Fatal("consume key must be scoped by video")
}
if key == freeWatchConsumeKey(1001, oid, day.AddDate(0, 0, 1)) {
t.Fatal("consume key must be scoped by day")
}
}
func TestIsRetryableFreeWatchTransactionError(t *testing.T) {
tests := []struct {
name string
err error
want bool
}{
{
name: "wrapped transient label",
err: fmt.Errorf("decrement watch count: %w", mongo.CommandError{
Code: 112,
Labels: []string{"TransientTransactionError"},
}),
want: true,
},
{
name: "write conflict code",
err: mongo.CommandError{Code: 112},
want: true,
},
{
name: "write exception transient label",
err: mongo.WriteException{
Labels: []string{"TransientTransactionError"},
},
want: true,
},
{
name: "no such transaction code",
err: fmt.Errorf("retry transaction: %w", mongo.CommandError{Code: 251}),
want: true,
},
{
name: "ordinary database error",
err: errors.New("database unavailable"),
},
{
name: "nil",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := isRetryableFreeWatchTransactionError(tt.err); got != tt.want {
t.Fatalf("isRetryableFreeWatchTransactionError() = %v, want %v", got, tt.want)
}
})
}
}
func TestRunFreeWatchTransactionWithRetry(t *testing.T) {
transient := fmt.Errorf("wrapped write conflict: %w", mongo.CommandError{
Code: 112,
Labels: []string{"TransientTransactionError"},
})
t.Run("eventually succeeds", func(t *testing.T) {
calls := 0
err := runFreeWatchTransactionWithRetry(func() error {
calls++
if calls < 3 {
return transient
}
return nil
})
if err != nil || calls != 3 {
t.Fatalf("err = %v, calls = %d, want nil and 3 calls", err, calls)
}
})
t.Run("stops at retry limit", func(t *testing.T) {
calls := 0
err := runFreeWatchTransactionWithRetry(func() error {
calls++
return transient
})
if err == nil || calls != freeWatchTransactionRetryLimit {
t.Fatalf("err = %v, calls = %d, want error and %d calls",
err, calls, freeWatchTransactionRetryLimit)
}
})
t.Run("duplicate is handled by caller without retry", func(t *testing.T) {
calls := 0
err := runFreeWatchTransactionWithRetry(func() error {
calls++
return stderr.InsertExistError
})
if !stderr.IsEqual(err, stderr.InsertExistError) || calls != 1 {
t.Fatalf("err = %v, calls = %d, want duplicate and 1 call", err, calls)
}
})
t.Run("ordinary error is not retried", func(t *testing.T) {
calls := 0
ordinary := errors.New("database unavailable")
err := runFreeWatchTransactionWithRetry(func() error {
calls++
return ordinary
})
if !errors.Is(err, ordinary) || calls != 1 {
t.Fatalf("err = %v, calls = %d, want ordinary error and 1 call", err, calls)
}
})
}