1 package layer_test
2
3 import (
4 "bytes"
5 "crypto/rand"
6 "io"
7 "testing"
8 "time"
9
10 v1 "github.com/google/go-containerregistry/pkg/v1"
11 "github.com/google/go-containerregistry/pkg/v1/mutate"
12 "github.com/google/go-containerregistry/pkg/v1/partial"
13 "github.com/google/go-containerregistry/pkg/v1/static"
14
15 wh "edge-infra.dev/pkg/f8n/warehouse"
16 "edge-infra.dev/pkg/f8n/warehouse/capability"
17 "edge-infra.dev/pkg/f8n/warehouse/cluster"
18 "edge-infra.dev/pkg/f8n/warehouse/oci/layer"
19 "edge-infra.dev/pkg/f8n/warehouse/pallet"
20 )
21
22 func TestLayer_Descriptor(t *testing.T) {
23 v1Layer := testLayer(t, layer.Runtime)
24 d, err := partial.Descriptor(v1Layer)
25 if err != nil {
26 t.Error(err)
27 }
28 annos := v1Layer.Annotations()
29
30 for k, v := range d.Annotations {
31 if annos[k] != v {
32 t.Errorf("annotation %s did not match between Descriptor and Layer. "+
33 "Expected %s and got %s", k, v, annos[k])
34 }
35 }
36 }
37
38 func TestType(t *testing.T) {
39 l := testLayer(t, layer.Runtime)
40 if l.Type() != layer.Runtime {
41 t.Errorf("incorrect layer type: expected %s, got %s",
42 layer.Runtime, l.Type())
43 }
44 }
45
46 func TestForCapability(t *testing.T) {
47 c := capability.Capability("linkerd")
48 annos := testLayer(t, layer.Runtime, layer.ForCapability(c)).Annotations()
49
50 if annos[wh.AnnotationLayerRuntimeCapability] != string(c) {
51 t.Errorf("annotation %s has unexpected value: wanted %s, got %s",
52 wh.AnnotationLayerRuntimeCapability,
53 c,
54 annos[wh.AnnotationLayerRuntimeCapability],
55 )
56 }
57 }
58
59 func TestKey(t *testing.T) {
60 tcs := map[string]struct {
61 layer layer.Layer
62 expected string
63 }{
64 "base runtime layer": {testLayer(t, layer.Runtime), string(layer.Runtime)},
65 "infra layer": {testLayer(t, layer.Infra), string(layer.Infra)},
66 "config layer": {testLayer(t, layer.Config), string(layer.Config)},
67 "runtime capability layer": {
68 testLayer(t, layer.Runtime, layer.ForCapability(capability.Capability("prometheus"))),
69 "prometheus",
70 },
71 }
72
73 for name, tc := range tcs {
74 t.Run(name, func(t *testing.T) {
75 if tc.layer.Key() != tc.expected {
76 t.Errorf("incorrect layer key. expected %s, got %s",
77 tc.expected, tc.layer.Key())
78 }
79 })
80 }
81 }
82
83 func TestSort(t *testing.T) {
84 tcs := []struct {
85 input []string
86 expected []string
87 }{
88 {
89 []string{"runtime", "infrastructure", "prometheus", "linkerd"},
90 []string{"runtime", "infrastructure", "prometheus", "linkerd"},
91 },
92 {
93 []string{"infrastructure", "prometheus", "runtime"},
94 []string{"runtime", "infrastructure", "prometheus"},
95 },
96 {
97 []string{"prometheus", "runtime", "linkerd", "infrastructure"},
98 []string{"runtime", "infrastructure", "prometheus", "linkerd"},
99 },
100 {
101 []string{"prometheus", "linkerd", "runtime", "infrastructure", "gatekeeper"},
102 []string{"runtime", "infrastructure", "prometheus", "linkerd", "gatekeeper"},
103 },
104 }
105
106 for _, tc := range tcs {
107 layers := make([]layer.Layer, 0, len(tc.input))
108 for _, key := range tc.input {
109 lt := layer.Runtime
110 opts := []layer.Option{}
111 if key == layer.Infra.String() {
112 lt = layer.Infra
113 }
114 if !layer.IsType(key) {
115 opts = append(opts, layer.ForCapability(capability.Capability(key)))
116 }
117 layers = append(layers, testLayer(t, lt, opts...))
118 }
119
120 layer.Sort(layers)
121
122 for i, l := range layers {
123 if l.Key() != tc.expected[i] {
124 t.Errorf("incorrect order, got %s for element %d instead of %s",
125 l.Key(), i, tc.expected[i])
126 }
127 }
128 }
129 }
130
131 func TestFromImage(t *testing.T) {
132 t.Run("drops non-warehouse layers", func(t *testing.T) {
133 img, err := pallet.Image(pallet.Options{
134 ClusterProviders: []cluster.Provider{cluster.Generic},
135 Metadata: pallet.Metadata{
136 Team: "@ncrvoyix-swt-retail/sorry-suckers",
137 Name: "includes-non-warehouse-layers",
138 BuildInfo: pallet.BuildInfo{
139 Source: "https://github.com/ncrvoyix-swt-retail/foo",
140 Version: "0.0.1",
141 Revision: "d34db33f",
142 Created: time.Now().Format(time.RFC3339),
143 },
144 Vendor: "NCR",
145 },
146 }, testLayer(t, layer.Infra), testLayer(t, layer.Runtime))
147 if err != nil {
148 t.Fatal("failed to create test image", err)
149 }
150
151 i, err := mutate.AppendLayers(img.Unwrap().(v1.Image), staticLayer(t))
152 if err != nil {
153 t.Fatal("failed to create test image", err)
154 }
155
156 layers, err := layer.FromImage(i)
157 if err != nil {
158 t.Error("unexpected error", err)
159 }
160 if len(layers) != 2 {
161 t.Errorf("unexpected number of layers %d, expected %d", len(layers), 2)
162 }
163 })
164 }
165
166 func testLayer(t *testing.T, ty layer.Type, o ...layer.Option) layer.Layer {
167 c, err := randomContents(256)
168 if err != nil {
169 t.Fatal("failed to create layer content", err)
170 }
171 l, err := layer.New(ty, c, o...)
172 if err != nil {
173 t.Fatal("failed to instantiate layer", err)
174 }
175
176 return l
177 }
178
179 func staticLayer(t *testing.T) v1.Layer {
180 c, err := randomContents(256)
181 if err != nil {
182 t.Fatal("failed to create layer content", err)
183 }
184 return static.NewLayer(c, layer.YAML)
185 }
186
187 func randomContents(byteSize int64) ([]byte, error) {
188 var b bytes.Buffer
189 _, err := io.CopyN(&b, rand.Reader, byteSize)
190 if err != nil {
191 return nil, err
192 }
193
194 return b.Bytes(), nil
195 }
196
View as plain text