package envpool_test import ( "context" "errors" "reflect" "testing" "time" "github.com/jfraeys/fetch_ml/internal/envpool" ) type fakeRunner struct { outputs map[string][]byte errs map[string]error calls []call } type call struct { name string args []string } func (r *fakeRunner) CombinedOutput(_ context.Context, name string, args ...string) ([]byte, error) { r.calls = append(r.calls, call{name: name, args: append([]string(nil), args...)}) key := name + " " + join(args) out := r.outputs[key] if err, ok := r.errs[key]; ok { return out, err } return out, nil } func join(args []string) string { if len(args) == 0 { return "" } s := args[0] for i := 1; i < len(args); i++ { s += " " + args[i] } return s } func TestWarmImageTag(t *testing.T) { p := envpool.New("") tag, err := p.WarmImageTag("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") if err != nil { t.Fatalf("unexpected error: %v", err) } if tag != "fetchml-prewarm:aaaaaaaaaaaa" { t.Fatalf("unexpected tag: %q", tag) } if _, err := p.WarmImageTag(""); err == nil { t.Fatalf("expected error for empty sha") } if _, err := p.WarmImageTag("ABC"); err == nil { t.Fatalf("expected error for invalid sha") } } func TestImageExists_NotFoundOutputIsFalse(t *testing.T) { r := &fakeRunner{outputs: map[string][]byte{}, errs: map[string]error{}} p := envpool.New("").WithRunner(r).WithCacheTTL(10 * time.Second) key := "podman image inspect fetchml-prewarm:deadbeef" r.outputs[key] = []byte("Error: no such image fetchml-prewarm:deadbeef") r.errs[key] = errors.New("exit") exists, err := p.ImageExists(context.Background(), "fetchml-prewarm:deadbeef") if err != nil { t.Fatalf("unexpected error: %v", err) } if exists { t.Fatalf("expected exists=false") } } func TestPrepare_SkipsWhenImageAlreadyExists(t *testing.T) { r := &fakeRunner{outputs: map[string][]byte{}, errs: map[string]error{}} p := envpool.New("").WithRunner(r).WithCacheTTL(10 * time.Second) inspectKey := "podman image inspect fetchml-prewarm:aaaaaaaaaaaa" r.outputs[inspectKey] = []byte("ok") err := p.Prepare(context.Background(), envpool.PrepareRequest{ BaseImage: "base:latest", TargetImage: "fetchml-prewarm:aaaaaaaaaaaa", HostWorkspace: "/tmp/ws", ContainerWorkspace: "/workspace", DepsPathInContainer: "/workspace/requirements.txt", }) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(r.calls) != 1 { t.Fatalf("expected only image inspect call, got %d", len(r.calls)) } wantArgs := []string{"image", "inspect", "fetchml-prewarm:aaaaaaaaaaaa"} if r.calls[0].name != "podman" || !reflect.DeepEqual(r.calls[0].args, wantArgs) { t.Fatalf("unexpected call: %+v", r.calls[0]) } } func TestPrepare_RequiresDepsUnderWorkspace(t *testing.T) { p := envpool.New("") err := p.Prepare(context.Background(), envpool.PrepareRequest{ BaseImage: "base:latest", TargetImage: "fetchml-prewarm:aaaaaaaaaaaa", HostWorkspace: "/tmp/ws", ContainerWorkspace: "/workspace", DepsPathInContainer: "/etc/passwd", }) if err == nil { t.Fatalf("expected error") } }