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 }