1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-10 03:47:03 +02:00
goreleaser/internal/pipeline/docker/docker_test.go

567 lines
13 KiB
Go
Raw Normal View History

2017-09-12 05:29:12 +02:00
package docker
import (
"flag"
2017-09-13 01:58:02 +02:00
"io/ioutil"
2017-09-12 05:29:12 +02:00
"os"
2017-09-13 01:58:02 +02:00
"os/exec"
"path/filepath"
2017-12-26 03:53:44 +02:00
"syscall"
"testing"
2017-12-26 03:53:44 +02:00
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/pipeline"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
2017-09-13 01:58:02 +02:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2017-09-12 05:29:12 +02:00
)
var it = flag.Bool("it", false, "push images to docker hub")
var registry = "localhost:5000/"
func TestMain(m *testing.M) {
2017-12-26 19:24:19 +02:00
flag.Parse()
if *it {
registry = "docker.io/"
}
os.Exit(m.Run())
}
func start(t *testing.T) {
2017-12-26 19:41:50 +02:00
if *it {
return
}
if out, err := exec.Command(
"docker", "run", "-d", "-p", "5000:5000", "--name", "registry", "registry:2",
).CombinedOutput(); err != nil {
t.Log("failed to start docker registry", string(out), err)
t.FailNow()
}
}
func killAndRm(t *testing.T) {
2017-12-26 19:41:50 +02:00
if *it {
return
}
t.Log("killing registry")
_ = exec.Command("docker", "kill", "registry").Run()
_ = exec.Command("docker", "rm", "registry").Run()
}
2017-09-13 01:58:02 +02:00
func TestRunPipe(t *testing.T) {
type errChecker func(*testing.T, error)
var shouldErr = func(msg string) errChecker {
return func(t *testing.T, err error) {
require.Error(t, err)
require.Contains(t, err.Error(), msg)
}
}
var shouldNotErr = func(t *testing.T, err error) {
require.NoError(t, err)
}
var table = map[string]struct {
dockers []config.Docker
publish bool
expect []string
assertError errChecker
}{
"valid": {
publish: true,
dockers: []config.Docker{
{
Image: registry + "goreleaser/test_run_pipe",
Goos: "linux",
Goarch: "amd64",
Dockerfile: "testdata/Dockerfile",
Binary: "mybin",
TagTemplates: []string{
"{{.Tag}}-{{.Env.FOO}}",
"v{{.Major}}",
"v{{.Major}}.{{.Minor}}",
"commint-{{.Commit}}",
"le-{{.Os}}",
"latest",
},
Files: []string{
"testdata/extra_file.txt",
},
},
},
expect: []string{
registry + "goreleaser/test_run_pipe:v1.0.0-123",
registry + "goreleaser/test_run_pipe:v1",
registry + "goreleaser/test_run_pipe:v1.0",
registry + "goreleaser/test_run_pipe:le-linux",
registry + "goreleaser/test_run_pipe:latest",
},
assertError: shouldNotErr,
},
"multiple images with same dockerfile": {
publish: true,
dockers: []config.Docker{
{
Image: registry + "goreleaser/test_run_pipe",
Goos: "linux",
Goarch: "amd64",
Dockerfile: "testdata/Dockerfile",
Binary: "mybin",
TagTemplates: []string{"latest"},
},
{
Image: registry + "goreleaser/test_run_pipe2",
Goos: "linux",
Goarch: "amd64",
Dockerfile: "testdata/Dockerfile",
Binary: "mybin",
TagTemplates: []string{"latest"},
},
},
expect: []string{
registry + "goreleaser/test_run_pipe:latest",
registry + "goreleaser/test_run_pipe2:latest",
},
assertError: shouldNotErr,
},
"valid_skip_push": {
publish: true,
dockers: []config.Docker{
{
Image: registry + "goreleaser/test_run_pipe",
Goos: "linux",
Goarch: "amd64",
Dockerfile: "testdata/Dockerfile",
Binary: "mybin",
SkipPush: true,
TagTemplates: []string{
"{{.Tag}}-{{.Env.FOO}}",
"v{{.Major}}",
"v{{.Major}}.{{.Minor}}",
"latest",
},
Files: []string{
"testdata/extra_file.txt",
},
},
},
expect: []string{
registry + "goreleaser/test_run_pipe:v1.0.0-123",
registry + "goreleaser/test_run_pipe:v1",
registry + "goreleaser/test_run_pipe:v1.0",
registry + "goreleaser/test_run_pipe:latest",
},
assertError: shouldNotErr,
},
"valid_no_latest": {
publish: true,
dockers: []config.Docker{
{
Image: registry + "goreleaser/test_run_pipe",
Goos: "linux",
Goarch: "amd64",
Dockerfile: "testdata/Dockerfile",
Binary: "mybin",
TagTemplates: []string{
"{{.Version}}",
},
Files: []string{
"testdata/extra_file.txt",
},
},
},
expect: []string{
registry + "goreleaser/test_run_pipe:1.0.0",
},
assertError: shouldNotErr,
},
"valid_dont_publish": {
publish: false,
dockers: []config.Docker{
{
Image: registry + "goreleaser/test_run_pipe",
Goos: "linux",
Goarch: "amd64",
Dockerfile: "testdata/Dockerfile",
Binary: "mybin",
TagTemplates: []string{
"{{.Tag}}-{{.Env.FOO}}",
"latest",
},
Files: []string{
"testdata/extra_file.txt",
},
},
},
expect: []string{
registry + "goreleaser/test_run_pipe:v1.0.0-123",
registry + "goreleaser/test_run_pipe:latest",
},
assertError: shouldNotErr,
},
"bad_dockerfile": {
publish: true,
dockers: []config.Docker{
{
Image: registry + "goreleaser/bad_dockerfile",
Goos: "linux",
Goarch: "amd64",
Dockerfile: "testdata/Dockerfile.bad",
Binary: "mybin",
TagTemplates: []string{
"{{.Version}}",
},
},
},
assertError: shouldErr("pull access denied for nope, repository does not exist"),
},
"template_error": {
publish: true,
dockers: []config.Docker{
{
Image: registry + "goreleaser/test_run_pipe",
Goos: "linux",
Goarch: "amd64",
Dockerfile: "testdata/Dockerfile",
Binary: "mybin",
TagTemplates: []string{
"{{.Tag}",
},
},
},
assertError: shouldErr(`template: tmpl:1: unexpected "}" in operand`),
},
"missing_env_on_template": {
publish: true,
dockers: []config.Docker{
{
Image: registry + "goreleaser/test_run_pipe",
Goos: "linux",
Goarch: "amd64",
Dockerfile: "testdata/Dockerfile",
Binary: "mybin",
TagTemplates: []string{
"{{.Env.NOPE}}",
},
},
},
assertError: shouldErr(`template: tmpl:1:6: executing "tmpl" at <.Env.NOPE>: map has no entry for key "NOPE"`),
},
"no_permissions": {
publish: true,
dockers: []config.Docker{
{
Image: "docker.io/nope",
Goos: "linux",
Goarch: "amd64",
Binary: "mybin",
Dockerfile: "testdata/Dockerfile",
TagTemplates: []string{
"{{.Tag}}",
"latest",
},
},
},
expect: []string{
"docker.io/nope:latest",
"docker.io/nope:v1.0.0",
},
assertError: shouldErr(`requested access to the resource is denied`),
},
"dockerfile_doesnt_exist": {
publish: true,
dockers: []config.Docker{
{
Image: "whatever",
Goos: "linux",
Goarch: "amd64",
Binary: "mybin",
Dockerfile: "testdata/Dockerfilezzz",
TagTemplates: []string{
"{{.Tag}}",
},
},
},
assertError: shouldErr(`failed to link dockerfile`),
},
"extra_file_doesnt_exist": {
publish: true,
dockers: []config.Docker{
{
Image: "whatever",
Goos: "linux",
Goarch: "amd64",
Binary: "mybin",
Files: []string{
"testdata/nope.txt",
},
Dockerfile: "testdata/Dockerfile",
TagTemplates: []string{
"{{.Tag}}",
},
},
},
assertError: shouldErr(`failed to link extra file 'testdata/nope.txt'`),
},
"no_matching_binaries": {
publish: true,
dockers: []config.Docker{
{
Image: "whatever",
Goos: "darwin",
Goarch: "amd64",
Binary: "mybinnnn",
Dockerfile: "testdata/Dockerfile",
},
},
assertError: shouldErr(`0 binaries match docker definition: mybinnnn: darwin_amd64_`),
},
}
killAndRm(t)
start(t)
defer killAndRm(t)
for name, docker := range table {
t.Run(name, func(tt *testing.T) {
folder, err := ioutil.TempDir("", "archivetest")
require.NoError(tt, err)
var dist = filepath.Join(folder, "dist")
require.NoError(tt, os.Mkdir(dist, 0755))
require.NoError(tt, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
var binPath = filepath.Join(dist, "mybin", "mybin")
_, err = os.Create(binPath)
require.NoError(tt, err)
2017-12-29 21:35:22 +02:00
var ctx = context.New(config.Project{
ProjectName: "mybin",
Dist: dist,
Dockers: docker.dockers,
2017-12-29 21:35:22 +02:00
})
ctx.SkipPublish = !docker.publish
2017-12-29 21:35:22 +02:00
ctx.Env = map[string]string{
"FOO": "123",
}
ctx.Version = "1.0.0"
ctx.Git = context.GitInfo{
CurrentTag: "v1.0.0",
}
for _, os := range []string{"linux", "darwin"} {
for _, arch := range []string{"amd64", "386"} {
ctx.Artifacts.Add(artifact.Artifact{
Name: "mybin",
Path: binPath,
Goarch: arch,
Goos: os,
Type: artifact.Binary,
Extra: map[string]string{
"Binary": "mybin",
},
})
}
}
// this might fail as the image doesnt exist yet, so lets ignore the error
for _, img := range docker.expect {
_ = exec.Command("docker", "rmi", img).Run()
}
docker.assertError(tt, Pipe{}.Run(ctx))
2017-09-15 01:16:49 +02:00
// this might should not fail as the image should have been created when
// the step ran
for _, img := range docker.expect {
2017-12-29 21:35:22 +02:00
tt.Log("removing docker image", img)
require.NoError(tt, exec.Command("docker", "rmi", img).Run(), "could not delete image %s", img)
}
})
2017-09-15 01:16:49 +02:00
}
2017-09-13 01:58:02 +02:00
}
2017-09-12 05:29:12 +02:00
func TestDescription(t *testing.T) {
assert.NotEmpty(t, Pipe{}.String())
2017-09-12 05:29:12 +02:00
}
func TestNoDockers(t *testing.T) {
assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{}))))
2017-09-12 05:29:12 +02:00
}
func TestNoDockerWithoutImageName(t *testing.T) {
assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{
2017-09-12 05:29:12 +02:00
Dockers: []config.Docker{
{
Goos: "linux",
},
},
}))))
}
func TestDockerNotInPath(t *testing.T) {
var path = os.Getenv("PATH")
defer func() {
assert.NoError(t, os.Setenv("PATH", path))
2017-09-12 05:29:12 +02:00
}()
assert.NoError(t, os.Setenv("PATH", ""))
2017-09-12 05:29:12 +02:00
var ctx = &context.Context{
Version: "1.0.0",
Config: config.Project{
Dockers: []config.Docker{
{
Image: "a/b",
},
},
},
}
assert.EqualError(t, Pipe{}.Run(ctx), ErrNoDocker.Error())
2017-09-12 05:29:12 +02:00
}
func TestDefault(t *testing.T) {
var ctx = &context.Context{
Config: config.Project{
Builds: []config.Build{
{
Binary: "foo",
},
},
Dockers: []config.Docker{
{},
},
},
}
assert.NoError(t, Pipe{}.Default(ctx))
assert.Len(t, ctx.Config.Dockers, 1)
var docker = ctx.Config.Dockers[0]
assert.Equal(t, "linux", docker.Goos)
assert.Equal(t, "amd64", docker.Goarch)
assert.Equal(t, ctx.Config.Builds[0].Binary, docker.Binary)
assert.Equal(t, "Dockerfile", docker.Dockerfile)
assert.Equal(t, []string{"{{ .Version }}"}, docker.TagTemplates)
}
func TestDefaultNoDockers(t *testing.T) {
var ctx = &context.Context{
Config: config.Project{
Dockers: []config.Docker{},
},
}
assert.NoError(t, Pipe{}.Default(ctx))
assert.Empty(t, ctx.Config.Dockers)
}
func TestDefaultSet(t *testing.T) {
var ctx = &context.Context{
Config: config.Project{
Dockers: []config.Docker{
{
Goos: "windows",
Goarch: "i386",
Binary: "bar",
Dockerfile: "Dockerfile.foo",
},
},
},
}
assert.NoError(t, Pipe{}.Default(ctx))
assert.Len(t, ctx.Config.Dockers, 1)
var docker = ctx.Config.Dockers[0]
assert.Equal(t, "windows", docker.Goos)
assert.Equal(t, "i386", docker.Goarch)
assert.Equal(t, "bar", docker.Binary)
assert.Equal(t, []string{"{{ .Version }}"}, docker.TagTemplates)
assert.Equal(t, "Dockerfile.foo", docker.Dockerfile)
}
func TestLinkFile(t *testing.T) {
const srcFile = "/tmp/test"
const dstFile = "/tmp/linked"
err := ioutil.WriteFile(srcFile, []byte("foo"), 0644)
if err != nil {
t.Log("Cannot setup test file")
t.Fail()
}
err = link(srcFile, dstFile)
if err != nil {
t.Log("Failed to link: ", err)
t.Fail()
}
if inode(srcFile) != inode(dstFile) {
t.Log("Inodes do not match, destination file is not a link")
t.Fail()
}
// cleanup
os.Remove(srcFile)
os.Remove(dstFile)
}
func TestLinkDirectory(t *testing.T) {
const srcDir = "/tmp/testdir"
const testFile = "test"
const dstDir = "/tmp/linkedDir"
os.Mkdir(srcDir, 0755)
err := ioutil.WriteFile(srcDir+"/"+testFile, []byte("foo"), 0644)
if err != nil {
t.Log("Cannot setup test file")
t.Fail()
}
2017-12-24 14:14:55 +02:00
err = link(srcDir, dstDir)
if err != nil {
t.Log("Failed to link: ", err)
t.Fail()
}
if inode(srcDir+"/"+testFile) != inode(dstDir+"/"+testFile) {
t.Log("Inodes do not match, destination file is not a link")
t.Fail()
}
// cleanup
os.RemoveAll(srcDir)
os.RemoveAll(dstDir)
}
func TestLinkTwoLevelDirectory(t *testing.T) {
const srcDir = "/tmp/testdir"
2017-12-26 03:53:44 +02:00
const srcLevel2 = srcDir + "/level2"
const testFile = "test"
const dstDir = "/tmp/linkedDir"
os.Mkdir(srcDir, 0755)
os.Mkdir(srcLevel2, 0755)
err := ioutil.WriteFile(srcDir+"/"+testFile, []byte("foo"), 0644)
if err != nil {
t.Log("Cannot setup test file")
t.Fail()
}
err = ioutil.WriteFile(srcLevel2+"/"+testFile, []byte("foo"), 0644)
if err != nil {
t.Log("Cannot setup test file")
t.Fail()
}
2017-12-24 14:14:55 +02:00
err = link(srcDir, dstDir)
if err != nil {
t.Log("Failed to link: ", err)
t.Fail()
}
if inode(srcDir+"/"+testFile) != inode(dstDir+"/"+testFile) {
t.Log("Inodes do not match")
t.Fail()
}
if inode(srcLevel2+"/"+testFile) != inode(dstDir+"/level2/"+testFile) {
t.Log("Inodes do not match")
t.Fail()
}
// cleanup
os.RemoveAll(srcDir)
os.RemoveAll(dstDir)
}
func inode(file string) uint64 {
fileInfo, err := os.Stat(file)
if err != nil {
return 0
}
stat := fileInfo.Sys().(*syscall.Stat_t)
return stat.Ino
}