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  }