Skip to content

Commit 237f9d4

Browse files
Add support for layers in fake client testing and unit tests
1 parent 7d39593 commit 237f9d4

File tree

2 files changed

+151
-7
lines changed

2 files changed

+151
-7
lines changed

pkg/dockerregistry/server/repository_test.go

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ func TestRepositoryBlobStat(t *testing.T) {
9999
stat string
100100
images []imageapiv1.Image
101101
imageStreams []imageapiv1.ImageStream
102+
imageStreamLayers []imageapiv1.ImageStreamLayers
102103
skipAuth bool
103104
deferredErrors deferredErrors
104105
expectedDescriptor distribution.Descriptor
@@ -141,7 +142,7 @@ func TestRepositoryBlobStat(t *testing.T) {
141142
},
142143

143144
{
144-
name: "blob referenced only by unmanaged image with pullthrough on",
145+
name: "blob referenced only by unmanaged image with pullthrough on and server doesn't support layers subresource",
145146
stat: "nm/unmanaged@" + testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[1].Name,
146147
images: []imageapiv1.Image{*testImages["nm/unmanaged:missing-layer-links"][0]},
147148
imageStreams: []imageapiv1.ImageStream{
@@ -168,6 +169,87 @@ func TestRepositoryBlobStat(t *testing.T) {
168169
expectedActions: []clientAction{{"get", "imagestreams/layers"}, {"get", "imagestreams"}, {"get", "images"}},
169170
},
170171

172+
{
173+
name: "blob not referenced and server supports layers subresource",
174+
stat: "nm/unmanaged@" + testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[1].Name,
175+
imageStreams: []imageapiv1.ImageStream{
176+
{
177+
ObjectMeta: metav1.ObjectMeta{
178+
Namespace: "nm",
179+
Name: "unmanaged",
180+
},
181+
Status: imageapiv1.ImageStreamStatus{
182+
Tags: []imageapiv1.NamedTagEventList{
183+
{
184+
Tag: "latest",
185+
Items: []imageapiv1.TagEvent{
186+
{
187+
Image: testImages["nm/unmanaged:missing-layer-links"][0].Name,
188+
},
189+
},
190+
},
191+
},
192+
},
193+
},
194+
},
195+
imageStreamLayers: []imageapiv1.ImageStreamLayers{
196+
{
197+
ObjectMeta: metav1.ObjectMeta{
198+
Namespace: "nm",
199+
Name: "unmanaged",
200+
},
201+
Blobs: map[string]imageapiv1.ImageLayerData{
202+
testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[0].Name: {
203+
LayerSize: &testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[0].LayerSize,
204+
MediaType: testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[0].MediaType,
205+
},
206+
},
207+
Images: map[string]imageapiv1.ImageBlobReferences{
208+
testImages["nm/unmanaged:missing-layer-links"][0].Name: {
209+
Layers: []string{
210+
testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[0].Name,
211+
},
212+
},
213+
},
214+
},
215+
},
216+
expectedError: distribution.ErrBlobUnknown,
217+
expectedActions: []clientAction{{"get", "imagestreams/layers"}, {"get", "imagestreams"}, {"get", "imagestreams/secrets"}},
218+
},
219+
220+
{
221+
name: "blob referenced only by unmanaged image with pullthrough on and server supports layers subresource",
222+
stat: "nm/unmanaged@" + testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[1].Name,
223+
imageStreamLayers: []imageapiv1.ImageStreamLayers{
224+
{
225+
ObjectMeta: metav1.ObjectMeta{
226+
Namespace: "nm",
227+
Name: "unmanaged",
228+
},
229+
Blobs: map[string]imageapiv1.ImageLayerData{
230+
testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[0].Name: {
231+
LayerSize: &testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[0].LayerSize,
232+
MediaType: testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[0].MediaType,
233+
},
234+
testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[1].Name: {
235+
LayerSize: &testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[1].LayerSize,
236+
MediaType: testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[1].MediaType,
237+
},
238+
},
239+
Images: map[string]imageapiv1.ImageBlobReferences{
240+
testImages["nm/unmanaged:missing-layer-links"][0].Name: {
241+
Layers: []string{
242+
testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[0].Name,
243+
testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[1].Name,
244+
},
245+
},
246+
},
247+
},
248+
},
249+
expectedDescriptor: testNewDescriptorForLayer(testImages["nm/unmanaged:missing-layer-links"][0].DockerImageLayers[1]),
250+
expectedActions: []clientAction{{"get", "imagestreams/layers"}},
251+
},
252+
171253
{
172254
// TODO: this should err out because of missing image stream.
173255
// Unfortunately, it's not the case. Until we start storing layer links in etcd, we depend on
@@ -312,6 +394,13 @@ func TestRepositoryBlobStat(t *testing.T) {
312394
}
313395
}
314396

397+
for _, image := range tc.imageStreamLayers {
398+
_, err = fos.CreateImageStreamLayers(image.Namespace, &image)
399+
if err != nil {
400+
t.Fatal(err)
401+
}
402+
}
403+
315404
reg, err := newTestRegistry(ctx, registryclient.NewFakeRegistryAPIClient(nil, imageClient), driver, cfg.Cache.BlobRepositoryTTL, true)
316405
if err != nil {
317406
t.Fatalf("unexpected error: %v", err)

pkg/testutil/fakeopenshift.go

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/docker/distribution/context"
99

10+
corev1 "k8s.io/api/core/v1"
1011
"k8s.io/apimachinery/pkg/api/errors"
1112
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1213
"k8s.io/apimachinery/pkg/runtime"
@@ -23,17 +24,19 @@ type FakeOpenShift struct {
2324
logger context.Logger
2425
mu sync.Mutex
2526

26-
images map[string]imageapiv1.Image
27-
imageStreams map[string]imageapiv1.ImageStream
27+
images map[string]imageapiv1.Image
28+
imageStreams map[string]imageapiv1.ImageStream
29+
imageStreamLayers map[string]imageapiv1.ImageStreamLayers
2830
}
2931

3032
// NewFakeOpenShift constructs the fake OpenShift reactors.
3133
func NewFakeOpenShift(ctx context.Context) *FakeOpenShift {
3234
return &FakeOpenShift{
3335
logger: context.GetLogger(ctx),
3436

35-
images: make(map[string]imageapiv1.Image),
36-
imageStreams: make(map[string]imageapiv1.ImageStream),
37+
images: make(map[string]imageapiv1.Image),
38+
imageStreams: make(map[string]imageapiv1.ImageStream),
39+
imageStreamLayers: make(map[string]imageapiv1.ImageStreamLayers),
3740
}
3841
}
3942

@@ -319,6 +322,39 @@ func (fos *FakeOpenShift) GetImageStreamImage(namespace string, id string) (*ima
319322
return &isi, nil
320323
}
321324

325+
func (fos *FakeOpenShift) CreateImageStreamLayers(namespace string, is *imageapiv1.ImageStreamLayers) (*imageapiv1.ImageStreamLayers, error) {
326+
fos.mu.Lock()
327+
defer fos.mu.Unlock()
328+
329+
ref := fmt.Sprintf("%s/%s", namespace, is.Name)
330+
331+
_, ok := fos.imageStreamLayers[ref]
332+
if ok {
333+
return nil, errors.NewAlreadyExists(imageapiv1.Resource("imagestreams/layers"), is.Name)
334+
}
335+
336+
is.Namespace = namespace
337+
is.CreationTimestamp = metav1.Now()
338+
339+
fos.imageStreamLayers[ref] = *is
340+
fos.logger.Debugf("(*FakeOpenShift).imageStreamLayers[%q] created", ref)
341+
342+
return is, nil
343+
}
344+
345+
func (fos *FakeOpenShift) GetImageStreamLayers(namespace, repo string) (*imageapiv1.ImageStreamLayers, error) {
346+
fos.mu.Lock()
347+
defer fos.mu.Unlock()
348+
349+
ref := fmt.Sprintf("%s/%s", namespace, repo)
350+
351+
is, ok := fos.imageStreamLayers[ref]
352+
if !ok {
353+
return nil, errors.NewNotFound(imageapiv1.Resource("imagestreams/layers"), repo)
354+
}
355+
return &is, nil
356+
}
357+
322358
func (fos *FakeOpenShift) getName(action clientgotesting.Action) string {
323359
if getnamer, ok := action.(interface {
324360
GetName() string
@@ -375,8 +411,27 @@ func (fos *FakeOpenShift) imageStreamsHandler(action clientgotesting.Action) (bo
375411
fmt.Sprintf("(*FakeOpenShift).imageStreamsHandler: %s %s/%s",
376412
action.GetVerb(), action.GetNamespace(), fos.getName(action)),
377413
func() (bool, runtime.Object, error) {
378-
if len(action.GetSubresource()) > 0 {
379-
// ATM neither secrets nor any other subresource is handled here
414+
switch action.GetSubresource() {
415+
case "":
416+
case "layers":
417+
switch action := action.(type) {
418+
case clientgotesting.GetActionImpl:
419+
is, err := fos.GetImageStreamLayers(
420+
action.GetNamespace(),
421+
action.GetName(),
422+
)
423+
return true, is, err
424+
default:
425+
return fos.todo(action)
426+
}
427+
case "secrets":
428+
switch action := action.(type) {
429+
case clientgotesting.GetActionImpl:
430+
return true, &corev1.SecretList{}, nil
431+
default:
432+
return fos.todo(action)
433+
}
434+
default:
380435
return fos.todo(action)
381436
}
382437

0 commit comments

Comments
 (0)