github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/dist/buildpack_descriptor_test.go (about) 1 package dist_test 2 3 import ( 4 "testing" 5 6 "github.com/buildpacks/lifecycle/api" 7 "github.com/heroku/color" 8 "github.com/sclevine/spec" 9 "github.com/sclevine/spec/report" 10 11 "github.com/buildpacks/pack/pkg/buildpack" 12 "github.com/buildpacks/pack/pkg/dist" 13 h "github.com/buildpacks/pack/testhelpers" 14 ) 15 16 func TestBuildpackDescriptor(t *testing.T) { 17 color.Disable(true) 18 defer color.Disable(false) 19 spec.Run(t, "testBuildpackDescriptor", testBuildpackDescriptor, spec.Parallel(), spec.Report(report.Terminal{})) 20 } 21 22 func testBuildpackDescriptor(t *testing.T, when spec.G, it spec.S) { 23 when("#EscapedID", func() { 24 it("returns escaped ID", func() { 25 bpDesc := dist.BuildpackDescriptor{ 26 WithInfo: dist.ModuleInfo{ID: "some/id"}, 27 } 28 h.AssertEq(t, bpDesc.EscapedID(), "some_id") 29 }) 30 }) 31 32 when("#EnsureStackSupport", func() { 33 when("not validating against run image mixins", func() { 34 it("ignores run-only mixins", func() { 35 bp := dist.BuildpackDescriptor{ 36 WithInfo: dist.ModuleInfo{ 37 ID: "some.buildpack.id", 38 Version: "some.buildpack.version", 39 }, 40 WithStacks: []dist.Stack{{ 41 ID: "some.stack.id", 42 Mixins: []string{"mixinA", "build:mixinB", "run:mixinD"}, 43 }}, 44 } 45 46 providedMixins := []string{"mixinA", "build:mixinB", "mixinC"} 47 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", providedMixins, false)) 48 }) 49 50 it("works with wildcard stack", func() { 51 bp := dist.BuildpackDescriptor{ 52 WithInfo: dist.ModuleInfo{ 53 ID: "some.buildpack.id", 54 Version: "some.buildpack.version", 55 }, 56 WithStacks: []dist.Stack{{ 57 ID: "*", 58 Mixins: []string{"mixinA", "build:mixinB", "run:mixinD"}, 59 }}, 60 } 61 62 providedMixins := []string{"mixinA", "build:mixinB", "mixinC"} 63 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", providedMixins, false)) 64 }) 65 66 it("returns an error with any missing (and non-ignored) mixins", func() { 67 bp := dist.BuildpackDescriptor{ 68 WithInfo: dist.ModuleInfo{ 69 ID: "some.buildpack.id", 70 Version: "some.buildpack.version", 71 }, 72 WithStacks: []dist.Stack{{ 73 ID: "some.stack.id", 74 Mixins: []string{"mixinX", "mixinY", "run:mixinZ"}, 75 }}, 76 } 77 78 providedMixins := []string{"mixinA", "mixinB"} 79 err := bp.EnsureStackSupport("some.stack.id", providedMixins, false) 80 81 h.AssertError(t, err, "buildpack 'some.buildpack.id@some.buildpack.version' requires missing mixin(s): mixinX, mixinY") 82 }) 83 }) 84 85 when("validating against run image mixins", func() { 86 it("requires run-only mixins", func() { 87 bp := dist.BuildpackDescriptor{ 88 WithInfo: dist.ModuleInfo{ 89 ID: "some.buildpack.id", 90 Version: "some.buildpack.version", 91 }, 92 WithStacks: []dist.Stack{{ 93 ID: "some.stack.id", 94 Mixins: []string{"mixinA", "build:mixinB", "run:mixinD"}, 95 }}, 96 } 97 98 providedMixins := []string{"mixinA", "build:mixinB", "mixinC", "run:mixinD"} 99 100 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", providedMixins, true)) 101 }) 102 103 it("returns an error with any missing mixins", func() { 104 bp := dist.BuildpackDescriptor{ 105 WithInfo: dist.ModuleInfo{ 106 ID: "some.buildpack.id", 107 Version: "some.buildpack.version", 108 }, 109 WithStacks: []dist.Stack{{ 110 ID: "some.stack.id", 111 Mixins: []string{"mixinX", "mixinY", "run:mixinZ"}, 112 }}, 113 } 114 115 providedMixins := []string{"mixinA", "mixinB"} 116 117 err := bp.EnsureStackSupport("some.stack.id", providedMixins, true) 118 119 h.AssertError(t, err, "buildpack 'some.buildpack.id@some.buildpack.version' requires missing mixin(s): mixinX, mixinY, run:mixinZ") 120 }) 121 }) 122 123 it("returns an error when buildpack does not support stack", func() { 124 bp := dist.BuildpackDescriptor{ 125 WithInfo: dist.ModuleInfo{ 126 ID: "some.buildpack.id", 127 Version: "some.buildpack.version", 128 }, 129 WithStacks: []dist.Stack{{ 130 ID: "some.stack.id", 131 Mixins: []string{"mixinX", "mixinY"}, 132 }}, 133 } 134 135 err := bp.EnsureStackSupport("some.nonexistent.stack.id", []string{"mixinA"}, true) 136 137 h.AssertError(t, err, "buildpack 'some.buildpack.id@some.buildpack.version' does not support stack 'some.nonexistent.stack.id") 138 }) 139 140 it("skips validating order buildpack", func() { 141 bp := dist.BuildpackDescriptor{ 142 WithInfo: dist.ModuleInfo{ 143 ID: "some.buildpack.id", 144 Version: "some.buildpack.version", 145 }, 146 WithStacks: []dist.Stack{}, 147 } 148 149 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", []string{"mixinA"}, true)) 150 }) 151 }) 152 153 when("validating against run image target", func() { 154 it("succeeds with no distribution", func() { 155 bp := dist.BuildpackDescriptor{ 156 WithInfo: dist.ModuleInfo{ 157 ID: "some.buildpack.id", 158 Version: "some.buildpack.version", 159 }, 160 WithTargets: []dist.Target{{ 161 OS: "fake-os", 162 Arch: "fake-arch", 163 }}, 164 } 165 166 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", []string{}, true)) 167 h.AssertNil(t, bp.EnsureTargetSupport("fake-os", "fake-arch", "fake-distro", "0.0")) 168 }) 169 170 it("succeeds with no target and bin/build.exe", func() { 171 bp := dist.BuildpackDescriptor{ 172 WithInfo: dist.ModuleInfo{ 173 ID: "some.buildpack.id", 174 Version: "some.buildpack.version", 175 }, 176 WithWindowsBuild: true, 177 } 178 179 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", []string{}, true)) 180 h.AssertNil(t, bp.EnsureTargetSupport("windows", "amd64", "fake-distro", "0.0")) 181 }) 182 183 it("succeeds with no target and bin/build", func() { 184 bp := dist.BuildpackDescriptor{ 185 WithInfo: dist.ModuleInfo{ 186 ID: "some.buildpack.id", 187 Version: "some.buildpack.version", 188 }, 189 WithLinuxBuild: true, 190 } 191 192 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", []string{}, true)) 193 h.AssertNil(t, bp.EnsureTargetSupport("linux", "amd64", "fake-distro", "0.0")) 194 }) 195 196 it("returns an error when no match", func() { 197 bp := dist.BuildpackDescriptor{ 198 WithInfo: dist.ModuleInfo{ 199 ID: "some.buildpack.id", 200 Version: "some.buildpack.version", 201 }, 202 WithTargets: []dist.Target{{ 203 OS: "fake-os", 204 Arch: "fake-arch", 205 }}, 206 } 207 208 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", []string{}, true)) 209 h.AssertError(t, bp.EnsureTargetSupport("some-other-os", "fake-arch", "fake-distro", "0.0"), 210 `unable to satisfy target os/arch constraints; build image: {"os":"some-other-os","arch":"fake-arch","distribution":{"name":"fake-distro","version":"0.0"}}, buildpack 'some.buildpack.id@some.buildpack.version': [{"os":"fake-os","arch":"fake-arch"}]`) 211 }) 212 213 it("succeeds with distribution", func() { 214 bp := dist.BuildpackDescriptor{ 215 WithInfo: dist.ModuleInfo{ 216 ID: "some.buildpack.id", 217 Version: "some.buildpack.version", 218 }, 219 WithTargets: []dist.Target{{ 220 OS: "fake-os", 221 Arch: "fake-arch", 222 Distributions: []dist.Distribution{ 223 { 224 Name: "fake-distro", 225 Version: "0.1", 226 }, 227 { 228 Name: "another-distro", 229 Version: "0.22", 230 }, 231 }, 232 }}, 233 } 234 235 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", []string{}, true)) 236 h.AssertNil(t, bp.EnsureTargetSupport("fake-os", "fake-arch", "fake-distro", "0.1")) 237 }) 238 239 it("returns an error when no distribution matches", func() { 240 bp := dist.BuildpackDescriptor{ 241 WithInfo: dist.ModuleInfo{ 242 ID: "some.buildpack.id", 243 Version: "some.buildpack.version", 244 }, 245 WithTargets: []dist.Target{{ 246 OS: "fake-os", 247 Arch: "fake-arch", 248 Distributions: []dist.Distribution{ 249 { 250 Name: "fake-distro", 251 Version: "0.1", 252 }, 253 { 254 Name: "another-distro", 255 Version: "0.22", 256 }, 257 }, 258 }}, 259 } 260 261 h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", []string{}, true)) 262 h.AssertError(t, bp.EnsureTargetSupport("some-other-os", "fake-arch", "fake-distro", "0.0"), 263 `unable to satisfy target os/arch constraints; build image: {"os":"some-other-os","arch":"fake-arch","distribution":{"name":"fake-distro","version":"0.0"}}, buildpack 'some.buildpack.id@some.buildpack.version': [{"os":"fake-os","arch":"fake-arch","distros":[{"name":"fake-distro","version":"0.1"},{"name":"another-distro","version":"0.22"}]}]`) 264 }) 265 266 it("succeeds with missing arch", func() { 267 bp := dist.BuildpackDescriptor{ 268 WithInfo: dist.ModuleInfo{ 269 ID: "some.buildpack.id", 270 Version: "some.buildpack.version", 271 }, 272 WithTargets: []dist.Target{{ 273 OS: "fake-os", 274 }}, 275 } 276 277 h.AssertNil(t, bp.EnsureTargetSupport("fake-os", "fake-arch", "fake-distro", "0.1")) 278 }) 279 }) 280 281 when("#Kind", func() { 282 it("returns 'buildpack'", func() { 283 bpDesc := dist.BuildpackDescriptor{} 284 h.AssertEq(t, bpDesc.Kind(), buildpack.KindBuildpack) 285 }) 286 }) 287 288 when("#API", func() { 289 it("returns the api", func() { 290 bpDesc := dist.BuildpackDescriptor{ 291 WithAPI: api.MustParse("0.99"), 292 } 293 h.AssertEq(t, bpDesc.API().String(), "0.99") 294 }) 295 }) 296 297 when("#Info", func() { 298 it("returns the module info", func() { 299 info := dist.ModuleInfo{ 300 ID: "some-id", 301 Name: "some-name", 302 Version: "some-version", 303 } 304 bpDesc := dist.BuildpackDescriptor{ 305 WithInfo: info, 306 } 307 h.AssertEq(t, bpDesc.Info(), info) 308 }) 309 }) 310 311 when("#Order", func() { 312 it("returns the order", func() { 313 order := dist.Order{ 314 dist.OrderEntry{Group: []dist.ModuleRef{ 315 {ModuleInfo: dist.ModuleInfo{ 316 ID: "some-id", Name: "some-name", Version: "some-version", 317 }}, 318 }}, 319 } 320 bpDesc := dist.BuildpackDescriptor{ 321 WithOrder: order, 322 } 323 h.AssertEq(t, bpDesc.Order(), order) 324 }) 325 }) 326 327 when("#Stacks", func() { 328 it("returns the stacks", func() { 329 stacks := []dist.Stack{ 330 {ID: "some-id", Mixins: []string{"some-mixin"}}, 331 } 332 bpDesc := dist.BuildpackDescriptor{ 333 WithStacks: stacks, 334 } 335 h.AssertEq(t, bpDesc.Stacks(), stacks) 336 }) 337 }) 338 }