lifecycle/platform/target_data_test.go

334 lines
12 KiB
Go

package platform_test
import (
"fmt"
"runtime"
"testing"
"github.com/apex/log"
"github.com/apex/log/handlers/memory"
"github.com/sclevine/spec"
"github.com/buildpacks/lifecycle/buildpack"
"github.com/buildpacks/lifecycle/internal/fsutil"
llog "github.com/buildpacks/lifecycle/log"
"github.com/buildpacks/lifecycle/platform"
"github.com/buildpacks/lifecycle/platform/files"
h "github.com/buildpacks/lifecycle/testhelpers"
)
func TestTargetData(t *testing.T) {
spec.Run(t, "target_data", testTargetData)
}
func testTargetData(t *testing.T, when spec.G, it spec.S) {
when(".TargetSatisfiedForBuild", func() {
baseTarget := &files.TargetMetadata{OS: "Win95", Arch: "Pentium"}
d := mockDetector{
contents: "this is just test contents really",
t: t,
HasFile: false, // by default, don't use info from /etc/os-release for these tests
}
when("base image data", func() {
when("has os and arch", func() {
when("buildpack data", func() {
when("has os and arch", func() {
it("must match", func() {
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch}, &log.Logger{Handler: memory.New()}), true)
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: "Win98", Arch: baseTarget.Arch}, &log.Logger{Handler: memory.New()}), false)
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: baseTarget.OS, Arch: "Pentium MMX"}, &log.Logger{Handler: memory.New()}), false)
})
})
when("missing os and arch", func() {
it("matches", func() {
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: "", Arch: ""}, &log.Logger{Handler: memory.New()}), true)
})
})
when("has distro information", func() {
it("does not match", func() {
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{
OS: baseTarget.OS,
Arch: baseTarget.Arch,
Distros: []buildpack.OSDistro{{Name: "a", Version: "2"}},
}, &log.Logger{Handler: memory.New()}), false)
})
when("/etc/os-release has information", func() {
it("must match", func() {
d := mockDetector{
contents: "this is just test contents really",
t: t,
HasFile: true,
}
h.AssertEq(
t,
platform.TargetSatisfiedForBuild(
&d,
baseTarget,
buildpack.TargetMetadata{
OS: baseTarget.OS,
Arch: baseTarget.Arch,
Distros: []buildpack.OSDistro{
{Name: "opensesame", Version: "3.14"},
},
},
&log.Logger{Handler: memory.New()},
), true)
})
})
})
})
when("has arch variant", func() {
baseTarget.ArchVariant = "some-arch-variant"
when("buildpack data", func() {
when("has arch variant", func() {
it("must match", func() {
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch, ArchVariant: "some-arch-variant"}, &log.Logger{Handler: memory.New()}), true)
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch, ArchVariant: "some-other-arch-variant"}, &log.Logger{Handler: memory.New()}), false)
})
})
when("missing arch variant", func() {
it("matches", func() {
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch}, &log.Logger{Handler: memory.New()}), true)
})
})
})
})
when("has distro information", func() {
baseTarget.Distro = &files.OSDistro{Name: "A", Version: "1"}
when("buildpack data", func() {
when("has distro information", func() {
it("must match", func() {
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch, Distros: []buildpack.OSDistro{{Name: "B", Version: "2"}, {Name: "A", Version: "1"}}}, &log.Logger{Handler: memory.New()}), true)
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch, Distros: []buildpack.OSDistro{{Name: "g", Version: "2"}, {Name: "B", Version: "2"}}}, &log.Logger{Handler: memory.New()}), false)
})
})
when("missing distro information", func() {
it("matches", func() {
h.AssertEq(t, platform.TargetSatisfiedForBuild(&d, baseTarget, buildpack.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch}, &log.Logger{Handler: memory.New()}), true)
})
})
})
})
})
})
})
when(".GetTargetOSFromFileSystem", func() {
it("populates appropriately", func() {
logr := &log.Logger{Handler: memory.New()}
tm := files.TargetMetadata{}
d := mockDetector{contents: "this is just test contents really",
t: t,
HasFile: true}
platform.GetTargetOSFromFileSystem(&d, &tm, logr)
h.AssertEq(t, "linux", tm.OS)
h.AssertEq(t, runtime.GOARCH, tm.Arch)
h.AssertEq(t, "opensesame", tm.Distro.Name)
h.AssertEq(t, "3.14", tm.Distro.Version)
})
it("doesn't populate if there's no file", func() {
logr := &log.Logger{Handler: memory.New()}
tm := files.TargetMetadata{}
d := mockDetector{contents: "in unit tests 2.0 the users will generate the content but we'll serve them ads",
t: t,
HasFile: false}
platform.GetTargetOSFromFileSystem(&d, &tm, logr)
h.AssertNil(t, tm.Distro)
})
it("doesn't populate if there's an error reading the file", func() {
logr := &log.Logger{Handler: memory.New()}
tm := files.TargetMetadata{}
d := mockDetector{contents: "contentment is the greatest wealth",
t: t,
HasFile: true,
ReadFileErr: fmt.Errorf("I'm sorry Dave, I don't even remember exactly what HAL says"),
}
platform.GetTargetOSFromFileSystem(&d, &tm, logr)
h.AssertNil(t, tm.Distro)
})
})
when(".EnvVarsFor", func() {
it("returns the right thing", func() {
tm := files.TargetMetadata{Arch: "pentium", ArchVariant: "mmx", ID: "my-id", OS: "linux", Distro: &files.OSDistro{Name: "nix", Version: "22.11"}}
d := &mockDetector{
contents: "this is just test contents really",
t: t,
HasFile: false,
}
observed := platform.EnvVarsFor(d, tm, &log.Logger{Handler: memory.New()})
h.AssertContains(t, observed, "CNB_TARGET_ARCH="+tm.Arch)
h.AssertContains(t, observed, "CNB_TARGET_ARCH_VARIANT="+tm.ArchVariant)
h.AssertContains(t, observed, "CNB_TARGET_DISTRO_NAME="+tm.Distro.Name)
h.AssertContains(t, observed, "CNB_TARGET_DISTRO_VERSION="+tm.Distro.Version)
h.AssertContains(t, observed, "CNB_TARGET_OS="+tm.OS)
h.AssertEq(t, len(observed), 5)
})
it("returns the right thing from /etc/os-release", func() {
d := &mockDetector{
contents: "this is just test contents really",
t: t,
HasFile: true,
}
tm := files.TargetMetadata{Arch: "pentium", ArchVariant: "mmx", ID: "my-id", OS: "linux", Distro: nil}
observed := platform.EnvVarsFor(d, tm, &log.Logger{Handler: memory.New()})
h.AssertContains(t, observed, "CNB_TARGET_ARCH="+tm.Arch)
h.AssertContains(t, observed, "CNB_TARGET_ARCH_VARIANT="+tm.ArchVariant)
h.AssertContains(t, observed, "CNB_TARGET_DISTRO_NAME=opensesame")
h.AssertContains(t, observed, "CNB_TARGET_DISTRO_VERSION=3.14")
h.AssertContains(t, observed, "CNB_TARGET_OS="+tm.OS)
h.AssertEq(t, len(observed), 5)
})
it("does not return the wrong thing", func() {
tm := files.TargetMetadata{Arch: "pentium", OS: "linux"}
d := &mockDetector{
contents: "this is just test contents really",
t: t,
HasFile: false,
}
observed := platform.EnvVarsFor(d, tm, &log.Logger{Handler: memory.New()})
h.AssertContains(t, observed, "CNB_TARGET_ARCH="+tm.Arch)
h.AssertContains(t, observed, "CNB_TARGET_OS="+tm.OS)
h.AssertEq(t, len(observed), 2)
})
when("optional vars are empty", func() {
it("omits them", func() {
tm := files.TargetMetadata{
// required
OS: "linux",
Arch: "pentium",
// optional
ArchVariant: "",
Distro: &files.OSDistro{Name: "nix", Version: ""},
ID: "",
}
d := &mockDetector{
contents: "this is just test contents really",
t: t,
HasFile: false,
}
observed := platform.EnvVarsFor(d, tm, &log.Logger{Handler: memory.New()})
h.AssertEq(t, len(observed), 3)
})
})
})
when(".TargetSatisfiedForRebase", func() {
var baseTarget files.TargetMetadata
when("orig image data", func() {
when("has os and arch", func() {
baseTarget = files.TargetMetadata{OS: "Win95", Arch: "Pentium"}
when("new image data", func() {
it("must match", func() {
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch}), true)
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{OS: "Win98", Arch: baseTarget.Arch}), false)
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{OS: baseTarget.OS, Arch: "Pentium MMX"}), false)
})
when("has extra information", func() {
it("matches", func() {
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch, ArchVariant: "MMX"}), true)
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{
OS: baseTarget.OS,
Arch: baseTarget.Arch,
Distro: &files.OSDistro{Name: "a", Version: "2"},
}), true)
})
})
})
when("has arch variant", func() {
baseTarget.ArchVariant = "some-arch-variant"
when("new image data", func() {
when("has arch variant", func() {
it("must match", func() {
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch, ArchVariant: "some-arch-variant"}), true)
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch, ArchVariant: "some-other-arch-variant"}), false)
})
})
when("missing arch variant", func() {
it("matches", func() {
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch}), true)
})
})
})
})
when("has distro information", func() {
baseTarget.Distro = &files.OSDistro{Name: "A", Version: "1"}
when("new image data", func() {
when("has distro information", func() {
it("must match", func() {
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{
OS: baseTarget.OS,
Arch: baseTarget.Arch,
Distro: &files.OSDistro{Name: "A", Version: "1"},
}), true)
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{
OS: baseTarget.OS,
Arch: baseTarget.Arch,
Distro: &files.OSDistro{Name: "B", Version: "2"},
}), false)
})
})
when("missing distro information", func() {
it("errors", func() {
h.AssertEq(t, platform.TargetSatisfiedForRebase(baseTarget, files.TargetMetadata{OS: baseTarget.OS, Arch: baseTarget.Arch}), false)
})
})
})
})
})
})
})
}
type mockDetector struct {
contents string
t *testing.T
HasFile bool
ReadFileErr error
}
func (d *mockDetector) HasSystemdFile() bool {
return d.HasFile
}
func (d *mockDetector) ReadSystemdFile() (string, error) {
return d.contents, d.ReadFileErr
}
func (d *mockDetector) GetInfo(osReleaseContents string) fsutil.OSInfo {
h.AssertEq(d.t, osReleaseContents, d.contents)
return fsutil.OSInfo{
Name: "opensesame",
Version: "3.14",
}
}
func (d *mockDetector) InfoOnce(_ llog.Logger) {}
func (d *mockDetector) StoredInfo() *fsutil.OSInfo {
return nil
}