github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/builder/dockerfile/evaluator_test.go (about)

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