From f736dd70463d7b0e4fe17a9f0b112ab3e3ef4bb2 Mon Sep 17 00:00:00 2001 From: Oleg Bulatov Date: Thu, 20 Sep 2018 16:01:40 +0200 Subject: [PATCH] Refactor integration tests --- pkg/testframework/manifest.go | 106 ++++++++++++++++++ .../manifestmigration_test.go | 51 +++------ .../metricspullthrough_test.go | 50 ++------- test/integration/offline/offline_test.go | 78 ++++--------- .../pullthroughblob/pullthroughblob_test.go | 66 +++-------- 5 files changed, 168 insertions(+), 183 deletions(-) create mode 100644 pkg/testframework/manifest.go diff --git a/pkg/testframework/manifest.go b/pkg/testframework/manifest.go new file mode 100644 index 000000000..92bb8e00c --- /dev/null +++ b/pkg/testframework/manifest.go @@ -0,0 +1,106 @@ +package testframework + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/opencontainers/go-digest" + "github.com/pborman/uuid" +) + +type Schema2ImageData struct { + ConfigMediaType string + Config []byte + ConfigDigest digest.Digest + LayerMediaType string + Layer []byte + LayerDigest digest.Digest + ManifestMediaType string + Manifest []byte + ManifestDigest digest.Digest +} + +func NewSchema2ImageData() (Schema2ImageData, error) { + data := Schema2ImageData{ + ConfigMediaType: "application/vnd.docker.container.image.v1+json", + Config: []byte("{}"), + LayerMediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", + Layer: []byte("image-registry-integration-test-" + uuid.NewRandom().String()), + ManifestMediaType: "application/vnd.docker.distribution.manifest.v2+json", + } + data.ConfigDigest = digest.FromBytes(data.Config) + data.LayerDigest = digest.FromBytes(data.Layer) + + manifest, err := json.Marshal(map[string]interface{}{ + "schemaVersion": 2, + "mediaType": data.ManifestMediaType, + "config": map[string]interface{}{ + "mediaType": data.ConfigMediaType, + "size": len(data.Config), + "digest": data.ConfigDigest.String(), + }, + "layers": []map[string]interface{}{ + { + "mediaType": data.LayerMediaType, + "size": len(data.Layer), + "digest": data.LayerDigest.String(), + }, + }, + }) + if err != nil { + return data, fmt.Errorf("unable to create image manifest: %v", err) + } + + data.Manifest = manifest + data.ManifestDigest = digest.FromBytes(data.Manifest) + + return data, nil +} + +func ServeV2(w http.ResponseWriter, r *http.Request) bool { + if r.Method == "GET" && r.URL.Path == "/v2/" { + _, _ = w.Write([]byte(`{}`)) + return true + } + return false +} + +func ServeImage(w http.ResponseWriter, r *http.Request, image string, data Schema2ImageData, tags []string) bool { + prefix := "/v2/" + image + + isGetManifest := func() bool { + if r.Method == "GET" { + if r.URL.Path == prefix+"/manifests/"+data.ManifestDigest.String() { + return true + } + for _, tag := range tags { + if r.URL.Path == prefix+"/manifests/"+tag { + return true + } + } + } + return false + } + + switch { + case isGetManifest(): + w.Header().Set("Content-Type", data.ManifestMediaType) + _, _ = w.Write(data.Manifest) + case r.Method == "GET" && r.URL.Path == prefix+"/blobs/"+data.ConfigDigest.String(): + _, _ = w.Write(data.Config) + case r.Method == "GET" && r.URL.Path == prefix+"/blobs/"+data.LayerDigest.String(): + _, _ = w.Write(data.Layer) + case r.Method == "HEAD" && r.URL.Path == prefix+"/blobs/"+data.ConfigDigest.String(): + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Length", fmt.Sprintf("%d", len(data.Config))) + w.WriteHeader(http.StatusOK) + case r.Method == "HEAD" && r.URL.Path == prefix+"/blobs/"+data.LayerDigest.String(): + w.Header().Set("Content-Type", "application/octet-stream") + w.Header().Set("Content-Length", fmt.Sprintf("%d", len(data.Layer))) + w.WriteHeader(http.StatusOK) + default: + return false + } + return true +} diff --git a/test/integration/manifestmigration/manifestmigration_test.go b/test/integration/manifestmigration/manifestmigration_test.go index c52d26bc1..6945e8a97 100644 --- a/test/integration/manifestmigration/manifestmigration_test.go +++ b/test/integration/manifestmigration/manifestmigration_test.go @@ -3,12 +3,10 @@ package integration import ( "bytes" "context" - "encoding/json" "testing" "time" "github.com/docker/distribution/registry/storage/driver/inmemory" - "github.com/opencontainers/go-digest" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -25,33 +23,10 @@ import ( ) func TestManifestMigration(t *testing.T) { - config := []byte("{}") - configDigest := digest.FromBytes(config) - - foo := []byte("foo-manifest-migration") - fooDigest := digest.FromBytes(foo) - - manifestMediaType := "application/vnd.docker.distribution.manifest.v2+json" - manifest, err := json.Marshal(map[string]interface{}{ - "schemaVersion": 2, - "mediaType": manifestMediaType, - "config": map[string]interface{}{ - "mediaType": "application/vnd.docker.container.image.v1+json", - "size": len(config), - "digest": configDigest.String(), - }, - "layers": []map[string]interface{}{ - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "size": len(foo), - "digest": fooDigest.String(), - }, - }, - }) + imageData, err := testframework.NewSchema2ImageData() if err != nil { - t.Fatalf("unable to marshal manifest: %v", err) + t.Fatal(err) } - manifestDigest := digest.FromBytes(manifest) master := testframework.NewMaster(t) defer master.Close() @@ -72,7 +47,7 @@ func TestManifestMigration(t *testing.T) { t.Fatal(err) } - err = imageClient.Images().Delete(string(manifestDigest), &metav1.DeleteOptions{}) + err = imageClient.Images().Delete(imageData.ManifestDigest.String(), &metav1.DeleteOptions{}) if err != nil && !kerrors.IsNotFound(err) { t.Fatalf("failed to delete an old instance of the image: %v", err) } @@ -84,15 +59,15 @@ func TestManifestMigration(t *testing.T) { }, Image: imageapiv1.Image{ ObjectMeta: metav1.ObjectMeta{ - Name: string(manifestDigest), + Name: imageData.ManifestDigest.String(), Annotations: map[string]string{ imageapi.ManagedByOpenShiftAnnotation: "true", }, }, DockerImageReference: "shouldnt-be-resolved.example.com/this-is-a-fake-image", - DockerImageManifestMediaType: manifestMediaType, - DockerImageManifest: string(manifest), - DockerImageConfig: string(config), + DockerImageManifestMediaType: imageData.ManifestMediaType, + DockerImageManifest: string(imageData.Manifest), + DockerImageConfig: string(imageData.Config), }, Tag: "latest", }) @@ -114,25 +89,25 @@ func TestManifestMigration(t *testing.T) { t.Fatal(err) } - _, err = ms.Get(ctx, digest.Digest(manifestDigest)) + _, err = ms.Get(ctx, imageData.ManifestDigest) if err != nil { t.Fatal(err) } t.Logf("waiting for migration to finish...") - if err := driver.WaitFor(ctx, storagepath.Blob(manifestDigest)); err != nil { + if err := driver.WaitFor(ctx, storagepath.Blob(imageData.ManifestDigest)); err != nil { t.Fatal(err) } t.Logf("manifest is migrated, checking results...") - manifestOnStorage, err := driver.GetContent(ctx, storagepath.Blob(manifestDigest)) + manifestOnStorage, err := driver.GetContent(ctx, storagepath.Blob(imageData.ManifestDigest)) if err != nil { t.Fatal(err) } - if !bytes.Equal(manifestOnStorage, manifest) { - t.Errorf("migration has changed the manifest: got %q, want %q", manifestOnStorage, manifest) + if !bytes.Equal(manifestOnStorage, imageData.Manifest) { + t.Errorf("migration has changed the manifest: got %q, want %q", manifestOnStorage, imageData.Manifest) } w, err := imageClient.Images().Watch(metav1.ListOptions{ @@ -150,7 +125,7 @@ func TestManifestMigration(t *testing.T) { if !ok { return false, nil } - if image.Name != string(manifestDigest) || image.DockerImageManifest != "" && image.DockerImageConfig != "" { + if image.Name != imageData.ManifestDigest.String() || image.DockerImageManifest != "" && image.DockerImageConfig != "" { return false, nil } return true, nil diff --git a/test/integration/metricspullthrough/metricspullthrough_test.go b/test/integration/metricspullthrough/metricspullthrough_test.go index 66f09e6aa..756194152 100644 --- a/test/integration/metricspullthrough/metricspullthrough_test.go +++ b/test/integration/metricspullthrough/metricspullthrough_test.go @@ -3,7 +3,6 @@ package integration import ( "bufio" "context" - "encoding/json" "fmt" "io" "net/http" @@ -11,7 +10,6 @@ import ( "testing" "github.com/docker/distribution" - digest "github.com/opencontainers/go-digest" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -23,11 +21,10 @@ import ( ) func TestPullthroughBlob(t *testing.T) { - config := "{}" - configDigest := digest.FromBytes([]byte(config)) - - foo := "foo" - fooDigest := digest.FromBytes([]byte(foo)) + imageData, err := testframework.NewSchema2ImageData() + if err != nil { + t.Fatal(err) + } master := testframework.NewMaster(t) defer master.Close() @@ -50,38 +47,13 @@ func TestPullthroughBlob(t *testing.T) { return } - switch req { - case "GET /v2/": - w.Write([]byte(`{}`)) - case "GET /v2/remoteimage/manifests/latest": - mediaType := "application/vnd.docker.distribution.manifest.v2+json" - w.Header().Set("Content-Type", mediaType) - _ = json.NewEncoder(w).Encode(map[string]interface{}{ - "schemaVersion": 2, - "mediaType": mediaType, - "config": map[string]interface{}{ - "mediaType": "application/vnd.docker.container.image.v1+json", - "size": len(config), - "digest": configDigest.String(), - }, - "layers": []map[string]interface{}{ - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "size": len(foo), - "digest": fooDigest.String(), - }, - }, - }) - case "GET /v2/remoteimage/blobs/" + configDigest.String(): - w.Write([]byte(config)) - case "HEAD /v2/remoteimage/blobs/" + fooDigest.String(): - w.Header().Set("Content-Length", fmt.Sprintf("%d", len(foo))) - w.WriteHeader(http.StatusOK) - case "GET /v2/remoteimage/blobs/" + fooDigest.String(): - w.Write([]byte(foo)) - default: - t.Errorf("error: remote registry got unexpected request %s: %#+v", req, r) + if testframework.ServeV2(w, r) || + testframework.ServeImage(w, r, "remoteimage", imageData, []string{"latest"}) { + return } + + t.Errorf("error: remote registry got unexpected request %s: %#+v", req, r) + http.Error(w, "unable to handle the request", http.StatusInternalServerError) })) defer ts.Close() @@ -128,7 +100,7 @@ func TestPullthroughBlob(t *testing.T) { ctx := context.Background() - _, err = repo.Blobs(ctx).Get(ctx, fooDigest) + _, err = repo.Blobs(ctx).Get(ctx, imageData.LayerDigest) if err != distribution.ErrBlobUnknown { t.Fatal(err) } diff --git a/test/integration/offline/offline_test.go b/test/integration/offline/offline_test.go index 21049bea9..5c51e7ff0 100644 --- a/test/integration/offline/offline_test.go +++ b/test/integration/offline/offline_test.go @@ -2,14 +2,12 @@ package integration import ( "context" - "encoding/json" "fmt" "net/http" "testing" "time" "github.com/docker/distribution/registry/storage/driver/inmemory" - digest "github.com/opencontainers/go-digest" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -23,34 +21,11 @@ import ( "github.com/openshift/image-registry/test/internal/storagepath" ) -func TestPullthroughBlob(t *testing.T) { - config := []byte("{}") - configDigest := digest.FromBytes(config) - - foo := []byte("foo") - fooDigest := digest.FromBytes(foo) - - manifestMediaType := "application/vnd.docker.distribution.manifest.v2+json" - manifest, err := json.Marshal(map[string]interface{}{ - "schemaVersion": 2, - "mediaType": manifestMediaType, - "config": map[string]interface{}{ - "mediaType": "application/vnd.docker.container.image.v1+json", - "size": len(config), - "digest": configDigest.String(), - }, - "layers": []map[string]interface{}{ - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "size": len(foo), - "digest": fooDigest.String(), - }, - }, - }) +func TestOffline(t *testing.T) { + imageData, err := testframework.NewSchema2ImageData() if err != nil { - t.Fatalf("unable to marshal manifest: %v", err) + t.Fatal(err) } - manifestDigest := digest.FromBytes(manifest) remoteRegistryUnavailable := false ts := testframework.NewHTTPServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -65,26 +40,13 @@ func TestPullthroughBlob(t *testing.T) { return } - switch req { - case "GET /v2/": - w.Write([]byte(`{}`)) - case "GET /v2/remoteimage/manifests/latest", "GET /v2/remoteimage/manifests/" + manifestDigest.String(): - w.Header().Set("Content-Type", manifestMediaType) - w.Write(manifest) - case "HEAD /v2/remoteimage/blobs/" + configDigest.String(): - w.Header().Set("Content-Length", fmt.Sprintf("%d", len(config))) - w.WriteHeader(http.StatusOK) - case "GET /v2/remoteimage/blobs/" + configDigest.String(): - w.Write(config) - case "HEAD /v2/remoteimage/blobs/" + fooDigest.String(): - w.Header().Set("Content-Length", fmt.Sprintf("%d", len(foo))) - w.WriteHeader(http.StatusOK) - case "GET /v2/remoteimage/blobs/" + fooDigest.String(): - w.Write(foo) - default: - t.Errorf("error: remote registry got unexpected request %s: %#+v", req, r) - http.Error(w, "unable to handle the request", http.StatusInternalServerError) + if testframework.ServeV2(w, r) || + testframework.ServeImage(w, r, "remoteimage", imageData, []string{"latest"}) { + return } + + t.Errorf("error: remote registry got unexpected request %s: %#+v", req, r) + http.Error(w, "unable to handle the request", http.StatusInternalServerError) })) defer ts.Close() @@ -147,20 +109,20 @@ func TestPullthroughBlob(t *testing.T) { if err != nil { t.Fatal(err) } - if mediatype != manifestMediaType { - t.Fatalf("manifest mediatype: got %q, want %q", mediatype, manifestMediaType) + if mediatype != imageData.ManifestMediaType { + t.Fatalf("manifest mediatype: got %q, want %q", mediatype, imageData.ManifestMediaType) } - if dgst != manifestDigest { - t.Fatalf("manifest digest: got %q, want %q", dgst, manifestDigest) + if dgst != imageData.ManifestDigest { + t.Fatalf("manifest digest: got %q, want %q", dgst, imageData.ManifestDigest) } /* Wait for mirroring to complete */ timeoutContext, timeoutCancel := context.WithTimeout(ctx, 10*time.Second) if err := driver.WaitFor( timeoutContext, - storagepath.Layer(testproject.Name+"/"+teststream.Name, configDigest), - storagepath.Layer(testproject.Name+"/"+teststream.Name, fooDigest), - storagepath.Manifest(testproject.Name+"/"+teststream.Name, manifestDigest), + storagepath.Layer(testproject.Name+"/"+teststream.Name, imageData.ConfigDigest), + storagepath.Layer(testproject.Name+"/"+teststream.Name, imageData.LayerDigest), + storagepath.Manifest(testproject.Name+"/"+teststream.Name, imageData.ManifestDigest), ); err != nil { t.Fatal(err) } @@ -174,10 +136,10 @@ func TestPullthroughBlob(t *testing.T) { if err != nil { t.Fatal(err) } - if mediatype != manifestMediaType { - t.Fatalf("manifest mediatype: got %q, want %q", mediatype, manifestMediaType) + if mediatype != imageData.ManifestMediaType { + t.Fatalf("manifest mediatype: got %q, want %q", mediatype, imageData.ManifestMediaType) } - if dgst != manifestDigest { - t.Fatalf("manifest digest: got %q, want %q", dgst, manifestDigest) + if dgst != imageData.ManifestDigest { + t.Fatalf("manifest digest: got %q, want %q", dgst, imageData.ManifestDigest) } } diff --git a/test/integration/pullthroughblob/pullthroughblob_test.go b/test/integration/pullthroughblob/pullthroughblob_test.go index e77abc82b..7e466aab7 100644 --- a/test/integration/pullthroughblob/pullthroughblob_test.go +++ b/test/integration/pullthroughblob/pullthroughblob_test.go @@ -2,13 +2,10 @@ package integration import ( "context" - "encoding/json" "fmt" "net/http" "testing" - digest "github.com/opencontainers/go-digest" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -20,11 +17,10 @@ import ( ) func TestPullthroughBlob(t *testing.T) { - config := "{}" - configDigest := digest.FromBytes([]byte(config)) - - foo := "foo" - fooDigest := digest.FromBytes([]byte(foo)) + imageData, err := testframework.NewSchema2ImageData() + if err != nil { + t.Fatal(err) + } master := testframework.NewMaster(t) defer master.Close() @@ -42,39 +38,13 @@ func TestPullthroughBlob(t *testing.T) { w.Header().Set("Docker-Distribution-API-Version", "registry/2.0") - switch req { - case "GET /v2/": - w.Write([]byte(`{}`)) - case "GET /v2/remoteimage/manifests/latest": - mediaType := "application/vnd.docker.distribution.manifest.v2+json" - w.Header().Set("Content-Type", mediaType) - _ = json.NewEncoder(w).Encode(map[string]interface{}{ - "schemaVersion": 2, - "mediaType": mediaType, - "config": map[string]interface{}{ - "mediaType": "application/vnd.docker.container.image.v1+json", - "size": len(config), - "digest": configDigest.String(), - }, - "layers": []map[string]interface{}{ - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "size": len(foo), - "digest": fooDigest.String(), - }, - }, - }) - case "GET /v2/remoteimage/blobs/" + configDigest.String(): - w.Write([]byte(config)) - case "HEAD /v2/remoteimage/blobs/" + fooDigest.String(): - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Length", fmt.Sprintf("%d", len(foo))) - w.WriteHeader(http.StatusOK) - case "GET /v2/remoteimage/blobs/" + fooDigest.String(): - w.Write([]byte(foo)) - default: - t.Errorf("error: remote registry got unexpected request %s: %#+v", req, r) + if testframework.ServeV2(w, r) || + testframework.ServeImage(w, r, "remoteimage", imageData, []string{"latest"}) { + return } + + t.Errorf("error: remote registry got unexpected request %s: %#+v", req, r) + http.Error(w, "unable to handle the request", http.StatusInternalServerError) })) defer ts.Close() @@ -113,9 +83,9 @@ func TestPullthroughBlob(t *testing.T) { } if diff := requestCounter.Diff(counter.M{ - "GET /v2/": 1, - "GET /v2/remoteimage/manifests/latest": 1, - "GET /v2/remoteimage/blobs/" + configDigest.String(): 1, + "GET /v2/": 1, + "GET /v2/remoteimage/manifests/latest": 1, + "GET /v2/remoteimage/blobs/" + imageData.ConfigDigest.String(): 1, }); diff != nil { t.Fatalf("unexpected number of requests: %q", diff) } @@ -130,20 +100,20 @@ func TestPullthroughBlob(t *testing.T) { ctx := context.Background() - data, err := repo.Blobs(ctx).Get(ctx, fooDigest) + data, err := repo.Blobs(ctx).Get(ctx, imageData.LayerDigest) if err != nil { t.Fatal(err) } - if string(data) != foo { - t.Fatalf("got %q, want %q", string(data), foo) + if string(data) != string(imageData.Layer) { + t.Fatalf("got %q, want %q", string(data), string(imageData.Layer)) } // TODO(dmage): remove the HEAD request if diff := requestCounter.Diff(counter.M{ "GET /v2/": 1, - "HEAD /v2/remoteimage/blobs/" + fooDigest.String(): 1, - "GET /v2/remoteimage/blobs/" + fooDigest.String(): 1, + "HEAD /v2/remoteimage/blobs/" + imageData.LayerDigest.String(): 1, + "GET /v2/remoteimage/blobs/" + imageData.LayerDigest.String(): 1, }); diff != nil { t.Fatalf("unexpected number of requests: %q", diff) }