github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/builder/dockerfile/evaluator_test.go (about)

     1  package dockerfile // import "github.com/docker/docker/builder/dockerfile"
     2  
     3  import (
     4  	"os"
     5  	"runtime"
     6  	"testing"
     7  
     8  	"github.com/docker/docker/builder/remotecontext"
     9  	"github.com/docker/docker/pkg/archive"
    10  	"github.com/docker/docker/pkg/reexec"
    11  	"github.com/moby/buildkit/frontend/dockerfile/instructions"
    12  	"gotest.tools/v3/assert"
    13  	is "gotest.tools/v3/assert/cmp"
    14  	"gotest.tools/v3/skip"
    15  )
    16  
    17  type dispatchTestCase struct {
    18  	name, expectedError string
    19  	cmd                 instructions.Command
    20  	files               map[string]string
    21  }
    22  
    23  func init() {
    24  	reexec.Init()
    25  }
    26  
    27  func TestDispatch(t *testing.T) {
    28  	if runtime.GOOS != "windows" {
    29  		skip.If(t, os.Getuid() != 0, "skipping test that requires root")
    30  	}
    31  	testCases := []dispatchTestCase{
    32  		{
    33  			name: "ADD multiple files to file",
    34  			cmd: &instructions.AddCommand{SourcesAndDest: instructions.SourcesAndDest{
    35  				SourcePaths: []string{"file1.txt", "file2.txt"},
    36  				DestPath:    "test",
    37  			}},
    38  			expectedError: "When using ADD with more than one source file, the destination must be a directory and end with a /",
    39  			files:         map[string]string{"file1.txt": "test1", "file2.txt": "test2"},
    40  		},
    41  		{
    42  			name: "Wildcard ADD multiple files to file",
    43  			cmd: &instructions.AddCommand{SourcesAndDest: instructions.SourcesAndDest{
    44  				SourcePaths: []string{"file*.txt"},
    45  				DestPath:    "test",
    46  			}},
    47  			expectedError: "When using ADD with more than one source file, the destination must be a directory and end with a /",
    48  			files:         map[string]string{"file1.txt": "test1", "file2.txt": "test2"},
    49  		},
    50  		{
    51  			name: "COPY multiple files to file",
    52  			cmd: &instructions.CopyCommand{SourcesAndDest: instructions.SourcesAndDest{
    53  				SourcePaths: []string{"file1.txt", "file2.txt"},
    54  				DestPath:    "test",
    55  			}},
    56  			expectedError: "When using COPY with more than one source file, the destination must be a directory and end with a /",
    57  			files:         map[string]string{"file1.txt": "test1", "file2.txt": "test2"},
    58  		},
    59  		{
    60  			name: "ADD multiple files to file with whitespace",
    61  			cmd: &instructions.AddCommand{SourcesAndDest: instructions.SourcesAndDest{
    62  				SourcePaths: []string{"test file1.txt", "test file2.txt"},
    63  				DestPath:    "test",
    64  			}},
    65  			expectedError: "When using ADD with more than one source file, the destination must be a directory and end with a /",
    66  			files:         map[string]string{"test file1.txt": "test1", "test file2.txt": "test2"},
    67  		},
    68  		{
    69  			name: "COPY multiple files to file with whitespace",
    70  			cmd: &instructions.CopyCommand{SourcesAndDest: instructions.SourcesAndDest{
    71  				SourcePaths: []string{"test file1.txt", "test file2.txt"},
    72  				DestPath:    "test",
    73  			}},
    74  			expectedError: "When using COPY with more than one source file, the destination must be a directory and end with a /",
    75  			files:         map[string]string{"test file1.txt": "test1", "test file2.txt": "test2"},
    76  		},
    77  		{
    78  			name: "COPY wildcard no files",
    79  			cmd: &instructions.CopyCommand{SourcesAndDest: instructions.SourcesAndDest{
    80  				SourcePaths: []string{"file*.txt"},
    81  				DestPath:    "/tmp/",
    82  			}},
    83  			expectedError: "COPY failed: no source files were specified",
    84  			files:         nil,
    85  		},
    86  		{
    87  			name: "COPY url",
    88  			cmd: &instructions.CopyCommand{SourcesAndDest: instructions.SourcesAndDest{
    89  				SourcePaths: []string{"https://index.docker.io/robots.txt"},
    90  				DestPath:    "/",
    91  			}},
    92  			expectedError: "source can't be a URL for COPY",
    93  			files:         nil,
    94  		},
    95  	}
    96  
    97  	for _, tc := range testCases {
    98  		t.Run(tc.name, func(t *testing.T) {
    99  			contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test")
   100  			defer cleanup()
   101  
   102  			for filename, content := range tc.files {
   103  				createTestTempFile(t, contextDir, filename, content, 0777)
   104  			}
   105  
   106  			tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
   107  
   108  			if err != nil {
   109  				t.Fatalf("Error when creating tar stream: %s", err)
   110  			}
   111  
   112  			defer func() {
   113  				if err = tarStream.Close(); err != nil {
   114  					t.Fatalf("Error when closing tar stream: %s", err)
   115  				}
   116  			}()
   117  
   118  			context, err := remotecontext.FromArchive(tarStream)
   119  
   120  			if err != nil {
   121  				t.Fatalf("Error when creating tar context: %s", err)
   122  			}
   123  
   124  			defer func() {
   125  				if err = context.Close(); err != nil {
   126  					t.Fatalf("Error when closing tar context: %s", err)
   127  				}
   128  			}()
   129  
   130  			b := newBuilderWithMockBackend()
   131  			sb := newDispatchRequest(b, '`', context, NewBuildArgs(make(map[string]*string)), newStagesBuildResults())
   132  			err = dispatch(sb, tc.cmd)
   133  			assert.Check(t, is.ErrorContains(err, tc.expectedError))
   134  		})
   135  	}
   136  }