Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/handlers/import_video_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func TestImportFromVideo_Accepted_AndPoll(t *testing.T) {

// Poll the status endpoint until the async job completes.
path := "/recipes/import/video/" + itoa(accepted.Job.ID)
deadline := time.Now().Add(3 * time.Second)
deadline := time.Now().Add(testutil.AsyncDeadline)
var lastStatus string
for time.Now().Before(deadline) {
gw := httptest.NewRecorder()
Expand Down
4 changes: 2 additions & 2 deletions internal/service/import_video_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ func newVideoTestService(repo *testutil.MockRecipeRepo, vrepo *testutil.MockVide
// waitForVideoJob polls until the job reaches a terminal state or times out.
func waitForVideoJob(t *testing.T, svc *ImportService, id uint) *models.VideoImport {
t.Helper()
deadline := time.Now().Add(3 * time.Second)
deadline := time.Now().Add(testutil.AsyncDeadline)
for time.Now().Before(deadline) {
job, err := svc.GetVideoImport(id)
if err == nil && (job.Status == models.VideoImportDone || job.Status == models.VideoImportFailed) {
Expand Down Expand Up @@ -470,7 +470,7 @@ func TestVideoImport_RefundsQuotaOnFailure(t *testing.T) {
}
// The refund runs in the goroutine after the job is marked failed; poll the
// lock-synchronized counter until it lands.
deadline := time.Now().Add(2 * time.Second)
deadline := time.Now().Add(testutil.AsyncDeadline)
for time.Now().Before(deadline) && userRepo.SubscriptionUsage(user.ID, "video_imports_used") != 0 {
time.Sleep(5 * time.Millisecond)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/service/multi_recipe_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func newResolverForTest(preview ai.TextProvider, canonicalRepo *testutil.MockCan
// waitResolved polls the entry until background extraction finishes.
func waitResolved(t *testing.T, entry *MultiRecipeEntry) {
t.Helper()
deadline := time.Now().Add(3 * time.Second)
deadline := time.Now().Add(testutil.AsyncDeadline)
for time.Now().Before(deadline) {
if entry.GetStatus() == "resolved" {
return
Expand Down
18 changes: 18 additions & 0 deletions internal/testutil/async.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package testutil

import "time"

// AsyncDeadline bounds the test helpers that poll for a background goroutine to
// finish (video import jobs, multi-recipe resolution, hub room teardown).
//
// It is deliberately generous, and that costs nothing: every one of those loops
// exits the moment the work lands, so the happy path is unaffected. The deadline
// only decides how long a genuinely stuck test waits before failing.
//
// A tight bound here is really a timing assertion on the Go scheduler. Under a
// loaded parallel suite — `go test ./...` compiling and running every package at
// once, which is exactly what the CI deploy gate does — a background goroutine
// can be starved for seconds. That is how TestVideoImport_NativeVideoUsed failed
// at a 3-second deadline while passing in isolation: nothing was broken, the
// machine was just busy. Flaky gates get ignored, so buy the margin.
const AsyncDeadline = 30 * time.Second
4 changes: 3 additions & 1 deletion internal/ws/hub_rooms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package ws
import (
"testing"
"time"

"github.com/windoze95/saltybytes-api/internal/testutil"
)

// roomExists checks the hub's room map under its lock.
Expand All @@ -16,7 +18,7 @@ func roomExists(h *Hub, roomID string) bool {
// waitForRoomGone polls until the room disappears from the hub or times out.
func waitForRoomGone(t *testing.T, h *Hub, roomID string) {
t.Helper()
deadline := time.Now().Add(2 * time.Second)
deadline := time.Now().Add(testutil.AsyncDeadline)
for roomExists(h, roomID) {
if time.Now().After(deadline) {
t.Fatalf("room %q was not removed from the hub", roomID)
Expand Down
Loading