github.com/paketoio/libpak@v1.3.1/layer_test.go (about)

     1  /*
     2   * Copyright 2018-2020 the original author or authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *      https://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package libpak_test
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"net/http"
    23  	"os"
    24  	"path/filepath"
    25  	"testing"
    26  
    27  	"github.com/buildpacks/libcnb"
    28  	. "github.com/onsi/gomega"
    29  	"github.com/onsi/gomega/ghttp"
    30  	"github.com/paketoio/libpak"
    31  	"github.com/sclevine/spec"
    32  )
    33  
    34  func testLayer(t *testing.T, context spec.G, it spec.S) {
    35  	var (
    36  		Expect = NewWithT(t).Expect
    37  
    38  		layer libcnb.Layer
    39  		path  string
    40  	)
    41  
    42  	it.Before(func() {
    43  		var err error
    44  
    45  		path, err = ioutil.TempDir("", "layer")
    46  		Expect(err).NotTo(HaveOccurred())
    47  	})
    48  
    49  	it.After(func() {
    50  		Expect(os.RemoveAll(path)).To(Succeed())
    51  	})
    52  
    53  	context("LayerContributor", func() {
    54  		var (
    55  			lc libpak.LayerContributor
    56  		)
    57  
    58  		it.Before(func() {
    59  			layer.Metadata = map[string]interface{}{}
    60  			layer.Path = path
    61  			lc.ExpectedMetadata = map[string]interface{}{
    62  				"alpha": "test-alpha",
    63  				"bravo": map[string]interface{}{
    64  					"bravo-1": "test-bravo-1",
    65  					"bravo-2": "test-bravo-2",
    66  				},
    67  			}
    68  		})
    69  
    70  		it("calls function with no existing metadata", func() {
    71  			var called bool
    72  
    73  			_, err := lc.Contribute(layer, func() (libcnb.Layer, error) {
    74  				called = true
    75  				return layer, nil
    76  			})
    77  			Expect(err).NotTo(HaveOccurred())
    78  
    79  			Expect(called).To(BeTrue())
    80  		})
    81  
    82  		it("calls function with non-matching metadata", func() {
    83  			layer.Metadata["alpha"] = "test-alpha"
    84  
    85  			var called bool
    86  
    87  			_, err := lc.Contribute(layer, func() (libcnb.Layer, error) {
    88  				called = true
    89  				return layer, nil
    90  			})
    91  			Expect(err).NotTo(HaveOccurred())
    92  
    93  			Expect(called).To(BeTrue())
    94  		})
    95  
    96  		it("does not call function with matching metadata", func() {
    97  			layer.Metadata = map[string]interface{}{
    98  				"alpha": "test-alpha",
    99  				"bravo": map[string]interface{}{
   100  					"bravo-1": "test-bravo-1",
   101  					"bravo-2": "test-bravo-2",
   102  				},
   103  			}
   104  
   105  			var called bool
   106  
   107  			_, err := lc.Contribute(layer, func() (libcnb.Layer, error) {
   108  				called = true
   109  				return layer, nil
   110  			})
   111  			Expect(err).NotTo(HaveOccurred())
   112  
   113  			Expect(called).To(BeFalse())
   114  		})
   115  
   116  		it("returns function error", func() {
   117  			_, err := lc.Contribute(layer, func() (libcnb.Layer, error) {
   118  				return libcnb.Layer{}, fmt.Errorf("test-error")
   119  			})
   120  			Expect(err).To(MatchError("test-error"))
   121  		})
   122  
   123  		it("adds expected metadata to layer", func() {
   124  			layer, err := lc.Contribute(layer, func() (libcnb.Layer, error) {
   125  				return layer, nil
   126  			})
   127  			Expect(err).NotTo(HaveOccurred())
   128  
   129  			Expect(layer.Metadata).To(Equal(map[string]interface{}{
   130  				"alpha": "test-alpha",
   131  				"bravo": map[string]interface{}{
   132  					"bravo-1": "test-bravo-1",
   133  					"bravo-2": "test-bravo-2",
   134  				},
   135  			}))
   136  		})
   137  	})
   138  
   139  	context("DependencyLayerContributor", func() {
   140  		var (
   141  			dependency libpak.BuildpackDependency
   142  			dlc        libpak.DependencyLayerContributor
   143  			server     *ghttp.Server
   144  		)
   145  
   146  		it.Before(func() {
   147  			RegisterTestingT(t)
   148  			server = ghttp.NewServer()
   149  
   150  			dependency = libpak.BuildpackDependency{
   151  				ID:      "test-id",
   152  				Name:    "test-name",
   153  				Version: "1.1.1",
   154  				URI:     fmt.Sprintf("%s/test-path", server.URL()),
   155  				SHA256:  "576dd8416de5619ea001d9662291d62444d1292a38e96956bc4651c01f14bca1",
   156  				Stacks:  []string{"test-stack"},
   157  				Licenses: []libpak.BuildpackDependencyLicense{
   158  					{
   159  						Type: "test-type",
   160  						URI:  "test-uri",
   161  					},
   162  				},
   163  			}
   164  
   165  			layer.Metadata = map[string]interface{}{}
   166  
   167  			dlc.LayerContributor.ExpectedMetadata = map[string]interface{}{
   168  				"id":       dependency.ID,
   169  				"name":     dependency.Name,
   170  				"version":  dependency.Version,
   171  				"uri":      dependency.URI,
   172  				"sha256":   dependency.SHA256,
   173  				"stacks":   dependency.Stacks,
   174  				"licenses": []map[string]interface{}{},
   175  			}
   176  			for _, l := range dependency.Licenses {
   177  				dlc.LayerContributor.ExpectedMetadata["licenses"] = append(
   178  					dlc.LayerContributor.ExpectedMetadata["licenses"].([]map[string]interface{}),
   179  					map[string]interface{}{
   180  						"type": l.Type,
   181  						"uri":  l.URI,
   182  					})
   183  			}
   184  
   185  			layer.Path = path
   186  			dlc.Dependency = dependency
   187  			dlc.DependencyCache.CachePath = path
   188  			dlc.DependencyCache.DownloadPath = path
   189  		})
   190  
   191  		it.After(func() {
   192  			server.Close()
   193  		})
   194  
   195  		it("calls function with no existing metadata", func() {
   196  			server.AppendHandlers(ghttp.RespondWith(http.StatusOK, "test-fixture"))
   197  
   198  			var called bool
   199  
   200  			_, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   201  				defer artifact.Close()
   202  
   203  				called = true
   204  				return layer, nil
   205  			})
   206  			Expect(err).NotTo(HaveOccurred())
   207  
   208  			Expect(called).To(BeTrue())
   209  		})
   210  
   211  		it("calls function with non-matching metadata", func() {
   212  			layer.Metadata["alpha"] = "test-alpha"
   213  
   214  			server.AppendHandlers(ghttp.RespondWith(http.StatusOK, "test-fixture"))
   215  
   216  			var called bool
   217  
   218  			_, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   219  				defer artifact.Close()
   220  
   221  				called = true
   222  				return layer, nil
   223  			})
   224  			Expect(err).NotTo(HaveOccurred())
   225  
   226  			Expect(called).To(BeTrue())
   227  		})
   228  
   229  		it("does not call function with matching metadata", func() {
   230  			layer.Metadata = map[string]interface{}{
   231  				"id":      dependency.ID,
   232  				"name":    dependency.Name,
   233  				"version": dependency.Version,
   234  				"uri":     dependency.URI,
   235  				"sha256":  dependency.SHA256,
   236  				"stacks":  dependency.Stacks,
   237  				"licenses": []map[string]interface{}{
   238  					{
   239  						"type": dependency.Licenses[0].Type,
   240  						"uri":  dependency.Licenses[0].URI,
   241  					},
   242  				},
   243  			}
   244  
   245  			var called bool
   246  
   247  			_, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   248  				defer artifact.Close()
   249  
   250  				called = true
   251  				return layer, nil
   252  			})
   253  			Expect(err).NotTo(HaveOccurred())
   254  
   255  			Expect(called).To(BeFalse())
   256  		})
   257  
   258  		it("returns function error", func() {
   259  			server.AppendHandlers(ghttp.RespondWith(http.StatusOK, "test-fixture"))
   260  
   261  			_, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   262  				defer artifact.Close()
   263  
   264  				return libcnb.Layer{}, fmt.Errorf("test-error")
   265  			})
   266  			Expect(err).To(MatchError("test-error"))
   267  		})
   268  
   269  		it("adds expected metadata to layer", func() {
   270  			server.AppendHandlers(ghttp.RespondWith(http.StatusOK, "test-fixture"))
   271  
   272  			layer, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   273  				defer artifact.Close()
   274  				return layer, nil
   275  			})
   276  			Expect(err).NotTo(HaveOccurred())
   277  
   278  			Expect(layer.Metadata).To(Equal(map[string]interface{}{
   279  				"id":      dependency.ID,
   280  				"name":    dependency.Name,
   281  				"version": dependency.Version,
   282  				"uri":     dependency.URI,
   283  				"sha256":  dependency.SHA256,
   284  				"stacks":  dependency.Stacks,
   285  				"licenses": []map[string]interface{}{
   286  					{
   287  						"type": dependency.Licenses[0].Type,
   288  						"uri":  dependency.Licenses[0].URI,
   289  					},
   290  				},
   291  			}))
   292  		})
   293  
   294  		it("contributes to buildpack plan", func() {
   295  			plan := libcnb.BuildpackPlan{}
   296  
   297  			_ = libpak.NewDependencyLayerContributor(dependency, libpak.DependencyCache{}, &plan)
   298  
   299  			Expect(plan.Entries).To(ContainElement(libcnb.BuildpackPlanEntry{
   300  				Name:    dependency.ID,
   301  				Version: dependency.Version,
   302  				Metadata: map[string]interface{}{
   303  					"name":     dependency.Name,
   304  					"uri":      dependency.URI,
   305  					"sha256":   dependency.SHA256,
   306  					"stacks":   dependency.Stacks,
   307  					"licenses": dependency.Licenses,
   308  				},
   309  			}))
   310  		})
   311  	})
   312  
   313  	context("HelperLayerContributor", func() {
   314  		var (
   315  			helper *os.File
   316  			hlc    libpak.HelperLayerContributor
   317  			info   libcnb.BuildpackInfo
   318  		)
   319  
   320  		it.Before(func() {
   321  			var err error
   322  			helper, err = ioutil.TempFile("", "layer")
   323  			Expect(err).NotTo(HaveOccurred())
   324  			Expect(helper.Close()).To(Succeed())
   325  
   326  			info = libcnb.BuildpackInfo{
   327  				ID:      "test-id",
   328  				Name:    "test-name",
   329  				Version: "test-version",
   330  			}
   331  
   332  			layer.Metadata = map[string]interface{}{}
   333  			layer.Path = path
   334  
   335  			hlc.LayerContributor.ExpectedMetadata = map[string]interface{}{
   336  				"id":        info.ID,
   337  				"name":      info.Name,
   338  				"version":   info.Version,
   339  				"clear-env": info.ClearEnvironment,
   340  			}
   341  			hlc.Path = helper.Name()
   342  		})
   343  
   344  		it("calls function with no existing metadata", func() {
   345  			var called bool
   346  
   347  			_, err := hlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   348  				defer artifact.Close()
   349  
   350  				called = true
   351  				return layer, nil
   352  			})
   353  			Expect(err).NotTo(HaveOccurred())
   354  
   355  			Expect(called).To(BeTrue())
   356  		})
   357  
   358  		it("calls function with non-matching metadata", func() {
   359  			layer.Metadata["alpha"] = "other-alpha"
   360  
   361  			var called bool
   362  
   363  			_, err := hlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   364  				defer artifact.Close()
   365  
   366  				called = true
   367  				return layer, nil
   368  			})
   369  			Expect(err).NotTo(HaveOccurred())
   370  
   371  			Expect(called).To(BeTrue())
   372  		})
   373  
   374  		it("does not call function with matching metadata", func() {
   375  			layer.Metadata = map[string]interface{}{
   376  				"id":        info.ID,
   377  				"name":      info.Name,
   378  				"version":   info.Version,
   379  				"clear-env": info.ClearEnvironment,
   380  			}
   381  
   382  			var called bool
   383  
   384  			_, err := hlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   385  				defer artifact.Close()
   386  
   387  				called = true
   388  				return layer, nil
   389  			})
   390  			Expect(err).NotTo(HaveOccurred())
   391  
   392  			Expect(called).To(BeFalse())
   393  		})
   394  
   395  		it("returns function error", func() {
   396  			_, err := hlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   397  				defer artifact.Close()
   398  
   399  				return libcnb.Layer{}, fmt.Errorf("test-error")
   400  			})
   401  			Expect(err).To(MatchError("test-error"))
   402  		})
   403  
   404  		it("adds expected metadata to layer", func() {
   405  			layer, err := hlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) {
   406  				defer artifact.Close()
   407  				return layer, nil
   408  			})
   409  			Expect(err).NotTo(HaveOccurred())
   410  
   411  			Expect(layer.Metadata).To(Equal(map[string]interface{}{
   412  				"id":        info.ID,
   413  				"name":      info.Name,
   414  				"version":   info.Version,
   415  				"clear-env": info.ClearEnvironment,
   416  			}))
   417  		})
   418  
   419  		it("contributes to buildpack plan", func() {
   420  			plan := libcnb.BuildpackPlan{}
   421  
   422  			_ = libpak.NewHelperLayerContributor(helper.Name(), "test-name", info, &plan)
   423  
   424  			Expect(plan.Entries).To(ContainElement(libcnb.BuildpackPlanEntry{
   425  				Name:    filepath.Base(helper.Name()),
   426  				Version: info.Version,
   427  				Metadata: map[string]interface{}{
   428  					"buildpack-id":      info.ID,
   429  					"buildpack-version": info.Version,
   430  				},
   431  			}))
   432  		})
   433  	})
   434  }