cuelabs.dev/go/oci/ociregistry@v0.0.0-20240906074133-82eb438dd565/ociclient/error_test.go (about)

     1  package ociclient
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"net/url"
     9  	"strings"
    10  	"testing"
    11  
    12  	"cuelabs.dev/go/oci/ociregistry"
    13  	"cuelabs.dev/go/oci/ociregistry/ociserver"
    14  	"github.com/go-quicktest/qt"
    15  	"github.com/opencontainers/go-digest"
    16  )
    17  
    18  func TestErrorStuttering(t *testing.T) {
    19  	// This checks that the stuttering observed in issue #31
    20  	// isn't an issue when ociserver wraps ociclient.
    21  	srv := httptest.NewServer(ociserver.New(&ociregistry.Funcs{
    22  		NewError: func(ctx context.Context, methodName, repo string) error {
    23  			return ociregistry.ErrManifestUnknown
    24  		},
    25  	}, nil))
    26  	defer srv.Close()
    27  
    28  	srvURL, _ := url.Parse(srv.URL)
    29  	r, err := New(srvURL.Host, &Options{
    30  		Insecure: true,
    31  	})
    32  	qt.Assert(t, qt.IsNil(err))
    33  	_, err = r.GetTag(context.Background(), "foo", "sometag")
    34  	qt.Check(t, qt.ErrorIs(err, ociregistry.ErrManifestUnknown))
    35  	qt.Check(t, qt.ErrorMatches(err, `404 Not Found: manifest unknown: manifest unknown to registry`))
    36  
    37  	// ResolveTag uses HEAD rather than GET, so here we're testing
    38  	// the path where a response with no body gets turned back into
    39  	// something vaguely resembling the original error, which is why
    40  	// the code and message have changed.
    41  	_, err = r.ResolveTag(context.Background(), "foo", "sometag")
    42  	qt.Check(t, qt.ErrorIs(err, ociregistry.ErrNameUnknown))
    43  	qt.Check(t, qt.ErrorMatches(err, `404 Not Found: name unknown: repository name not known to registry`))
    44  }
    45  
    46  func TestNonJSONErrorResponse(t *testing.T) {
    47  	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    48  		w.WriteHeader(http.StatusTeapot)
    49  		w.Write([]byte("some body"))
    50  	}))
    51  	defer srv.Close()
    52  
    53  	srvURL, _ := url.Parse(srv.URL)
    54  	r, err := New(srvURL.Host, &Options{
    55  		Insecure: true,
    56  	})
    57  	qt.Assert(t, qt.IsNil(err))
    58  	assertStatusCode := func(f func(ctx context.Context, r ociregistry.Interface) error) {
    59  		err := f(context.Background(), r)
    60  		var herr ociregistry.HTTPError
    61  		ok := errors.As(err, &herr)
    62  		qt.Assert(t, qt.IsTrue(ok))
    63  		qt.Assert(t, qt.Equals(herr.StatusCode(), http.StatusTeapot))
    64  	}
    65  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
    66  		rd, err := r.GetBlob(ctx, "foo/read", "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
    67  		if rd != nil {
    68  			rd.Close()
    69  		}
    70  		return err
    71  	})
    72  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
    73  		rd, err := r.GetBlobRange(ctx, "foo/read", "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 100, 200)
    74  		if rd != nil {
    75  			rd.Close()
    76  		}
    77  		return err
    78  	})
    79  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
    80  		rd, err := r.GetManifest(ctx, "foo/read", "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
    81  		if rd != nil {
    82  			rd.Close()
    83  		}
    84  		return err
    85  	})
    86  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
    87  		rd, err := r.GetTag(ctx, "foo/read", "sometag")
    88  		if rd != nil {
    89  			rd.Close()
    90  		}
    91  		return err
    92  	})
    93  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
    94  		_, err := r.ResolveBlob(ctx, "foo/read", "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
    95  		return err
    96  	})
    97  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
    98  		_, err := r.ResolveManifest(ctx, "foo/read", "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
    99  		return err
   100  	})
   101  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   102  		_, err := r.ResolveTag(ctx, "foo/read", "sometag")
   103  		return err
   104  	})
   105  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   106  		_, err := r.PushBlob(ctx, "foo/write", ociregistry.Descriptor{
   107  			MediaType: "application/json",
   108  			Digest:    "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
   109  			Size:      3,
   110  		}, strings.NewReader("foo"))
   111  		return err
   112  	})
   113  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   114  		w, err := r.PushBlobChunked(ctx, "foo/write", 0)
   115  		if err != nil {
   116  			return err
   117  		}
   118  		w.Close()
   119  		return nil
   120  	})
   121  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   122  		w, err := r.PushBlobChunkedResume(ctx, "foo/write", "/someid", 3, 0)
   123  		if err != nil {
   124  			return err
   125  		}
   126  		data := []byte("some data")
   127  		if _, err := w.Write(data); err != nil {
   128  			return err
   129  		}
   130  		_, err = w.Commit(digest.FromBytes(data))
   131  		return err
   132  	})
   133  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   134  		_, err := r.MountBlob(ctx, "foo/read", "foo/write", "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
   135  		return err
   136  	})
   137  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   138  		_, err := r.PushManifest(ctx, "foo/write", "sometag", []byte("something"), "application/json")
   139  		return err
   140  	})
   141  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   142  		return r.DeleteBlob(ctx, "foo/write", "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
   143  	})
   144  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   145  		return r.DeleteManifest(ctx, "foo/write", "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
   146  	})
   147  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   148  		return r.DeleteTag(ctx, "foo/write", "sometag")
   149  	})
   150  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   151  		_, err := ociregistry.All(r.Repositories(ctx, ""))
   152  		return err
   153  	})
   154  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   155  		_, err := ociregistry.All(r.Tags(ctx, "foo/read", ""))
   156  		return err
   157  	})
   158  	assertStatusCode(func(ctx context.Context, r ociregistry.Interface) error {
   159  		_, err := ociregistry.All(r.Referrers(ctx, "foo/read", "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", ""))
   160  		return err
   161  	})
   162  }