summaryrefslogtreecommitdiff
path: root/builder/dockerfile/evaluator_test.go
blob: 5c40fed55875a90fe1c7faeb2202f489ce421c2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package dockerfile // import "github.com/docker/docker/builder/dockerfile"

import (
	"context"
	"os"
	"runtime"
	"testing"

	"github.com/docker/docker/builder/remotecontext"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/reexec"
	"github.com/moby/buildkit/frontend/dockerfile/instructions"
	"gotest.tools/v3/assert"
	is "gotest.tools/v3/assert/cmp"
	"gotest.tools/v3/skip"
)

type dispatchTestCase struct {
	name, expectedError string
	cmd                 instructions.Command
	files               map[string]string
}

func TestMain(m *testing.M) {
	if reexec.Init() {
		return
	}
	os.Exit(m.Run())
}

func TestDispatch(t *testing.T) {
	if runtime.GOOS != "windows" {
		skip.If(t, os.Getuid() != 0, "skipping test that requires root")
	}
	testCases := []dispatchTestCase{
		{
			name: "ADD multiple files to file",
			cmd: &instructions.AddCommand{SourcesAndDest: instructions.SourcesAndDest{
				SourcePaths: []string{"file1.txt", "file2.txt"},
				DestPath:    "test",
			}},
			expectedError: "When using ADD with more than one source file, the destination must be a directory and end with a /",
			files:         map[string]string{"file1.txt": "test1", "file2.txt": "test2"},
		},
		{
			name: "Wildcard ADD multiple files to file",
			cmd: &instructions.AddCommand{SourcesAndDest: instructions.SourcesAndDest{
				SourcePaths: []string{"file*.txt"},
				DestPath:    "test",
			}},
			expectedError: "When using ADD with more than one source file, the destination must be a directory and end with a /",
			files:         map[string]string{"file1.txt": "test1", "file2.txt": "test2"},
		},
		{
			name: "COPY multiple files to file",
			cmd: &instructions.CopyCommand{SourcesAndDest: instructions.SourcesAndDest{
				SourcePaths: []string{"file1.txt", "file2.txt"},
				DestPath:    "test",
			}},
			expectedError: "When using COPY with more than one source file, the destination must be a directory and end with a /",
			files:         map[string]string{"file1.txt": "test1", "file2.txt": "test2"},
		},
		{
			name: "ADD multiple files to file with whitespace",
			cmd: &instructions.AddCommand{SourcesAndDest: instructions.SourcesAndDest{
				SourcePaths: []string{"test file1.txt", "test file2.txt"},
				DestPath:    "test",
			}},
			expectedError: "When using ADD with more than one source file, the destination must be a directory and end with a /",
			files:         map[string]string{"test file1.txt": "test1", "test file2.txt": "test2"},
		},
		{
			name: "COPY multiple files to file with whitespace",
			cmd: &instructions.CopyCommand{SourcesAndDest: instructions.SourcesAndDest{
				SourcePaths: []string{"test file1.txt", "test file2.txt"},
				DestPath:    "test",
			}},
			expectedError: "When using COPY with more than one source file, the destination must be a directory and end with a /",
			files:         map[string]string{"test file1.txt": "test1", "test file2.txt": "test2"},
		},
		{
			name: "COPY wildcard no files",
			cmd: &instructions.CopyCommand{SourcesAndDest: instructions.SourcesAndDest{
				SourcePaths: []string{"file*.txt"},
				DestPath:    "/tmp/",
			}},
			expectedError: "COPY failed: no source files were specified",
			files:         nil,
		},
		{
			name: "COPY url",
			cmd: &instructions.CopyCommand{SourcesAndDest: instructions.SourcesAndDest{
				SourcePaths: []string{"https://example.com/index.html"},
				DestPath:    "/",
			}},
			expectedError: "source can't be a URL for COPY",
			files:         nil,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test")
			defer cleanup()

			for filename, content := range tc.files {
				createTestTempFile(t, contextDir, filename, content, 0777)
			}

			tarStream, err := archive.Tar(contextDir, archive.Uncompressed)

			if err != nil {
				t.Fatalf("Error when creating tar stream: %s", err)
			}

			defer func() {
				if err = tarStream.Close(); err != nil {
					t.Fatalf("Error when closing tar stream: %s", err)
				}
			}()

			buildContext, err := remotecontext.FromArchive(tarStream)

			if err != nil {
				t.Fatalf("Error when creating tar context: %s", err)
			}

			defer func() {
				if err = buildContext.Close(); err != nil {
					t.Fatalf("Error when closing tar context: %s", err)
				}
			}()

			b := newBuilderWithMockBackend(t)
			sb := newDispatchRequest(b, '`', buildContext, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
			err = dispatch(context.TODO(), sb, tc.cmd)
			assert.Check(t, is.ErrorContains(err, tc.expectedError))
		})
	}
}