github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/build/container_test.go (about) 1 //go:build !skipcontainertests && !windows 2 // +build !skipcontainertests,!windows 3 4 // Tests that involve spinning up/interacting with actual containers 5 package build 6 7 import ( 8 "bytes" 9 "context" 10 "regexp" 11 "testing" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "github.com/tilt-dev/tilt/internal/container" 17 "github.com/tilt-dev/tilt/internal/docker" 18 "github.com/tilt-dev/tilt/internal/dockerfile" 19 "github.com/tilt-dev/tilt/pkg/apis/core/v1alpha1" 20 "github.com/tilt-dev/tilt/pkg/logger" 21 "github.com/tilt-dev/tilt/pkg/model" 22 ) 23 24 // * * * IMAGE BUILDER * * * 25 26 func TestDockerBuildDockerfile(t *testing.T) { 27 f := newDockerBuildFixture(t) 28 29 df := dockerfile.Dockerfile(` 30 FROM alpine 31 WORKDIR /src 32 ADD a.txt . 33 RUN cp a.txt b.txt 34 ADD dir/c.txt . 35 `) 36 37 f.WriteFile("a.txt", "a") 38 f.WriteFile("dir/c.txt", "c") 39 f.WriteFile("missing.txt", "missing") 40 41 spec := v1alpha1.DockerImageSpec{ 42 DockerfileContents: df.String(), 43 Context: f.Path(), 44 } 45 refs, _, err := f.b.BuildImage(f.ctx, f.ps, f.getNameFromTest(), spec, 46 defaultCluster, 47 nil, 48 model.EmptyMatcher) 49 if err != nil { 50 t.Fatal(err) 51 } 52 53 f.assertImageHasLabels(refs.LocalRef, docker.BuiltLabelSet) 54 55 pcs := []expectedFile{ 56 expectedFile{Path: "/src/a.txt", Contents: "a"}, 57 expectedFile{Path: "/src/b.txt", Contents: "a"}, 58 expectedFile{Path: "/src/c.txt", Contents: "c"}, 59 expectedFile{Path: "/src/dir/c.txt", Missing: true}, 60 expectedFile{Path: "/src/missing.txt", Missing: true}, 61 } 62 f.assertFilesInImage(refs.LocalRef, pcs) 63 } 64 65 func TestDockerBuildWithBuildArgs(t *testing.T) { 66 f := newDockerBuildFixture(t) 67 68 df := dockerfile.Dockerfile(`FROM alpine 69 ARG some_variable_name 70 71 ADD $some_variable_name /test.txt`) 72 73 f.WriteFile("awesome_variable", "hi im an awesome variable") 74 75 spec := v1alpha1.DockerImageSpec{ 76 DockerfileContents: df.String(), 77 Context: f.Path(), 78 Args: []string{"some_variable_name=awesome_variable"}, 79 } 80 refs, _, err := f.b.BuildImage(f.ctx, f.ps, f.getNameFromTest(), spec, 81 defaultCluster, 82 nil, 83 model.EmptyMatcher) 84 if err != nil { 85 t.Fatal(err) 86 } 87 88 expected := []expectedFile{ 89 expectedFile{Path: "/test.txt", Contents: "hi im an awesome variable"}, 90 } 91 f.assertFilesInImage(refs.LocalRef, expected) 92 } 93 94 func TestDockerBuildWithExtraTags(t *testing.T) { 95 f := newDockerBuildFixture(t) 96 97 df := dockerfile.Dockerfile(` 98 FROM alpine 99 WORKDIR /src 100 ADD a.txt .`) 101 102 f.WriteFile("a.txt", "a") 103 104 spec := v1alpha1.DockerImageSpec{ 105 DockerfileContents: df.String(), 106 Context: f.Path(), 107 ExtraTags: []string{"fe:jenkins-1234"}, 108 Args: []string{"some_variable_name=awesome_variable"}, 109 } 110 refs, _, err := f.b.BuildImage(f.ctx, f.ps, f.getNameFromTest(), spec, 111 defaultCluster, 112 nil, 113 model.EmptyMatcher) 114 if err != nil { 115 t.Fatal(err) 116 } 117 118 f.assertImageHasLabels(refs.LocalRef, docker.BuiltLabelSet) 119 120 pcs := []expectedFile{ 121 expectedFile{Path: "/src/a.txt", Contents: "a"}, 122 } 123 f.assertFilesInImage(container.MustParseNamedTagged("fe:jenkins-1234"), pcs) 124 } 125 126 func TestDetectBuildkitCorruption(t *testing.T) { 127 f := newDockerBuildFixture(t) 128 129 out := bytes.NewBuffer(nil) 130 ctx := logger.WithLogger(context.Background(), logger.NewTestLogger(out)) 131 ps := NewPipelineState(ctx, 1, ProvideClock()) 132 133 spec := v1alpha1.DockerImageSpec{ 134 // Simulate buildkit corruption 135 DockerfileContents: `FROM alpine 136 RUN echo 'failed to create LLB definition: failed commit on ref "unknown-sha256:b72fa303a3a5fbf52c723bfcfb93948bb53b3d7e8d22418e9d171a27ad7dcd84": "unknown-sha256:b72fa303a3a5fbf52c723bfcfb93948bb53b3d7e8d22418e9d171a27ad7dcd84" failed size validation: 80941 != 80929: failed precondition' && exit 1 137 `, 138 Context: f.Path(), 139 } 140 _, _, err := f.b.BuildImage(ctx, ps, f.getNameFromTest(), spec, 141 defaultCluster, 142 nil, 143 model.EmptyMatcher) 144 assert.Error(t, err) 145 assert.Contains(t, out.String(), "Detected Buildkit corruption. Rebuilding without Buildkit") 146 assert.Contains(t, out.String(), "[1/2] FROM docker.io/library/alpine") // buildkit-style output 147 assert.True(t, regexp.MustCompile("Step 1/[0-9]+ : FROM alpine").MatchString(out.String())) // Legacy output 148 } 149 150 func TestDockerBuildEmptyContext(t *testing.T) { 151 f := newDockerBuildFixture(t) 152 153 df := dockerfile.Dockerfile(` 154 FROM alpine 155 `) 156 157 spec := v1alpha1.DockerImageSpec{ 158 DockerfileContents: df.String(), 159 Context: "-", 160 } 161 refs, _, err := f.b.BuildImage(f.ctx, f.ps, f.getNameFromTest(), spec, 162 defaultCluster, 163 nil, 164 model.EmptyMatcher) 165 require.NoError(t, err) 166 f.assertImageHasLabels(refs.LocalRef, docker.BuiltLabelSet) 167 } 168 169 func TestDockerBuildMissingContext(t *testing.T) { 170 f := newDockerBuildFixture(t) 171 172 df := dockerfile.Dockerfile(` 173 FROM alpine 174 `) 175 176 spec := v1alpha1.DockerImageSpec{ 177 DockerfileContents: df.String(), 178 Context: "unknown-dir", 179 } 180 _, _, err := f.b.BuildImage(f.ctx, f.ps, f.getNameFromTest(), spec, 181 defaultCluster, 182 nil, 183 model.EmptyMatcher) 184 if assert.Error(t, err) { 185 assert.Contains(t, err.Error(), "reading build context: stat unknown-dir: no such file or directory") 186 } 187 }