package image
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestSplitDockerfileAndContext_DefaultDockerfile(t *testing.T) {
ctxDir := t.TempDir()
dockerfile := filepath.Join(ctxDir, "Dockerfile")
if err := os.WriteFile(dockerfile, []byte("FROM scratch\n"), 0o644); err != nil {
t.Fatalf("write Dockerfile: %v", err)
}
gotDockerfile, gotContext, gotRest, err := splitDockerfileAndContext([]string{"-t", "demo:latest", ctxDir})
if err != nil {
t.Fatalf("splitDockerfileAndContext: %v", err)
}
if gotDockerfile != dockerfile {
t.Fatalf("dockerfile: got %q want %q", gotDockerfile, dockerfile)
}
if gotContext != ctxDir {
t.Fatalf("context: got %q want %q", gotContext, ctxDir)
}
if len(gotRest) != 2 || gotRest[0] != "-t" || gotRest[1] != "demo:latest" {
t.Fatalf("unexpected rest args: %#v", gotRest)
}
}
func TestSplitDockerfileAndContext_RejectsRemoteContext(t *testing.T) {
_, _, _, err := splitDockerfileAndContext([]string{"-f", "Dockerfile", "https://example.com/demo.git"})
if err == nil {
t.Fatal("expected remote context to fail")
}
if !strings.Contains(err.Error(), "remote build context") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestSplitDockerfileAndContext_DoesNotTreatBuildArgAsContext(t *testing.T) {
ctxDir := t.TempDir()
oldWD, err := os.Getwd()
if err != nil {
t.Fatalf("getwd: %v", err)
}
if err := os.Chdir(ctxDir); err != nil {
t.Fatalf("chdir: %v", err)
}
t.Cleanup(func() {
_ = os.Chdir(oldWD)
})
dockerfile := filepath.Join(ctxDir, "Dockerfile")
if err := os.WriteFile(dockerfile, []byte("FROM scratch\n"), 0o644); err != nil {
t.Fatalf("write Dockerfile: %v", err)
}
gotDockerfile, gotContext, gotRest, err := splitDockerfileAndContext([]string{"--build-arg", "FOO=bar"})
if err != nil {
t.Fatalf("splitDockerfileAndContext: %v", err)
}
if gotDockerfile != "Dockerfile" {
t.Fatalf("dockerfile: got %q want %q", gotDockerfile, "Dockerfile")
}
if gotContext != "." {
t.Fatalf("context: got %q want %q", gotContext, ".")
}
if len(gotRest) != 2 || gotRest[0] != "--build-arg" || gotRest[1] != "FOO=bar" {
t.Fatalf("unexpected rest args: %#v", gotRest)
}
}
func TestBuildahArgsPlaceContextLast(t *testing.T) {
patched := patchDockerfileFlag([]string{"-t", "demo:latest"}, "/tmp/processed.Dockerfile")
patched = ensureBuildahIsolation(patched)
patched = append(patched, "--iidfile", "/tmp/imageid")
patched = append(patched, "/tmp/context")
if got, want := patched[len(patched)-1], "/tmp/context"; got != want {
t.Fatalf("context must be last arg: got %q want %q (args=%#v)", got, want, patched)
}
for i := 0; i < len(patched)-1; i++ {
if patched[i] == "/tmp/context" {
t.Fatalf("context appeared before end of args: %#v", patched)
}
}
foundIID := false
for i := 0; i < len(patched)-1; i++ {
if patched[i] == "--iidfile" && i+1 < len(patched)-1 && patched[i+1] == "/tmp/imageid" {
foundIID = true
break
}
}
if !foundIID {
t.Fatalf("missing --iidfile pair before context: %#v", patched)
}
}
func TestEnsureBuildahIsolationAddsDefault(t *testing.T) {
got := ensureBuildahIsolation([]string{"-t", "demo:latest"})
want := []string{"--isolation", "chroot", "-t", "demo:latest"}
if strings.Join(got, "\x00") != strings.Join(want, "\x00") {
t.Fatalf("ensureBuildahIsolation() = %#v, want %#v", got, want)
}
}
func TestEnsureBuildahIsolationRespectsExistingValue(t *testing.T) {
tests := [][]string{
{"--isolation", "oci", "-t", "demo:latest"},
{"--isolation=oci", "-t", "demo:latest"},
}
for _, tt := range tests {
got := ensureBuildahIsolation(tt)
if strings.Join(got, "\x00") != strings.Join(tt, "\x00") {
t.Fatalf("ensureBuildahIsolation(%#v) = %#v, want unchanged", tt, got)
}
}
}
func TestFirstImageTag(t *testing.T) {
tests := []struct {
name string
args []string
want string
}{
{name: "short", args: []string{"-t", "demo:latest", "."}, want: "demo:latest"},
{name: "long", args: []string{"--tag", "demo:latest", "."}, want: "demo:latest"},
{name: "equals", args: []string{"--tag=demo:latest", "."}, want: "demo:latest"},
{name: "missing", args: []string{"."}, want: ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := firstImageTag(tt.args); got != tt.want {
t.Fatalf("firstImageTag(%#v) = %q, want %q", tt.args, got, tt.want)
}
})
}
}