Files
kandev/apps/backend/internal/sprites/errors_test.go
T
José Almeida 85885dd866 feat(sprites): provision a fresh sandbox when the persisted one is gone
Resuming a Sprites task whose sandbox was destroyed upstream returned
"sprite not found" and dead-ended the user. Detect the upstream 404 via
a typed ErrSpriteNotFound sentinel, mark the reconnect step skipped with
a user-facing warning explaining what happened, swap the prepare plan
in place to the fresh-provision shape, and continue the launch under a
new sandbox name on the same branch.

The progress plan is now mutable so the reporter can stream the fresh
steps live after the reconnect-then-fresh transition. Only the explicit
not-found case triggers fallback; other reconnect failures still
surface as before, and the fallback fires at most once per launch.
2026-05-05 21:19:39 +01:00

63 lines
1.9 KiB
Go

package sprites
import (
"errors"
"fmt"
"testing"
)
func TestWrapNotFoundWraps404Errors(t *testing.T) {
cases := []struct {
name string
err error
want bool
}{
{name: "sprite not found exact", err: fmt.Errorf("sprite not found: kandev-abc"), want: true},
{name: "uppercase variant", err: fmt.Errorf("Sprite Not Found: kandev-abc"), want: true},
{name: "wrapped not found", err: fmt.Errorf("get sprite: %w", fmt.Errorf("sprite not found: kandev-abc")), want: true},
{name: "generic 404 mention", err: fmt.Errorf("HTTP 404: not found"), want: true},
{name: "auth failure", err: fmt.Errorf("401 unauthorized"), want: false},
{name: "transient 500", err: fmt.Errorf("internal server error"), want: false},
{name: "nil", err: nil, want: false},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
wrapped := WrapNotFound(tc.err)
got := errors.Is(wrapped, ErrSpriteNotFound)
if got != tc.want {
t.Fatalf("errors.Is(WrapNotFound(%v), ErrSpriteNotFound) = %v, want %v", tc.err, got, tc.want)
}
if got != IsNotFound(tc.err) {
t.Fatalf("IsNotFound(%v) disagrees with errors.Is on wrapped form", tc.err)
}
})
}
}
func TestWrapNotFoundPreservesOriginalError(t *testing.T) {
orig := fmt.Errorf("sprite not found: kandev-abc")
wrapped := WrapNotFound(orig)
if !errors.Is(wrapped, orig) {
t.Fatalf("WrapNotFound dropped the original error from the chain")
}
if !errors.Is(wrapped, ErrSpriteNotFound) {
t.Fatalf("WrapNotFound dropped the sentinel from the chain")
}
}
func TestWrapNotFoundIsIdempotent(t *testing.T) {
once := WrapNotFound(fmt.Errorf("sprite not found: kandev-abc"))
twice := WrapNotFound(once)
if once.Error() != twice.Error() {
t.Fatalf("WrapNotFound is not idempotent: once=%q, twice=%q", once, twice)
}
}
func TestWrapNotFoundNilPassthrough(t *testing.T) {
if WrapNotFound(nil) != nil {
t.Fatalf("WrapNotFound(nil) should return nil")
}
}