mirror of https://github.com/buildpacks/pack.git
391 lines
10 KiB
Go
391 lines
10 KiB
Go
package builder_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/heroku/color"
|
|
"github.com/sclevine/spec"
|
|
"github.com/sclevine/spec/report"
|
|
|
|
"github.com/buildpacks/pack/builder"
|
|
h "github.com/buildpacks/pack/testhelpers"
|
|
)
|
|
|
|
func TestConfig(t *testing.T) {
|
|
color.Disable(true)
|
|
defer color.Disable(false)
|
|
spec.Run(t, "testConfig", testConfig, spec.Parallel(), spec.Report(report.Terminal{}))
|
|
}
|
|
|
|
func testConfig(t *testing.T, when spec.G, it spec.S) {
|
|
when("#ReadConfig", func() {
|
|
var (
|
|
tmpDir string
|
|
builderConfigPath string
|
|
err error
|
|
)
|
|
|
|
it.Before(func() {
|
|
tmpDir, err = os.MkdirTemp("", "config-test")
|
|
h.AssertNil(t, err)
|
|
builderConfigPath = filepath.Join(tmpDir, "builder.toml")
|
|
})
|
|
|
|
it.After(func() {
|
|
h.AssertNil(t, os.RemoveAll(tmpDir))
|
|
})
|
|
|
|
when("file is written properly", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, os.WriteFile(builderConfigPath, []byte(`
|
|
[[buildpacks]]
|
|
id = "buildpack/1"
|
|
version = "0.0.1"
|
|
uri = "https://example.com/buildpack-1.tgz"
|
|
|
|
[[buildpacks]]
|
|
image = "example.com/buildpack:2"
|
|
|
|
[[buildpacks]]
|
|
uri = "https://example.com/buildpack-3.tgz"
|
|
|
|
[[order]]
|
|
[[order.group]]
|
|
id = "buildpack/1"
|
|
exec-env = ["production"]
|
|
|
|
[[build.env]]
|
|
name = "key1"
|
|
value = "value1"
|
|
suffix = "append"
|
|
delim = "%"
|
|
exec-env = ["test"]
|
|
|
|
`), 0666))
|
|
})
|
|
|
|
it("returns a builder config", func() {
|
|
builderConfig, warns, err := builder.ReadConfig(builderConfigPath)
|
|
h.AssertNil(t, err)
|
|
h.AssertEq(t, len(warns), 0)
|
|
|
|
h.AssertEq(t, builderConfig.Buildpacks[0].ID, "buildpack/1")
|
|
h.AssertEq(t, builderConfig.Buildpacks[0].Version, "0.0.1")
|
|
h.AssertEq(t, builderConfig.Buildpacks[0].URI, "https://example.com/buildpack-1.tgz")
|
|
h.AssertEq(t, builderConfig.Buildpacks[0].ImageName, "")
|
|
|
|
h.AssertEq(t, builderConfig.Buildpacks[1].ID, "")
|
|
h.AssertEq(t, builderConfig.Buildpacks[1].URI, "")
|
|
h.AssertEq(t, builderConfig.Buildpacks[1].ImageName, "example.com/buildpack:2")
|
|
|
|
h.AssertEq(t, builderConfig.Buildpacks[2].ID, "")
|
|
h.AssertEq(t, builderConfig.Buildpacks[2].URI, "https://example.com/buildpack-3.tgz")
|
|
h.AssertEq(t, builderConfig.Buildpacks[2].ImageName, "")
|
|
|
|
h.AssertEq(t, builderConfig.Order[0].Group[0].ID, "buildpack/1")
|
|
h.AssertTrue(t, len(builderConfig.Order[0].Group[0].ExecEnv) == 1)
|
|
h.AssertEq(t, builderConfig.Order[0].Group[0].ExecEnv[0], "production")
|
|
|
|
h.AssertTrue(t, len(builderConfig.Build.Env) == 1)
|
|
h.AssertEq(t, builderConfig.Build.Env[0].Name, "key1")
|
|
h.AssertEq(t, builderConfig.Build.Env[0].Value, "value1")
|
|
h.AssertEq(t, string(builderConfig.Build.Env[0].Suffix), "append")
|
|
h.AssertTrue(t, len(builderConfig.Build.Env[0].ExecEnv) == 1)
|
|
h.AssertEq(t, builderConfig.Build.Env[0].ExecEnv[0], "test")
|
|
})
|
|
})
|
|
|
|
when("an error occurs while reading", func() {
|
|
it("bubbles up the error", func() {
|
|
_, _, err := builder.ReadConfig(builderConfigPath)
|
|
h.AssertError(t, err, "opening config file")
|
|
})
|
|
})
|
|
|
|
when("detecting warnings", func() {
|
|
when("'groups' field is used", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, os.WriteFile(builderConfigPath, []byte(`
|
|
[[buildpacks]]
|
|
id = "some.buildpack"
|
|
version = "some.buildpack.version"
|
|
|
|
[[groups]]
|
|
[[groups.buildpacks]]
|
|
id = "some.buildpack"
|
|
version = "some.buildpack.version"
|
|
|
|
[[order]]
|
|
[[order.group]]
|
|
id = "some.buildpack"
|
|
`), 0666))
|
|
})
|
|
|
|
it("returns error when obsolete 'groups' field is used", func() {
|
|
_, warns, err := builder.ReadConfig(builderConfigPath)
|
|
h.AssertError(t, err, "parse contents of")
|
|
h.AssertEq(t, len(warns), 0)
|
|
})
|
|
})
|
|
|
|
when("'order' is missing or empty", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, os.WriteFile(builderConfigPath, []byte(`
|
|
[[buildpacks]]
|
|
id = "some.buildpack"
|
|
version = "some.buildpack.version"
|
|
`), 0666))
|
|
})
|
|
|
|
it("returns warnings", func() {
|
|
_, warns, err := builder.ReadConfig(builderConfigPath)
|
|
h.AssertNil(t, err)
|
|
|
|
h.AssertSliceContainsOnly(t, warns, "empty 'order' definition")
|
|
})
|
|
})
|
|
|
|
when("unknown buildpack key is present", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, os.WriteFile(builderConfigPath, []byte(`
|
|
[[buildpacks]]
|
|
url = "noop-buildpack.tgz"
|
|
`), 0666))
|
|
})
|
|
|
|
it("returns an error", func() {
|
|
_, _, err := builder.ReadConfig(builderConfigPath)
|
|
h.AssertError(t, err, "unknown configuration element 'buildpacks.url'")
|
|
})
|
|
})
|
|
|
|
when("unknown array table is present", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, os.WriteFile(builderConfigPath, []byte(`
|
|
[[buidlpack]]
|
|
uri = "noop-buildpack.tgz"
|
|
`), 0666))
|
|
})
|
|
|
|
it("returns an error", func() {
|
|
_, _, err := builder.ReadConfig(builderConfigPath)
|
|
h.AssertError(t, err, "unknown configuration element 'buidlpack'")
|
|
})
|
|
})
|
|
})
|
|
|
|
when("system buildpack is defined", func() {
|
|
it.Before(func() {
|
|
h.AssertNil(t, os.WriteFile(builderConfigPath, []byte(`
|
|
[[system.pre.buildpacks]]
|
|
id = "id-1"
|
|
version = "1.0"
|
|
optional = false
|
|
|
|
[[system.post.buildpacks]]
|
|
id = "id-2"
|
|
version = "2.0"
|
|
optional = true
|
|
`), 0666))
|
|
})
|
|
|
|
it("returns a builder config", func() {
|
|
builderConfig, _, err := builder.ReadConfig(builderConfigPath)
|
|
h.AssertNil(t, err)
|
|
h.AssertEq(t, len(builderConfig.System.Pre.Buildpacks), 1)
|
|
h.AssertEq(t, len(builderConfig.System.Post.Buildpacks), 1)
|
|
|
|
// Verify system.pre.buildpacks
|
|
h.AssertEq(t, builderConfig.System.Pre.Buildpacks[0].ID, "id-1")
|
|
h.AssertEq(t, builderConfig.System.Pre.Buildpacks[0].Version, "1.0")
|
|
h.AssertEq(t, builderConfig.System.Pre.Buildpacks[0].Optional, false)
|
|
|
|
// Verify system.post.buildpacks
|
|
h.AssertEq(t, builderConfig.System.Post.Buildpacks[0].ID, "id-2")
|
|
h.AssertEq(t, builderConfig.System.Post.Buildpacks[0].Version, "2.0")
|
|
h.AssertEq(t, builderConfig.System.Post.Buildpacks[0].Optional, true)
|
|
})
|
|
})
|
|
})
|
|
|
|
when("#ValidateConfig()", func() {
|
|
var (
|
|
testID = "testID"
|
|
testRunImage = "test-run-image"
|
|
testBuildImage = "test-build-image"
|
|
)
|
|
|
|
it("returns error if no stack id and no run images", func() {
|
|
config := builder.Config{
|
|
Stack: builder.StackConfig{
|
|
BuildImage: testBuildImage,
|
|
RunImage: testRunImage,
|
|
}}
|
|
h.AssertError(t, builder.ValidateConfig(config), "run.images are required")
|
|
})
|
|
|
|
it("returns error if no build image", func() {
|
|
config := builder.Config{
|
|
Stack: builder.StackConfig{
|
|
ID: testID,
|
|
RunImage: testRunImage,
|
|
}}
|
|
h.AssertError(t, builder.ValidateConfig(config), "build.image is required")
|
|
})
|
|
|
|
it("returns error if no run image", func() {
|
|
config := builder.Config{
|
|
Stack: builder.StackConfig{
|
|
ID: testID,
|
|
BuildImage: testBuildImage,
|
|
}}
|
|
h.AssertError(t, builder.ValidateConfig(config), "run.images are required")
|
|
})
|
|
|
|
it("returns error if no run images image", func() {
|
|
config := builder.Config{
|
|
Build: builder.BuildConfig{
|
|
Image: testBuildImage,
|
|
},
|
|
Run: builder.RunConfig{
|
|
Images: []builder.RunImageConfig{{
|
|
Image: "",
|
|
}},
|
|
}}
|
|
h.AssertError(t, builder.ValidateConfig(config), "run.images.image is required")
|
|
})
|
|
|
|
it("returns error if no stack or run image", func() {
|
|
config := builder.Config{
|
|
Build: builder.BuildConfig{
|
|
Image: testBuildImage,
|
|
}}
|
|
h.AssertError(t, builder.ValidateConfig(config), "run.images are required")
|
|
})
|
|
|
|
it("returns error if no stack and no build image", func() {
|
|
config := builder.Config{
|
|
Run: builder.RunConfig{
|
|
Images: []builder.RunImageConfig{{
|
|
Image: testBuildImage,
|
|
}},
|
|
}}
|
|
h.AssertError(t, builder.ValidateConfig(config), "build.image is required")
|
|
})
|
|
|
|
it("returns error if no stack, run, or build image", func() {
|
|
config := builder.Config{}
|
|
h.AssertError(t, builder.ValidateConfig(config), "build.image is required")
|
|
})
|
|
})
|
|
when("#ParseBuildConfigEnv()", func() {
|
|
it("should return an error when name is not defined", func() {
|
|
_, _, err := builder.ParseBuildConfigEnv([]builder.BuildConfigEnv{
|
|
{
|
|
Name: "",
|
|
Value: "vaiue",
|
|
},
|
|
}, "")
|
|
h.AssertNotNil(t, err)
|
|
})
|
|
it("should warn when the value is nil or empty string", func() {
|
|
env, warn, err := builder.ParseBuildConfigEnv([]builder.BuildConfigEnv{
|
|
{
|
|
Name: "key",
|
|
Value: "",
|
|
Suffix: "override",
|
|
},
|
|
}, "")
|
|
|
|
h.AssertNotNil(t, warn)
|
|
h.AssertNil(t, err)
|
|
h.AssertMapContains[string, string](t, env, h.NewKeyValue[string, string]("key.override", ""))
|
|
})
|
|
it("should return an error when unknown suffix is specified", func() {
|
|
_, _, err := builder.ParseBuildConfigEnv([]builder.BuildConfigEnv{
|
|
{
|
|
Name: "key",
|
|
Value: "",
|
|
Suffix: "invalid",
|
|
},
|
|
}, "")
|
|
|
|
h.AssertNotNil(t, err)
|
|
})
|
|
it("should override and show a warning when suffix or delim is defined multiple times", func() {
|
|
env, warn, err := builder.ParseBuildConfigEnv([]builder.BuildConfigEnv{
|
|
{
|
|
Name: "key1",
|
|
Value: "value1",
|
|
Suffix: "append",
|
|
Delim: "%",
|
|
},
|
|
{
|
|
Name: "key1",
|
|
Value: "value2",
|
|
Suffix: "append",
|
|
Delim: ",",
|
|
},
|
|
{
|
|
Name: "key1",
|
|
Value: "value3",
|
|
Suffix: "default",
|
|
Delim: ";",
|
|
},
|
|
{
|
|
Name: "key1",
|
|
Value: "value4",
|
|
Suffix: "prepend",
|
|
Delim: ":",
|
|
},
|
|
}, "")
|
|
|
|
h.AssertNotNil(t, warn)
|
|
h.AssertNil(t, err)
|
|
h.AssertMapContains[string, string](
|
|
t,
|
|
env,
|
|
h.NewKeyValue[string, string]("key1.append", "value2"),
|
|
h.NewKeyValue[string, string]("key1.default", "value3"),
|
|
h.NewKeyValue[string, string]("key1.prepend", "value4"),
|
|
h.NewKeyValue[string, string]("key1.delim", ":"),
|
|
)
|
|
h.AssertMapNotContains[string, string](
|
|
t,
|
|
env,
|
|
h.NewKeyValue[string, string]("key1.append", "value1"),
|
|
h.NewKeyValue[string, string]("key1.delim", "%"),
|
|
h.NewKeyValue[string, string]("key1.delim", ","),
|
|
h.NewKeyValue[string, string]("key1.delim", ";"),
|
|
)
|
|
})
|
|
it("should return an error when `suffix` is defined as `append` or `prepend` without a `delim`", func() {
|
|
_, warn, err := builder.ParseBuildConfigEnv([]builder.BuildConfigEnv{
|
|
{
|
|
Name: "key",
|
|
Value: "value",
|
|
Suffix: "append",
|
|
},
|
|
}, "")
|
|
|
|
h.AssertNotNil(t, warn)
|
|
h.AssertNotNil(t, err)
|
|
})
|
|
it("when suffix is NONE or omitted should default to `override`", func() {
|
|
env, warn, err := builder.ParseBuildConfigEnv([]builder.BuildConfigEnv{
|
|
{
|
|
Name: "key",
|
|
Value: "value",
|
|
Suffix: "",
|
|
},
|
|
}, "")
|
|
|
|
h.AssertNotNil(t, warn)
|
|
h.AssertNil(t, err)
|
|
h.AssertMapContains[string, string](t, env, h.NewKeyValue[string, string]("key", "value"))
|
|
})
|
|
})
|
|
}
|