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  }