package shortrecommendser import ( "context" "errors" "testing" "time" recommendqueue "91porn-server/common/shortrecommend" "91porn-server/models/v/vidmod" "go.mongodb.org/mongo-driver/bson/primitive" ) func TestFetchReservesOncePreservesOrderAndCommitsConsumedPrefix(t *testing.T) { validA := primitive.NewObjectID() downShelf := primitive.NewObjectID() excluded := primitive.NewObjectID() validB := primitive.NewObjectID() ids := []string{validA.Hex(), downShelf.Hex(), excluded.Hex(), validB.Hex()} deps := testFetchDependencies( testReservation(ids, len(ids)), func(_ context.Context, batch []primitive.ObjectID) ([]*vidmod.VideoModel, error) { out := make([]*vidmod.VideoModel, 0, len(batch)) for _, id := range batch { switch id { case validA, validB: out = append(out, &vidmod.VideoModel{ID: id}) case excluded: out = append(out, &vidmod.VideoModel{ID: id, MID: "blocked"}) } } return out, nil }, ) deps.excludedModuleIDs = func(time.Time, bool) ([]string, error) { return []string{"blocked"}, nil } reserveCalls, committed, aborted := 0, 0, 0 originalReserve := deps.reserve deps.reserve = func( ctx context.Context, uid uint64, size int, requestID string, ) (recommendqueue.Reservation, error) { reserveCalls++ if size != 10 { t.Fatalf("reserve size = %d, want scan budget 10", size) } return originalReserve(ctx, uid, size, requestID) } deps.commit = func( _ context.Context, _ uint64, _ recommendqueue.Reservation, consumed int, ) error { committed = consumed return nil } deps.abort = func( context.Context, uint64, recommendqueue.Reservation, ) error { aborted++ return nil } result, err := fetch(context.Background(), 7, 2, "request-1", fetchOptions{ maxBatches: 5, scanMultiplier: 5, }, deps) if err != nil { t.Fatalf("fetch() error = %v", err) } if len(result.Videos) != 2 || result.Videos[0].ID != validA || result.Videos[1].ID != validB { t.Fatalf("videos = %#v, want queue ordered valid videos", result.Videos) } if reserveCalls != 1 || committed != 4 || aborted != 0 { t.Fatalf("reserve=%d committed=%d aborted=%d", reserveCalls, committed, aborted) } if result.Scanned != 4 || result.Filtered != 2 || result.Batches != 3 { t.Fatalf("metrics = %+v", result) } if result.QueueVersion != "20260731-r1" || result.QueueLength != len(ids) { t.Fatalf("queue metadata = %+v", result) } if result.BudgetExceeded { t.Fatal("BudgetExceeded = true, want false after a full queue scan") } } func TestFetchCommitsOnlyBoundedScannedPrefix(t *testing.T) { ids := make([]string, 30) for i := range ids { ids[i] = primitive.NewObjectID().Hex() } reservation := testReservation(ids, 100) deps := testFetchDependencies( reservation, func(context.Context, []primitive.ObjectID) ([]*vidmod.VideoModel, error) { return nil, nil }, ) committed := 0 deps.commit = func( _ context.Context, _ uint64, _ recommendqueue.Reservation, consumed int, ) error { committed = consumed return nil } result, err := fetch(context.Background(), 8, 3, "request-2", fetchOptions{ maxBatches: 2, scanMultiplier: 10, }, deps) if err != nil { t.Fatalf("fetch() error = %v", err) } if result.Batches != 2 || result.Scanned != 6 || committed != 6 { t.Fatalf("committed=%d result=%+v", committed, result) } if !result.BudgetExceeded { t.Fatal("BudgetExceeded = false, want true") } } func TestFetchMongoFailureAbortsWithoutCommitOrPartialResponse(t *testing.T) { valid := primitive.NewObjectID() filtered := primitive.NewObjectID() failing := primitive.NewObjectID() wantErr := errors.New("mongo unavailable") findCalls := 0 deps := testFetchDependencies( testReservation( []string{valid.Hex(), filtered.Hex(), failing.Hex()}, 10, ), func(_ context.Context, ids []primitive.ObjectID) ([]*vidmod.VideoModel, error) { findCalls++ if findCalls == 1 { return []*vidmod.VideoModel{{ID: valid}}, nil } return nil, wantErr }, ) commitCalls, abortCalls := 0, 0 deps.commit = func( context.Context, uint64, recommendqueue.Reservation, int, ) error { commitCalls++ return nil } deps.abort = func( context.Context, uint64, recommendqueue.Reservation, ) error { abortCalls++ return nil } result, err := fetch(context.Background(), 9, 2, "request-3", fetchOptions{ maxBatches: 5, scanMultiplier: 5, }, deps) if !errors.Is(err, wantErr) { t.Fatalf("error = %v, want %v", err, wantErr) } if result.Videos != nil || commitCalls != 0 || abortCalls != 1 { t.Fatalf("result=%+v commitCalls=%d abortCalls=%d", result, commitCalls, abortCalls) } if result.Scanned != 2 || result.Batches != 1 { t.Fatalf("successful scan metrics = %+v", result) } } func TestFetchRetriesUncertainCommitWithSameReservation(t *testing.T) { id := primitive.NewObjectID() wantErr := errors.New("connection reset after write") deps := testFetchDependencies( testReservation([]string{id.Hex()}, 10), func(context.Context, []primitive.ObjectID) ([]*vidmod.VideoModel, error) { return []*vidmod.VideoModel{{ID: id}}, nil }, ) commitCalls := 0 deps.commit = func( context.Context, uint64, recommendqueue.Reservation, int, ) error { commitCalls++ if commitCalls == 1 { return wantErr } return nil } result, err := fetch(context.Background(), 10, 1, "request-4", fetchOptions{ maxBatches: 5, scanMultiplier: 5, }, deps) if err != nil { t.Fatalf("fetch() error = %v", err) } if commitCalls != 2 || len(result.Videos) != 1 { t.Fatalf("commitCalls=%d result=%+v", commitCalls, result) } } func TestFetchCommitFailureAbortsAndSuppressesVideos(t *testing.T) { id := primitive.NewObjectID() wantErr := errors.New("redis unavailable") deps := testFetchDependencies( testReservation([]string{id.Hex()}, 10), func(context.Context, []primitive.ObjectID) ([]*vidmod.VideoModel, error) { return []*vidmod.VideoModel{{ID: id}}, nil }, ) commitCalls, abortCalls := 0, 0 deps.commit = func( context.Context, uint64, recommendqueue.Reservation, int, ) error { commitCalls++ return wantErr } deps.abort = func( context.Context, uint64, recommendqueue.Reservation, ) error { abortCalls++ return nil } result, err := fetch(context.Background(), 11, 1, "request-5", fetchOptions{ maxBatches: 5, scanMultiplier: 5, }, deps) if !errors.Is(err, wantErr) { t.Fatalf("error = %v, want %v", err, wantErr) } if commitCalls != 2 || abortCalls != 1 || result.Videos != nil { t.Fatalf("commit=%d abort=%d result=%+v", commitCalls, abortCalls, result) } } func TestFetchReservationErrorCarriesQueueMetadata(t *testing.T) { deps := testFetchDependencies(recommendqueue.Reservation{}, nil) deps.reserve = func( context.Context, uint64, int, string, ) (recommendqueue.Reservation, error) { return recommendqueue.Reservation{ Version: "20260731-r2", Length: 100, }, recommendqueue.ErrReservationBusy } result, err := fetch(context.Background(), 12, 1, "", fetchOptions{}, deps) if !errors.Is(err, recommendqueue.ErrReservationBusy) { t.Fatalf("error = %v, want ErrReservationBusy", err) } if result.QueueVersion != "20260731-r2" || result.QueueLength != 100 { t.Fatalf("result = %+v", result) } } func TestFetchRetriesBusyReservationWithinRequest(t *testing.T) { id := primitive.NewObjectID() reservation := testReservation([]string{id.Hex()}, 10) deps := testFetchDependencies( reservation, func(context.Context, []primitive.ObjectID) ([]*vidmod.VideoModel, error) { return []*vidmod.VideoModel{{ID: id}}, nil }, ) reserveCalls := 0 deps.reserve = func( context.Context, uint64, int, string, ) (recommendqueue.Reservation, error) { reserveCalls++ if reserveCalls < 3 { return recommendqueue.Reservation{ Version: reservation.Version, Length: reservation.Length, }, recommendqueue.ErrReservationBusy } return reservation, nil } result, err := fetch(context.Background(), 12, 1, "", fetchOptions{}, deps) if err != nil { t.Fatalf("fetch() error = %v", err) } if reserveCalls != 3 || len(result.Videos) != 1 { t.Fatalf("reserveCalls=%d result=%+v", reserveCalls, result) } } func TestReserveBusyRetryHonorsCancellation(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) calls := 0 _, err := reserveWithBusyRetry( ctx, func( context.Context, uint64, int, string, ) (recommendqueue.Reservation, error) { calls++ cancel() return recommendqueue.Reservation{}, recommendqueue.ErrReservationBusy }, 1, 20, "", ) if !errors.Is(err, context.Canceled) || calls != 1 { t.Fatalf("error=%v calls=%d", err, calls) } } func TestFetchRejectsCanceledContextBeforeDependencies(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() called := false deps := testFetchDependencies(recommendqueue.Reservation{}, nil) deps.reserve = func( context.Context, uint64, int, string, ) (recommendqueue.Reservation, error) { called = true return recommendqueue.Reservation{}, nil } _, err := fetch(ctx, 13, 1, "request-6", fetchOptions{}, deps) if !errors.Is(err, context.Canceled) { t.Fatalf("error = %v, want context.Canceled", err) } if called { t.Fatal("dependency called after context cancellation") } } func TestFetchWithoutClientRequestIDUsesReservationWithoutBusinessReceiptScope(t *testing.T) { id := primitive.NewObjectID() deps := testFetchDependencies( testReservation([]string{id.Hex()}, 1), func(context.Context, []primitive.ObjectID) ([]*vidmod.VideoModel, error) { return []*vidmod.VideoModel{{ID: id}}, nil }, ) gotRequestID := "not-called" originalReserve := deps.reserve deps.reserve = func( ctx context.Context, uid uint64, size int, requestID string, ) (recommendqueue.Reservation, error) { gotRequestID = requestID return originalReserve(ctx, uid, size, requestID) } result, err := fetch(context.Background(), 14, 1, "", fetchOptions{ maxBatches: 5, scanMultiplier: 5, }, deps) if err != nil { t.Fatalf("fetch() error = %v", err) } if gotRequestID != "" || len(result.Videos) != 1 { t.Fatalf("requestID=%q result=%+v", gotRequestID, result) } } func TestFetchCommittedReceiptReplaysEntireConsumedPrefix(t *testing.T) { ids := []string{ primitive.NewObjectID().Hex(), primitive.NewObjectID().Hex(), primitive.NewObjectID().Hex(), } reservation := testReservation(ids, 10) reservation.AlreadyCommitted = true deps := testFetchDependencies( reservation, func(_ context.Context, batch []primitive.ObjectID) ([]*vidmod.VideoModel, error) { out := make([]*vidmod.VideoModel, 0, len(batch)) for _, id := range batch { out = append(out, &vidmod.VideoModel{ID: id}) } return out, nil }, ) committed := 0 deps.commit = func( _ context.Context, _ uint64, _ recommendqueue.Reservation, consumed int, ) error { committed = consumed return nil } result, err := fetch(context.Background(), 15, 1, "request-retry", fetchOptions{ maxBatches: 1, scanMultiplier: 1, }, deps) if err != nil { t.Fatal(err) } if committed != len(ids) || result.Scanned != len(ids) || len(result.Videos) != 1 { t.Fatalf("committed=%d result=%+v", committed, result) } } func TestFetchCommittedReceiptUsesBoundedMongoBatches(t *testing.T) { const ( requestSize = 20 consumed = 100 ) ids := make([]string, consumed) for i := range ids { ids[i] = primitive.NewObjectID().Hex() } reservation := testReservation(ids, consumed) reservation.AlreadyCommitted = true batchSizes := make([]int, 0, consumed/requestSize) deps := testFetchDependencies( reservation, func(_ context.Context, batch []primitive.ObjectID) ([]*vidmod.VideoModel, error) { batchSizes = append(batchSizes, len(batch)) if len(batchSizes) > 1 { return nil, nil } videos := make([]*vidmod.VideoModel, 0, requestSize-1) for _, id := range batch[:requestSize-1] { videos = append(videos, &vidmod.VideoModel{ID: id}) } return videos, nil }, ) committed := 0 deps.commit = func( _ context.Context, _ uint64, _ recommendqueue.Reservation, value int, ) error { committed = value return nil } result, err := fetch(context.Background(), 16, requestSize, "request-retry", fetchOptions{ maxBatches: 1, scanMultiplier: 1, }, deps) if err != nil { t.Fatal(err) } if len(batchSizes) != consumed/requestSize { t.Fatalf("Mongo calls=%d batchSizes=%v", len(batchSizes), batchSizes) } for _, batchSize := range batchSizes { if batchSize != requestSize { t.Fatalf("batchSizes=%v", batchSizes) } } if committed != consumed || result.Scanned != consumed || len(result.Videos) != requestSize-1 { t.Fatalf("committed=%d result=%+v", committed, result) } } func TestScopedRequestIDSeparatesEntryAndRequestSize(t *testing.T) { first, err := scopedRequestID("recommend-list", 20, "request") if err != nil { t.Fatal(err) } same, _ := scopedRequestID("recommend-list", 20, " request ") otherEntry, _ := scopedRequestID("module-short-all", 20, "request") otherSize, _ := scopedRequestID("recommend-list", 10, "request") if first == "" || first != same { t.Fatalf("scoped IDs first=%q same=%q", first, same) } if first == otherEntry || first == otherSize || otherEntry == otherSize { t.Fatalf("scope collision: %q %q %q", first, otherEntry, otherSize) } blank, err := scopedRequestID("recommend-list", 20, " ") if err != nil || blank != "" { t.Fatalf("blank request ID = %q, %v", blank, err) } } func testReservation(ids []string, length int) recommendqueue.Reservation { return recommendqueue.Reservation{ Version: "20260731-r1", Length: length, Offset: 0, Reserved: len(ids), IDs: append([]string(nil), ids...), LeaseToken: "lease", ReceiptID: "receipt", } } func testFetchDependencies( reservation recommendqueue.Reservation, find func(context.Context, []primitive.ObjectID) ([]*vidmod.VideoModel, error), ) fetchDependencies { if find == nil { find = func(context.Context, []primitive.ObjectID) ([]*vidmod.VideoModel, error) { return nil, nil } } return fetchDependencies{ reserve: func( context.Context, uint64, int, string, ) (recommendqueue.Reservation, error) { return reservation, nil }, commit: func( context.Context, uint64, recommendqueue.Reservation, int, ) error { return nil }, abort: func( context.Context, uint64, recommendqueue.Reservation, ) error { return nil }, excludedModuleIDs: func(time.Time, bool) ([]string, error) { return nil, nil }, findVideos: find, now: time.Now, } }