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