package handlers import ( "context" "fmt" "log/slog" "net/http" "net/http/httptest" "strings" "testing" "sneak.berlin/go/pixa/internal/httpfetcher" "sneak.berlin/go/pixa/internal/imageprocessor" "sneak.berlin/go/pixa/internal/imageproxy" "sneak.berlin/go/pixa/internal/imagerequest" ) // TestServerBusyAnswers503 checks that respondImageError, which answers the // errors of both image routes, answers 503 with a clear error when the image // service gives up waiting for a free upstream connection or processing slot, // wrapped as the service wraps them. func TestServerBusyAnswers503(t *testing.T) { t.Parallel() h := &Handlers{log: slog.New(slog.DiscardHandler)} req := &imagerequest.Request{ Source: imagerequest.Source{Host: "img.example.com", Path: "/a.jpg"}, } for _, err := range []error{ fmt.Errorf("upstream fetch failed: %w", httpfetcher.ErrTooManyConnections), fmt.Errorf("image processing failed: %w", imageprocessor.ErrTooManyImages), } { rec := httptest.NewRecorder() h.respondImageError(rec, req, err) if rec.Code != http.StatusServiceUnavailable { t.Errorf("for %v: status = %d, want %d", err, rec.Code, http.StatusServiceUnavailable) } if !strings.Contains(rec.Body.String(), "server busy, try again later") { t.Errorf("for %v: body = %q, want the server busy error", err, rec.Body.String()) } } } // TestProcessingTimedOutAnswers503 checks that respondImageError, which // answers the errors of both image routes, answers 503 with the server busy // error when the image service reports that processing stopped at the // deadline of the request doing it, wrapped as the service wraps it. A request // that waited for that processing gets this error while its own deadline may // have time left. The request's source only goes into a log line, so it is // left empty. func TestProcessingTimedOutAnswers503(t *testing.T) { t.Parallel() h := &Handlers{log: slog.New(slog.DiscardHandler)} err := fmt.Errorf("%w: failed to encode: %w", imageproxy.ErrProcessingTimedOut, context.DeadlineExceeded) rec := httptest.NewRecorder() h.respondImageError(rec, &imagerequest.Request{}, err) t.Logf("status = %d, body = %q", rec.Code, rec.Body.String()) if rec.Code != http.StatusServiceUnavailable { t.Errorf("status = %d, want %d", rec.Code, http.StatusServiceUnavailable) } if !strings.Contains(rec.Body.String(), "server busy, try again later") { t.Errorf("body = %q, want the server busy error", rec.Body.String()) } }