package runtime import ( "slices" "testing" ) func requireEqualArgs(t *testing.T, got, want []string) { t.Helper() if !slices.Equal(got, want) { t.Fatalf("args mismatch\ngot: %v\nwant: %v", got, want) } } func TestBuildRunArgs(t *testing.T) { p := &Podman{} t.Run("full spec", func(t *testing.T) { spec := ContainerSpec{ Name: "metacrypt-api", Image: "mcr.svc.mcp.metacircular.net:8443/metacrypt:v1.0.0", Network: "docker_default", User: "0:0", Restart: "unless-stopped", Ports: []string{"127.0.0.1:18443:8443", "127.0.0.1:19443:9443"}, Volumes: []string{"/srv/metacrypt:/srv/metacrypt", "/etc/ssl:/etc/ssl:ro"}, Cmd: []string{"server", "--config", "/srv/metacrypt/metacrypt.toml"}, } requireEqualArgs(t, p.BuildRunArgs(spec), []string{ "run", "-d", "--name", "metacrypt-api", "--network", "docker_default", "--user", "0:0", "--restart", "unless-stopped", "-p", "127.0.0.1:18443:8443", "-p", "127.0.0.1:19443:9443", "-v", "/srv/metacrypt:/srv/metacrypt", "-v", "/etc/ssl:/etc/ssl:ro", "mcr.svc.mcp.metacircular.net:8443/metacrypt:v1.0.0", "server", "--config", "/srv/metacrypt/metacrypt.toml", }) }) t.Run("minimal spec", func(t *testing.T) { spec := ContainerSpec{ Name: "test-app", Image: "img:latest", } requireEqualArgs(t, p.BuildRunArgs(spec), []string{ "run", "-d", "--name", "test-app", "img:latest", }) }) t.Run("ports only", func(t *testing.T) { spec := ContainerSpec{ Name: "test-app", Image: "img:latest", Ports: []string{"8080:80", "8443:443"}, } requireEqualArgs(t, p.BuildRunArgs(spec), []string{ "run", "-d", "--name", "test-app", "-p", "8080:80", "-p", "8443:443", "img:latest", }) }) t.Run("volumes only", func(t *testing.T) { spec := ContainerSpec{ Name: "test-app", Image: "img:latest", Volumes: []string{"/data:/data", "/config:/config:ro"}, } requireEqualArgs(t, p.BuildRunArgs(spec), []string{ "run", "-d", "--name", "test-app", "-v", "/data:/data", "-v", "/config:/config:ro", "img:latest", }) }) t.Run("env vars", func(t *testing.T) { spec := ContainerSpec{ Name: "test-app", Image: "img:latest", Env: []string{"PORT=12345", "PORT_GRPC=12346"}, } requireEqualArgs(t, p.BuildRunArgs(spec), []string{ "run", "-d", "--name", "test-app", "-e", "PORT=12345", "-e", "PORT_GRPC=12346", "img:latest", }) }) t.Run("full spec with env", func(t *testing.T) { // Route-allocated ports: host port = container port (matches $PORT). spec := ContainerSpec{ Name: "svc-api", Image: "img:latest", Network: "net", Ports: []string{"127.0.0.1:12345:12345"}, Volumes: []string{"/srv:/srv"}, Env: []string{"PORT=12345"}, } requireEqualArgs(t, p.BuildRunArgs(spec), []string{ "run", "-d", "--name", "svc-api", "--network", "net", "-p", "127.0.0.1:12345:12345", "-v", "/srv:/srv", "-e", "PORT=12345", "img:latest", }) }) t.Run("cmd after image", func(t *testing.T) { spec := ContainerSpec{ Name: "test-app", Image: "img:latest", Cmd: []string{"serve", "--port", "8080"}, } requireEqualArgs(t, p.BuildRunArgs(spec), []string{ "run", "-d", "--name", "test-app", "img:latest", "serve", "--port", "8080", }) }) } func TestExtractVersion(t *testing.T) { tests := []struct { image string want string }{ {"registry.example.com:5000/img:v1.2.0", "v1.2.0"}, {"img:latest", "latest"}, {"img", ""}, {"registry.example.com/path/img:v1", "v1"}, {"registry.example.com:5000/path/img", ""}, } for _, tt := range tests { t.Run(tt.image, func(t *testing.T) { got := ExtractVersion(tt.image) if got != tt.want { t.Fatalf("ExtractVersion(%q) = %q, want %q", tt.image, got, tt.want) } }) } }