1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-01-26 04:22:05 +02:00
goreleaser/internal/pipe/universalbinary/universalbinary_test.go
Carlos Alexandro Becker f544c5ce69
test: testctx pkg (#3807)
alternative to #3806 

the idea is that both `context.New` and `context.Context{}` are never
used in tests.

not sure yet how much I like it, so far code does look a bit more
readable though.

---------

Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
2023-03-02 00:01:11 -03:00

351 lines
9.4 KiB
Go

package universalbinary
import (
"debug/macho"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/testctx"
"github.com/goreleaser/goreleaser/internal/testlib"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/stretchr/testify/require"
)
func TestDescription(t *testing.T) {
require.NotEmpty(t, Pipe{}.String())
}
func TestDefault(t *testing.T) {
t.Run("empty", func(t *testing.T) {
ctx := testctx.NewWithCfg(config.Project{
ProjectName: "proj",
UniversalBinaries: []config.UniversalBinary{
{},
},
})
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, config.UniversalBinary{
ID: "proj",
IDs: []string{"proj"},
NameTemplate: "{{ .ProjectName }}",
}, ctx.Config.UniversalBinaries[0])
})
t.Run("given ids", func(t *testing.T) {
ctx := testctx.NewWithCfg(config.Project{
ProjectName: "proj",
UniversalBinaries: []config.UniversalBinary{
{IDs: []string{"foo"}},
},
})
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, config.UniversalBinary{
ID: "proj",
IDs: []string{"foo"},
NameTemplate: "{{ .ProjectName }}",
}, ctx.Config.UniversalBinaries[0])
})
t.Run("given id", func(t *testing.T) {
ctx := testctx.NewWithCfg(config.Project{
ProjectName: "proj",
UniversalBinaries: []config.UniversalBinary{
{ID: "foo"},
},
})
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, config.UniversalBinary{
ID: "foo",
IDs: []string{"foo"},
NameTemplate: "{{ .ProjectName }}",
}, ctx.Config.UniversalBinaries[0])
})
t.Run("given name", func(t *testing.T) {
ctx := testctx.NewWithCfg(config.Project{
ProjectName: "proj",
UniversalBinaries: []config.UniversalBinary{
{NameTemplate: "foo"},
},
})
require.NoError(t, Pipe{}.Default(ctx))
require.Equal(t, config.UniversalBinary{
ID: "proj",
IDs: []string{"proj"},
NameTemplate: "foo",
}, ctx.Config.UniversalBinaries[0])
})
t.Run("duplicated ids", func(t *testing.T) {
ctx := testctx.NewWithCfg(config.Project{
ProjectName: "proj",
UniversalBinaries: []config.UniversalBinary{
{ID: "foo"},
{ID: "foo"},
},
})
require.EqualError(t, Pipe{}.Default(ctx), `found 2 universal_binaries with the ID 'foo', please fix your config`)
})
}
func TestSkip(t *testing.T) {
t.Run("skip", func(t *testing.T) {
require.True(t, Pipe{}.Skip(testctx.New()))
})
t.Run("dont skip", func(t *testing.T) {
ctx := testctx.NewWithCfg(config.Project{
UniversalBinaries: []config.UniversalBinary{{}},
})
require.False(t, Pipe{}.Skip(ctx))
})
}
func TestRun(t *testing.T) {
dist := t.TempDir()
src := filepath.Join("testdata", "fake", "main.go")
paths := map[string]string{
"amd64": filepath.Join(dist, "fake_darwin_amd64/fake"),
"arm64": filepath.Join(dist, "fake_darwin_arm64/fake"),
}
pre := filepath.Join(dist, "pre")
post := filepath.Join(dist, "post")
cfg := config.Project{
Dist: dist,
UniversalBinaries: []config.UniversalBinary{
{
ID: "foo",
IDs: []string{"foo"},
NameTemplate: "foo",
Replace: true,
},
},
}
ctx1 := testctx.NewWithCfg(cfg)
ctx2 := testctx.NewWithCfg(config.Project{
Dist: dist,
UniversalBinaries: []config.UniversalBinary{
{
ID: "foo",
IDs: []string{"foo"},
NameTemplate: "foo",
},
},
})
ctx3 := testctx.NewWithCfg(config.Project{
Dist: dist,
UniversalBinaries: []config.UniversalBinary{
{
ID: "notfoo",
IDs: []string{"notfoo"},
NameTemplate: "notfoo",
},
},
})
ctx4 := testctx.NewWithCfg(config.Project{
Dist: dist,
UniversalBinaries: []config.UniversalBinary{
{
ID: "foo",
IDs: []string{"foo"},
NameTemplate: "foo",
},
},
})
ctx5 := testctx.NewWithCfg(config.Project{
Dist: dist,
UniversalBinaries: []config.UniversalBinary{
{
ID: "foo",
IDs: []string{"foo"},
NameTemplate: "foo",
Hooks: config.BuildHookConfig{
Pre: []config.Hook{
{Cmd: "touch " + pre},
},
Post: []config.Hook{
{Cmd: "touch " + post},
{Cmd: `sh -c 'echo "{{ .Name }} {{ .Os }} {{ .Arch }} {{ .Arm }} {{ .Target }} {{ .Ext }}" > {{ .Path }}.post'`, Output: true},
},
},
},
},
})
ctx6 := testctx.NewWithCfg(config.Project{
Dist: dist,
UniversalBinaries: []config.UniversalBinary{
{
ID: "foobar",
IDs: []string{"foo"},
NameTemplate: "foo",
},
},
})
for arch, path := range paths {
cmd := exec.Command("go", "build", "-o", path, src)
cmd.Env = append(os.Environ(), "GOOS=darwin", "GOARCH="+arch)
_, err := cmd.CombinedOutput()
require.NoError(t, err)
modTime := time.Unix(0, 0)
require.NoError(t, os.Chtimes(path, modTime, modTime))
art := artifact.Artifact{
Name: "fake",
Path: path,
Goos: "darwin",
Goarch: arch,
Type: artifact.Binary,
Extra: map[string]interface{}{
artifact.ExtraBinary: "fake",
artifact.ExtraID: "foo",
},
}
ctx1.Artifacts.Add(&art)
ctx2.Artifacts.Add(&art)
ctx5.Artifacts.Add(&art)
ctx6.Artifacts.Add(&art)
ctx4.Artifacts.Add(&artifact.Artifact{
Name: "fake",
Path: path + "wrong",
Goos: "darwin",
Goarch: arch,
Type: artifact.Binary,
Extra: map[string]interface{}{
artifact.ExtraBinary: "fake",
artifact.ExtraID: "foo",
},
})
}
t.Run("ensure new artifact id", func(t *testing.T) {
require.NoError(t, Pipe{}.Run(ctx6))
unis := ctx6.Artifacts.Filter(artifact.ByType(artifact.UniversalBinary)).List()
require.Len(t, unis, 1)
checkUniversalBinary(t, unis[0])
require.Equal(t, "foobar", unis[0].ID())
})
t.Run("replacing", func(t *testing.T) {
require.NoError(t, Pipe{}.Run(ctx1))
require.Len(t, ctx1.Artifacts.Filter(artifact.ByType(artifact.Binary)).List(), 0)
unis := ctx1.Artifacts.Filter(artifact.ByType(artifact.UniversalBinary)).List()
require.Len(t, unis, 1)
checkUniversalBinary(t, unis[0])
require.True(t, artifact.ExtraOr(*unis[0], artifact.ExtraReplaces, false))
})
t.Run("keeping", func(t *testing.T) {
require.NoError(t, Pipe{}.Run(ctx2))
require.Len(t, ctx2.Artifacts.Filter(artifact.ByType(artifact.Binary)).List(), 2)
unis := ctx2.Artifacts.Filter(artifact.ByType(artifact.UniversalBinary)).List()
require.Len(t, unis, 1)
checkUniversalBinary(t, unis[0])
require.False(t, artifact.ExtraOr(*unis[0], artifact.ExtraReplaces, true))
})
t.Run("bad template", func(t *testing.T) {
testlib.RequireTemplateError(t, Pipe{}.Run(testctx.NewWithCfg(config.Project{
UniversalBinaries: []config.UniversalBinary{
{
NameTemplate: "{{.Name}",
},
},
})))
})
t.Run("no darwin builds", func(t *testing.T) {
require.EqualError(t, Pipe{}.Run(ctx3), `no darwin binaries found with id "notfoo"`)
})
t.Run("fail to open", func(t *testing.T) {
require.ErrorIs(t, Pipe{}.Run(ctx4), os.ErrNotExist)
})
t.Run("hooks", func(t *testing.T) {
require.NoError(t, Pipe{}.Run(ctx5))
require.FileExists(t, pre)
require.FileExists(t, post)
post := filepath.Join(dist, "foo_darwin_all/foo.post")
require.FileExists(t, post)
bts, err := os.ReadFile(post)
require.NoError(t, err)
require.Equal(t, "foo darwin all darwin_all \n", string(bts))
})
t.Run("failing pre-hook", func(t *testing.T) {
ctx := ctx5
ctx.Config.UniversalBinaries[0].Hooks.Pre = []config.Hook{{Cmd: "exit 1"}}
ctx.Config.UniversalBinaries[0].Hooks.Post = []config.Hook{{Cmd: "echo post"}}
require.EqualError(t, Pipe{}.Run(ctx), "pre hook failed: failed to run 'exit 1': exec: \"exit\": executable file not found in $PATH")
})
t.Run("failing post-hook", func(t *testing.T) {
ctx := ctx5
ctx.Config.UniversalBinaries[0].Hooks.Pre = []config.Hook{{Cmd: "echo pre"}}
ctx.Config.UniversalBinaries[0].Hooks.Post = []config.Hook{{Cmd: "exit 1"}}
require.EqualError(t, Pipe{}.Run(ctx), "post hook failed: failed to run 'exit 1': exec: \"exit\": executable file not found in $PATH")
})
t.Run("hook with env tmpl", func(t *testing.T) {
ctx := ctx5
ctx.Config.UniversalBinaries[0].Hooks.Pre = []config.Hook{{
Cmd: "echo {{.Env.FOO}}",
Env: []string{"FOO=foo-{{.Tag}}"},
}}
ctx.Config.UniversalBinaries[0].Hooks.Post = []config.Hook{}
require.NoError(t, Pipe{}.Run(ctx))
})
t.Run("hook with bad env tmpl", func(t *testing.T) {
ctx := ctx5
ctx.Config.UniversalBinaries[0].Hooks.Pre = []config.Hook{{
Cmd: "echo blah",
Env: []string{"FOO=foo-{{.Tag}"},
}}
ctx.Config.UniversalBinaries[0].Hooks.Post = []config.Hook{}
testlib.RequireTemplateError(t, Pipe{}.Run(ctx))
})
t.Run("hook with bad dir tmpl", func(t *testing.T) {
ctx := ctx5
ctx.Config.UniversalBinaries[0].Hooks.Pre = []config.Hook{{
Cmd: "echo blah",
Dir: "{{.Tag}",
}}
ctx.Config.UniversalBinaries[0].Hooks.Post = []config.Hook{}
testlib.RequireTemplateError(t, Pipe{}.Run(ctx))
})
t.Run("hook with bad cmd tmpl", func(t *testing.T) {
ctx := ctx5
ctx.Config.UniversalBinaries[0].Hooks.Pre = []config.Hook{{
Cmd: "echo blah-{{.Tag }",
}}
ctx.Config.UniversalBinaries[0].Hooks.Post = []config.Hook{}
testlib.RequireTemplateError(t, Pipe{}.Run(ctx))
})
}
func checkUniversalBinary(tb testing.TB, unibin *artifact.Artifact) {
tb.Helper()
require.True(tb, strings.HasSuffix(unibin.Path, unibin.ID()+"_darwin_all/foo"))
f, err := macho.OpenFat(unibin.Path)
require.NoError(tb, err)
require.Len(tb, f.Arches, 2)
}