buildkit/frontend/dockerfile/dockerfile_test.go

215 lines
4.9 KiB
Go
Raw Normal View History

package dockerfile
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"testing"
"time"
"github.com/containerd/containerd/fs/fstest"
"github.com/moby/buildkit/identity"
"github.com/moby/buildkit/util/testutil/httpserver"
"github.com/moby/buildkit/util/testutil/integration"
"github.com/stretchr/testify/require"
)
func TestIntegration(t *testing.T) {
integration.Run(t, []integration.Test{
testDockerfileDirs,
testDockerfileInvalidCommand,
testDockerfileADDFromURL,
})
}
func testDockerfileDirs(t *testing.T, sb integration.Sandbox) {
t.Parallel()
dockerfile := []byte(`
FROM busybox
COPY foo /foo2
COPY foo /
RUN echo -n bar > foo3
RUN test -f foo
RUN cmp -s foo foo2
RUN cmp -s foo foo3
`)
dir, err := tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("foo", []byte("bar"), 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)
args, trace := dfCmdArgs(dir, dir)
defer os.RemoveAll(trace)
cmd := sb.Cmd(args)
require.NoError(t, cmd.Run())
_, err = os.Stat(trace)
require.NoError(t, err)
// relative urls
args, trace = dfCmdArgs(".", ".")
defer os.RemoveAll(trace)
cmd = sb.Cmd(args)
cmd.Dir = dir
require.NoError(t, cmd.Run())
_, err = os.Stat(trace)
require.NoError(t, err)
// different context and dockerfile directories
dir1, err := tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir1)
dir2, err := tmpdir(
fstest.CreateFile("foo", []byte("bar"), 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir2)
args, trace = dfCmdArgs(dir2, dir1)
defer os.RemoveAll(trace)
cmd = sb.Cmd(args)
cmd.Dir = dir
require.NoError(t, cmd.Run())
_, err = os.Stat(trace)
require.NoError(t, err)
// TODO: test trace file output, cache hits, logs etc.
// TODO: output metadata about original dockerfile command in trace
}
func testDockerfileInvalidCommand(t *testing.T, sb integration.Sandbox) {
t.Parallel()
dockerfile := []byte(`
FROM busybox
RUN invalidcmd
`)
dir, err := tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)
args, trace := dfCmdArgs(dir, dir)
defer os.RemoveAll(trace)
cmd := sb.Cmd(args)
stdout := new(bytes.Buffer)
cmd.Stderr = stdout
err = cmd.Run()
require.Error(t, err)
require.Contains(t, stdout.String(), "/bin/sh -c invalidcmd")
require.Contains(t, stdout.String(), "worker failed running")
}
func testDockerfileADDFromURL(t *testing.T, sb integration.Sandbox) {
t.Parallel()
modTime := time.Now().Add(-24 * time.Hour) // avoid falso positive with current time
resp := httpserver.Response{
Etag: identity.NewID(),
Content: []byte("content1"),
}
resp2 := httpserver.Response{
Etag: identity.NewID(),
LastModified: &modTime,
Content: []byte("content2"),
}
server := httpserver.NewTestServer(map[string]httpserver.Response{
"/foo": resp,
"/": resp2,
})
defer server.Close()
dockerfile := []byte(fmt.Sprintf(`
FROM scratch
ADD %s /dest/
`, server.URL+"/foo"))
dir, err := tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)
args, trace := dfCmdArgs(dir, dir)
defer os.RemoveAll(trace)
destDir, err := tmpdir()
require.NoError(t, err)
defer os.RemoveAll(destDir)
cmd := sb.Cmd(args + fmt.Sprintf(" --exporter=local --exporter-opt output=%s", destDir))
err = cmd.Run()
require.NoError(t, err)
dt, err := ioutil.ReadFile(filepath.Join(destDir, "dest/foo"))
require.NoError(t, err)
require.Equal(t, []byte("content1"), dt)
// test the default properties
dockerfile = []byte(fmt.Sprintf(`
FROM scratch
ADD %s /dest/
`, server.URL+"/"))
dir, err = tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)
args, trace = dfCmdArgs(dir, dir)
defer os.RemoveAll(trace)
destDir, err = tmpdir()
require.NoError(t, err)
defer os.RemoveAll(destDir)
cmd = sb.Cmd(args + fmt.Sprintf(" --exporter=local --exporter-opt output=%s", destDir))
err = cmd.Run()
require.NoError(t, err)
destFile := filepath.Join(destDir, "dest/__unnamed__")
dt, err = ioutil.ReadFile(destFile)
require.NoError(t, err)
require.Equal(t, []byte("content2"), dt)
fi, err := os.Stat(destFile)
require.NoError(t, err)
require.Equal(t, fi.ModTime().Format(http.TimeFormat), modTime.Format(http.TimeFormat))
}
func tmpdir(appliers ...fstest.Applier) (string, error) {
tmpdir, err := ioutil.TempDir("", "buildkit-dockerfile")
if err != nil {
return "", err
}
if err := fstest.Apply(appliers...).Apply(tmpdir); err != nil {
return "", err
}
return tmpdir, nil
}
func dfCmdArgs(ctx, dockerfile string) (string, string) {
traceFile := filepath.Join(os.TempDir(), "trace"+identity.NewID())
return fmt.Sprintf("build --no-progress --frontend dockerfile.v0 --local context=%s --local dockerfile=%s --trace=%s", ctx, dockerfile, traceFile), traceFile
}