Update comprehensive test coverage: - E2E tests with scheduler integration - Integration tests with tenant isolation - Unit tests with security assertions - Security tests with audit validation - Audit verification tests - Auth tests with tenant scoping - Config validation tests - Container security tests - Worker tests with scheduler mock - Environment pool tests - Load tests with distributed patterns - Test fixtures with scheduler support - Update go.mod/go.sum with new dependencies
119 lines
3.1 KiB
Go
119 lines
3.1 KiB
Go
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")
|
|
}
|
|
}
|