package layer_test import ( "bytes" "crypto/rand" "io" "testing" "time" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/partial" "github.com/google/go-containerregistry/pkg/v1/static" wh "edge-infra.dev/pkg/f8n/warehouse" "edge-infra.dev/pkg/f8n/warehouse/capability" "edge-infra.dev/pkg/f8n/warehouse/cluster" "edge-infra.dev/pkg/f8n/warehouse/oci/layer" "edge-infra.dev/pkg/f8n/warehouse/pallet" ) func TestLayer_Descriptor(t *testing.T) { v1Layer := testLayer(t, layer.Runtime) d, err := partial.Descriptor(v1Layer) if err != nil { t.Error(err) } annos := v1Layer.Annotations() for k, v := range d.Annotations { if annos[k] != v { t.Errorf("annotation %s did not match between Descriptor and Layer. "+ "Expected %s and got %s", k, v, annos[k]) } } } func TestType(t *testing.T) { l := testLayer(t, layer.Runtime) if l.Type() != layer.Runtime { t.Errorf("incorrect layer type: expected %s, got %s", layer.Runtime, l.Type()) } } func TestForCapability(t *testing.T) { c := capability.Capability("linkerd") annos := testLayer(t, layer.Runtime, layer.ForCapability(c)).Annotations() if annos[wh.AnnotationLayerRuntimeCapability] != string(c) { t.Errorf("annotation %s has unexpected value: wanted %s, got %s", wh.AnnotationLayerRuntimeCapability, c, annos[wh.AnnotationLayerRuntimeCapability], ) } } func TestKey(t *testing.T) { tcs := map[string]struct { layer layer.Layer expected string }{ "base runtime layer": {testLayer(t, layer.Runtime), string(layer.Runtime)}, "infra layer": {testLayer(t, layer.Infra), string(layer.Infra)}, "config layer": {testLayer(t, layer.Config), string(layer.Config)}, "runtime capability layer": { testLayer(t, layer.Runtime, layer.ForCapability(capability.Capability("prometheus"))), "prometheus", }, } for name, tc := range tcs { t.Run(name, func(t *testing.T) { if tc.layer.Key() != tc.expected { t.Errorf("incorrect layer key. expected %s, got %s", tc.expected, tc.layer.Key()) } }) } } func TestSort(t *testing.T) { tcs := []struct { input []string expected []string }{ { []string{"runtime", "infrastructure", "prometheus", "linkerd"}, []string{"runtime", "infrastructure", "prometheus", "linkerd"}, }, { []string{"infrastructure", "prometheus", "runtime"}, []string{"runtime", "infrastructure", "prometheus"}, }, { []string{"prometheus", "runtime", "linkerd", "infrastructure"}, []string{"runtime", "infrastructure", "prometheus", "linkerd"}, }, { []string{"prometheus", "linkerd", "runtime", "infrastructure", "gatekeeper"}, []string{"runtime", "infrastructure", "prometheus", "linkerd", "gatekeeper"}, }, } for _, tc := range tcs { layers := make([]layer.Layer, 0, len(tc.input)) for _, key := range tc.input { lt := layer.Runtime opts := []layer.Option{} if key == layer.Infra.String() { lt = layer.Infra } if !layer.IsType(key) { opts = append(opts, layer.ForCapability(capability.Capability(key))) } layers = append(layers, testLayer(t, lt, opts...)) } layer.Sort(layers) for i, l := range layers { if l.Key() != tc.expected[i] { t.Errorf("incorrect order, got %s for element %d instead of %s", l.Key(), i, tc.expected[i]) } } } } func TestFromImage(t *testing.T) { t.Run("drops non-warehouse layers", func(t *testing.T) { img, err := pallet.Image(pallet.Options{ ClusterProviders: []cluster.Provider{cluster.Generic}, Metadata: pallet.Metadata{ Team: "@ncrvoyix-swt-retail/sorry-suckers", Name: "includes-non-warehouse-layers", BuildInfo: pallet.BuildInfo{ Source: "https://github.com/ncrvoyix-swt-retail/foo", Version: "0.0.1", Revision: "d34db33f", Created: time.Now().Format(time.RFC3339), }, Vendor: "NCR", }, }, testLayer(t, layer.Infra), testLayer(t, layer.Runtime)) if err != nil { t.Fatal("failed to create test image", err) } i, err := mutate.AppendLayers(img.Unwrap().(v1.Image), staticLayer(t)) if err != nil { t.Fatal("failed to create test image", err) } layers, err := layer.FromImage(i) if err != nil { t.Error("unexpected error", err) } if len(layers) != 2 { t.Errorf("unexpected number of layers %d, expected %d", len(layers), 2) } }) } func testLayer(t *testing.T, ty layer.Type, o ...layer.Option) layer.Layer { c, err := randomContents(256) if err != nil { t.Fatal("failed to create layer content", err) } l, err := layer.New(ty, c, o...) if err != nil { t.Fatal("failed to instantiate layer", err) } return l } func staticLayer(t *testing.T) v1.Layer { c, err := randomContents(256) if err != nil { t.Fatal("failed to create layer content", err) } return static.NewLayer(c, layer.YAML) } func randomContents(byteSize int64) ([]byte, error) { var b bytes.Buffer _, err := io.CopyN(&b, rand.Reader, byteSize) if err != nil { return nil, err } return b.Bytes(), nil }