gitee.com/mirrors_opencollective/goreleaser@v0.45.0/pipeline/docker/docker_test.go (about)

     1  package docker
     2  
     3  import (
     4  	"flag"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"syscall"
    10  	"testing"
    11  
    12  	"github.com/goreleaser/goreleaser/config"
    13  	"github.com/goreleaser/goreleaser/context"
    14  	"github.com/goreleaser/goreleaser/internal/artifact"
    15  	"github.com/goreleaser/goreleaser/pipeline"
    16  	"github.com/stretchr/testify/assert"
    17  )
    18  
    19  var it = flag.Bool("it", false, "push images to docker hub")
    20  var registry = "localhost:5000/"
    21  
    22  func TestMain(m *testing.M) {
    23  	flag.Parse()
    24  	if *it {
    25  		registry = "docker.io/"
    26  	}
    27  	os.Exit(m.Run())
    28  }
    29  
    30  func start(t *testing.T) {
    31  	if *it {
    32  		return
    33  	}
    34  	if err := exec.Command(
    35  		"docker", "run", "-d", "-p", "5000:5000", "--name", "registry", "registry:2",
    36  	).Run(); err != nil {
    37  		t.Log("failed to start docker registry", err)
    38  		t.FailNow()
    39  	}
    40  }
    41  
    42  func killAndRm(t *testing.T) {
    43  	if *it {
    44  		return
    45  	}
    46  	t.Log("killing registry")
    47  	_ = exec.Command("docker", "kill", "registry").Run()
    48  	_ = exec.Command("docker", "rm", "registry").Run()
    49  }
    50  
    51  func TestRunPipe(t *testing.T) {
    52  	var table = map[string]struct {
    53  		docker  config.Docker
    54  		publish bool
    55  		expect  []string
    56  		err     string
    57  	}{
    58  		"valid": {
    59  			publish: true,
    60  			docker: config.Docker{
    61  				Image:      registry + "goreleaser/test_run_pipe",
    62  				Goos:       "linux",
    63  				Goarch:     "amd64",
    64  				Dockerfile: "testdata/Dockerfile",
    65  				Binary:     "mybin",
    66  				TagTemplates: []string{
    67  					"{{.Tag}}-{{.Env.FOO}}",
    68  					"v{{.Major}}",
    69  					"v{{.Major}}.{{.Minor}}",
    70  					"latest",
    71  				},
    72  				Files: []string{
    73  					"testdata/extra_file.txt",
    74  				},
    75  			},
    76  			expect: []string{
    77  				registry + "goreleaser/test_run_pipe:v1.0.0-123",
    78  				registry + "goreleaser/test_run_pipe:v1",
    79  				registry + "goreleaser/test_run_pipe:v1.0",
    80  				registry + "goreleaser/test_run_pipe:latest",
    81  			},
    82  			err: "",
    83  		},
    84  		"valid_no_latest": {
    85  			publish: true,
    86  			docker: config.Docker{
    87  				Image:      registry + "goreleaser/test_run_pipe",
    88  				Goos:       "linux",
    89  				Goarch:     "amd64",
    90  				Dockerfile: "testdata/Dockerfile",
    91  				Binary:     "mybin",
    92  				TagTemplates: []string{
    93  					"{{.Version}}",
    94  				},
    95  				Files: []string{
    96  					"testdata/extra_file.txt",
    97  				},
    98  			},
    99  			expect: []string{
   100  				registry + "goreleaser/test_run_pipe:1.0.0",
   101  			},
   102  			err: "",
   103  		},
   104  		"valid_dont_publish": {
   105  			publish: false,
   106  			docker: config.Docker{
   107  				Image:      registry + "goreleaser/test_run_pipe",
   108  				Goos:       "linux",
   109  				Goarch:     "amd64",
   110  				Dockerfile: "testdata/Dockerfile",
   111  				Binary:     "mybin",
   112  				TagTemplates: []string{
   113  					"{{.Tag}}-{{.Env.FOO}}",
   114  					"latest",
   115  				},
   116  				Files: []string{
   117  					"testdata/extra_file.txt",
   118  				},
   119  			},
   120  			expect: []string{
   121  				registry + "goreleaser/test_run_pipe:v1.0.0-123",
   122  				registry + "goreleaser/test_run_pipe:latest",
   123  			},
   124  			err: "",
   125  		},
   126  		"bad_dockerfile": {
   127  			publish: true,
   128  			docker: config.Docker{
   129  				Image:      registry + "goreleaser/test_run_pipe",
   130  				Goos:       "linux",
   131  				Goarch:     "amd64",
   132  				Dockerfile: "testdata/Dockerfile.bad",
   133  				Binary:     "mybin",
   134  				TagTemplates: []string{
   135  					"{{.Version}}",
   136  				},
   137  			},
   138  			err: "pull access denied for nope, repository does not exist",
   139  		},
   140  		"template_error": {
   141  			publish: true,
   142  			docker: config.Docker{
   143  				Image:      registry + "goreleaser/test_run_pipe",
   144  				Goos:       "linux",
   145  				Goarch:     "amd64",
   146  				Dockerfile: "testdata/Dockerfile",
   147  				Binary:     "mybin",
   148  				TagTemplates: []string{
   149  					"{{.Tag}",
   150  				},
   151  			},
   152  			err: `template: tag:1: unexpected "}" in operand`,
   153  		},
   154  		"missing_env_on_template": {
   155  			publish: true,
   156  			docker: config.Docker{
   157  				Image:      registry + "goreleaser/test_run_pipe",
   158  				Goos:       "linux",
   159  				Goarch:     "amd64",
   160  				Dockerfile: "testdata/Dockerfile",
   161  				Binary:     "mybin",
   162  				TagTemplates: []string{
   163  					"{{.Env.NOPE}}",
   164  				},
   165  			},
   166  			err: `template: tag:1:6: executing "tag" at <.Env.NOPE>: map has no entry for key "NOPE"`,
   167  		},
   168  		"no_permissions": {
   169  			publish: true,
   170  			docker: config.Docker{
   171  				Image:      "docker.io/nope",
   172  				Goos:       "linux",
   173  				Goarch:     "amd64",
   174  				Binary:     "mybin",
   175  				Dockerfile: "testdata/Dockerfile",
   176  				TagTemplates: []string{
   177  					"{{.Tag}}",
   178  					"latest",
   179  				},
   180  				Latest: true,
   181  			},
   182  			expect: []string{
   183  				"docker.io/nope:latest",
   184  				"docker.io/nope:v1.0.0",
   185  			},
   186  			err: `requested access to the resource is denied`,
   187  		},
   188  		"dockerfile_doesnt_exist": {
   189  			publish: true,
   190  			docker: config.Docker{
   191  				Image:      "whatever",
   192  				Goos:       "linux",
   193  				Goarch:     "amd64",
   194  				Binary:     "mybin",
   195  				Dockerfile: "testdata/Dockerfilezzz",
   196  				TagTemplates: []string{
   197  					"{{.Tag}}",
   198  				},
   199  			},
   200  			err: `failed to link dockerfile`,
   201  		},
   202  		"extra_file_doesnt_exist": {
   203  			publish: true,
   204  			docker: config.Docker{
   205  				Image:  "whatever",
   206  				Goos:   "linux",
   207  				Goarch: "amd64",
   208  				Binary: "mybin",
   209  				Files: []string{
   210  					"testdata/nope.txt",
   211  				},
   212  				Dockerfile: "testdata/Dockerfile",
   213  				TagTemplates: []string{
   214  					"{{.Tag}}",
   215  				},
   216  			},
   217  			err: `failed to link extra file 'testdata/nope.txt'`,
   218  		},
   219  		"no_matching_binaries": {
   220  			publish: true,
   221  			docker: config.Docker{
   222  				Image:      "whatever",
   223  				Goos:       "darwin",
   224  				Goarch:     "amd64",
   225  				Binary:     "mybinnnn",
   226  				Dockerfile: "testdata/Dockerfile",
   227  			},
   228  			err: "",
   229  		},
   230  	}
   231  
   232  	killAndRm(t)
   233  	start(t)
   234  	defer killAndRm(t)
   235  
   236  	for name, docker := range table {
   237  		t.Run(name, func(tt *testing.T) {
   238  			folder, err := ioutil.TempDir("", "archivetest")
   239  			assert.NoError(tt, err)
   240  			var dist = filepath.Join(folder, "dist")
   241  			assert.NoError(tt, os.Mkdir(dist, 0755))
   242  			assert.NoError(tt, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
   243  			var binPath = filepath.Join(dist, "mybin", "mybin")
   244  			_, err = os.Create(binPath)
   245  			assert.NoError(tt, err)
   246  
   247  			var ctx = context.New(config.Project{
   248  				ProjectName: "mybin",
   249  				Dist:        dist,
   250  				Dockers: []config.Docker{
   251  					docker.docker,
   252  				},
   253  			})
   254  			ctx.Publish = docker.publish
   255  			ctx.Env = map[string]string{
   256  				"FOO": "123",
   257  			}
   258  			ctx.Version = "1.0.0"
   259  			ctx.Git = context.GitInfo{
   260  				CurrentTag: "v1.0.0",
   261  			}
   262  			for _, os := range []string{"linux", "darwin"} {
   263  				for _, arch := range []string{"amd64", "386"} {
   264  					ctx.Artifacts.Add(artifact.Artifact{
   265  						Name:   "mybin",
   266  						Path:   binPath,
   267  						Goarch: arch,
   268  						Goos:   os,
   269  						Type:   artifact.Binary,
   270  						Extra: map[string]string{
   271  							"Binary": "mybin",
   272  						},
   273  					})
   274  				}
   275  			}
   276  
   277  			// this might fail as the image doesnt exist yet, so lets ignore the error
   278  			for _, img := range docker.expect {
   279  				_ = exec.Command("docker", "rmi", img).Run()
   280  			}
   281  
   282  			err = Pipe{}.Run(ctx)
   283  			if docker.err == "" {
   284  				assert.NoError(tt, err)
   285  			} else {
   286  				assert.Error(tt, err)
   287  				if err != nil {
   288  					assert.Contains(tt, err.Error(), docker.err)
   289  				}
   290  			}
   291  
   292  			// this might should not fail as the image should have been created when
   293  			// the step ran
   294  			for _, img := range docker.expect {
   295  				tt.Log("removing docker image", img)
   296  				assert.NoError(tt, exec.Command("docker", "rmi", img).Run(), "could not delete image %s", img)
   297  			}
   298  
   299  		})
   300  	}
   301  }
   302  
   303  func TestDescription(t *testing.T) {
   304  	assert.NotEmpty(t, Pipe{}.String())
   305  }
   306  
   307  func TestNoDockers(t *testing.T) {
   308  	assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{}))))
   309  }
   310  
   311  func TestNoDockerWithoutImageName(t *testing.T) {
   312  	assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{
   313  		Dockers: []config.Docker{
   314  			{
   315  				Goos: "linux",
   316  			},
   317  		},
   318  	}))))
   319  }
   320  
   321  func TestDockerNotInPath(t *testing.T) {
   322  	var path = os.Getenv("PATH")
   323  	defer func() {
   324  		assert.NoError(t, os.Setenv("PATH", path))
   325  	}()
   326  	assert.NoError(t, os.Setenv("PATH", ""))
   327  	var ctx = &context.Context{
   328  		Version: "1.0.0",
   329  		Config: config.Project{
   330  			Dockers: []config.Docker{
   331  				{
   332  					Image: "a/b",
   333  				},
   334  			},
   335  		},
   336  	}
   337  	assert.EqualError(t, Pipe{}.Run(ctx), ErrNoDocker.Error())
   338  }
   339  
   340  func TestDefault(t *testing.T) {
   341  	var ctx = &context.Context{
   342  		Config: config.Project{
   343  			Builds: []config.Build{
   344  				{
   345  					Binary: "foo",
   346  				},
   347  			},
   348  			Dockers: []config.Docker{
   349  				{
   350  					Latest: true,
   351  				},
   352  			},
   353  		},
   354  	}
   355  	assert.NoError(t, Pipe{}.Default(ctx))
   356  	assert.Len(t, ctx.Config.Dockers, 1)
   357  	var docker = ctx.Config.Dockers[0]
   358  	assert.Equal(t, "linux", docker.Goos)
   359  	assert.Equal(t, "amd64", docker.Goarch)
   360  	assert.Equal(t, ctx.Config.Builds[0].Binary, docker.Binary)
   361  	assert.Equal(t, "Dockerfile", docker.Dockerfile)
   362  	assert.Empty(t, docker.OldTagTemplate)
   363  	assert.Equal(t, []string{"{{ .Version }}", "latest"}, docker.TagTemplates)
   364  
   365  }
   366  
   367  func TestDefaultNoDockers(t *testing.T) {
   368  	var ctx = &context.Context{
   369  		Config: config.Project{
   370  			Dockers: []config.Docker{},
   371  		},
   372  	}
   373  	assert.NoError(t, Pipe{}.Default(ctx))
   374  	assert.Empty(t, ctx.Config.Dockers)
   375  }
   376  
   377  func TestDefaultSet(t *testing.T) {
   378  	var ctx = &context.Context{
   379  		Config: config.Project{
   380  			Dockers: []config.Docker{
   381  				{
   382  					Goos:       "windows",
   383  					Goarch:     "i386",
   384  					Binary:     "bar",
   385  					Dockerfile: "Dockerfile.foo",
   386  				},
   387  			},
   388  		},
   389  	}
   390  	assert.NoError(t, Pipe{}.Default(ctx))
   391  	assert.Len(t, ctx.Config.Dockers, 1)
   392  	var docker = ctx.Config.Dockers[0]
   393  	assert.Equal(t, "windows", docker.Goos)
   394  	assert.Equal(t, "i386", docker.Goarch)
   395  	assert.Equal(t, "bar", docker.Binary)
   396  	assert.Empty(t, docker.OldTagTemplate)
   397  	assert.Equal(t, []string{"{{ .Version }}"}, docker.TagTemplates)
   398  	assert.Equal(t, "Dockerfile.foo", docker.Dockerfile)
   399  }
   400  
   401  func TestDefaultWithOldTagTemplateSet(t *testing.T) {
   402  	var ctx = &context.Context{
   403  		Config: config.Project{
   404  			Dockers: []config.Docker{
   405  				{
   406  					Dockerfile:     "Dockerfile.foo",
   407  					OldTagTemplate: "{{.Tag}}",
   408  					Latest:         true,
   409  					Binary:         "foo",
   410  				},
   411  			},
   412  		},
   413  	}
   414  	assert.NoError(t, Pipe{}.Default(ctx))
   415  	assert.Len(t, ctx.Config.Dockers, 1)
   416  	var docker = ctx.Config.Dockers[0]
   417  	assert.Equal(t, []string{"{{.Tag}}", "latest"}, docker.TagTemplates)
   418  	assert.Equal(t, "Dockerfile.foo", docker.Dockerfile)
   419  }
   420  
   421  func TestLinkFile(t *testing.T) {
   422  	const srcFile = "/tmp/test"
   423  	const dstFile = "/tmp/linked"
   424  	err := ioutil.WriteFile(srcFile, []byte("foo"), 0644)
   425  	if err != nil {
   426  		t.Log("Cannot setup test file")
   427  		t.Fail()
   428  	}
   429  	err = link(srcFile, dstFile)
   430  	if err != nil {
   431  		t.Log("Failed to link: ", err)
   432  		t.Fail()
   433  	}
   434  	if inode(srcFile) != inode(dstFile) {
   435  		t.Log("Inodes do not match, destination file is not a link")
   436  		t.Fail()
   437  	}
   438  	// cleanup
   439  	os.Remove(srcFile)
   440  	os.Remove(dstFile)
   441  }
   442  
   443  func TestLinkDirectory(t *testing.T) {
   444  	const srcDir = "/tmp/testdir"
   445  	const testFile = "test"
   446  	const dstDir = "/tmp/linkedDir"
   447  
   448  	os.Mkdir(srcDir, 0755)
   449  	err := ioutil.WriteFile(srcDir+"/"+testFile, []byte("foo"), 0644)
   450  	if err != nil {
   451  		t.Log("Cannot setup test file")
   452  		t.Fail()
   453  	}
   454  	err = link(srcDir, dstDir)
   455  	if err != nil {
   456  		t.Log("Failed to link: ", err)
   457  		t.Fail()
   458  	}
   459  	if inode(srcDir+"/"+testFile) != inode(dstDir+"/"+testFile) {
   460  		t.Log("Inodes do not match, destination file is not a link")
   461  		t.Fail()
   462  	}
   463  
   464  	// cleanup
   465  	os.RemoveAll(srcDir)
   466  	os.RemoveAll(dstDir)
   467  }
   468  
   469  func TestLinkTwoLevelDirectory(t *testing.T) {
   470  	const srcDir = "/tmp/testdir"
   471  	const srcLevel2 = srcDir + "/level2"
   472  	const testFile = "test"
   473  	const dstDir = "/tmp/linkedDir"
   474  
   475  	os.Mkdir(srcDir, 0755)
   476  	os.Mkdir(srcLevel2, 0755)
   477  	err := ioutil.WriteFile(srcDir+"/"+testFile, []byte("foo"), 0644)
   478  	if err != nil {
   479  		t.Log("Cannot setup test file")
   480  		t.Fail()
   481  	}
   482  	err = ioutil.WriteFile(srcLevel2+"/"+testFile, []byte("foo"), 0644)
   483  	if err != nil {
   484  		t.Log("Cannot setup test file")
   485  		t.Fail()
   486  	}
   487  	err = link(srcDir, dstDir)
   488  	if err != nil {
   489  		t.Log("Failed to link: ", err)
   490  		t.Fail()
   491  	}
   492  	if inode(srcDir+"/"+testFile) != inode(dstDir+"/"+testFile) {
   493  		t.Log("Inodes do not match")
   494  		t.Fail()
   495  	}
   496  	if inode(srcLevel2+"/"+testFile) != inode(dstDir+"/level2/"+testFile) {
   497  		t.Log("Inodes do not match")
   498  		t.Fail()
   499  	}
   500  	// cleanup
   501  	os.RemoveAll(srcDir)
   502  	os.RemoveAll(dstDir)
   503  }
   504  
   505  func inode(file string) uint64 {
   506  	fileInfo, err := os.Stat(file)
   507  	if err != nil {
   508  		return 0
   509  	}
   510  	stat := fileInfo.Sys().(*syscall.Stat_t)
   511  	return stat.Ino
   512  }