cuelabs.dev/go/oci/ociregistry@v0.0.0-20240906074133-82eb438dd565/internal/ocirequest/request_test.go (about) 1 // Copyright 2023 CUE Labs AG 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ocirequest 16 17 import ( 18 "net/url" 19 "testing" 20 21 "github.com/go-quicktest/qt" 22 ) 23 24 var parseRequestTests = []struct { 25 testName string 26 method string 27 url string 28 29 wantRequest *Request 30 wantError string 31 wantConstruct string 32 }{{ 33 testName: "ping", 34 method: "GET", 35 url: "/v2", 36 wantRequest: &Request{ 37 Kind: ReqPing, 38 }, 39 wantConstruct: "/v2/", 40 }, { 41 testName: "ping", 42 method: "GET", 43 url: "/v2/", 44 wantRequest: &Request{ 45 Kind: ReqPing, 46 }, 47 }, { 48 testName: "getBlob", 49 method: "GET", 50 url: "/v2/foo/bar/blobs/sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", 51 wantRequest: &Request{ 52 Kind: ReqBlobGet, 53 Repo: "foo/bar", 54 Digest: "sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", 55 }, 56 }, { 57 testName: "getBlobInvalidDigest", 58 method: "GET", 59 url: "/v2/foo/bar/blobs/sha256:wrong", 60 wantError: `badly formed digest`, 61 }, { 62 testName: "getBlobInvalidRepo", 63 method: "GET", 64 url: "/v2/foo/bAr/blobs/sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", 65 wantError: `name invalid: invalid repository name`, 66 }, { 67 testName: "startUpload", 68 method: "POST", 69 url: "/v2/somerepo/blobs/uploads/", 70 wantRequest: &Request{ 71 Kind: ReqBlobStartUpload, 72 Repo: "somerepo", 73 }, 74 }, { 75 testName: "uploadChunk", 76 method: "PATCH", 77 url: "/v2/somerepo/blobs/uploads/YmxhaGJsYWg", 78 wantRequest: &Request{ 79 Kind: ReqBlobUploadChunk, 80 Repo: "somerepo", 81 UploadID: "blahblah", 82 }, 83 }, { 84 testName: "uploadChunk", 85 method: "PATCH", 86 url: "/v2/somerepo/blobs/uploads/YmxhaGJsYWg", 87 wantRequest: &Request{ 88 Kind: ReqBlobUploadChunk, 89 Repo: "somerepo", 90 UploadID: "blahblah", 91 }, 92 }, { 93 testName: "badlyFormedUploadDigest", 94 method: "POST", 95 url: "/v2/foo/blobs/uploads?digest=sha256:fake", 96 wantError: "badly formed digest", 97 }, { 98 testName: "getUploadInfo", 99 method: "GET", 100 url: "/v2/myorg/myrepo/blobs/uploads/YmxhaGJsYWg", 101 wantRequest: &Request{ 102 Kind: ReqBlobUploadInfo, 103 Repo: "myorg/myrepo", 104 UploadID: "blahblah", 105 }, 106 }, { 107 testName: "mount", 108 method: "POST", 109 url: "/v2/x/y/blobs/uploads/?mount=sha256:c659529df24a1878f6df8d93c652280235a50b95e862d8e5cb566ee5b9ed6386&from=somewhere/other", 110 wantRequest: &Request{ 111 Kind: ReqBlobMount, 112 Repo: "x/y", 113 Digest: "sha256:c659529df24a1878f6df8d93c652280235a50b95e862d8e5cb566ee5b9ed6386", 114 FromRepo: "somewhere/other", 115 }, 116 }, { 117 testName: "mount2", 118 method: "POST", 119 url: "/v2/myorg/other/blobs/uploads/?from=myorg%2Fmyrepo&mount=sha256%3Ad647b322fff1e9dcb828ee67a6c6d1ed0ceef760988fdf54f9cfdeb96186e001", 120 wantRequest: &Request{ 121 Kind: ReqBlobMount, 122 Repo: "myorg/other", 123 Digest: "sha256:d647b322fff1e9dcb828ee67a6c6d1ed0ceef760988fdf54f9cfdeb96186e001", 124 FromRepo: "myorg/myrepo", 125 }, 126 }, { 127 testName: "mountWithNoFrom", 128 method: "POST", 129 url: "/v2/x/y/blobs/uploads/?mount=sha256:c659529df24a1878f6df8d93c652280235a50b95e862d8e5cb566ee5b9ed6386", 130 wantRequest: &Request{ 131 Kind: ReqBlobStartUpload, 132 Repo: "x/y", 133 }, 134 wantConstruct: "/v2/x/y/blobs/uploads/", 135 }, { 136 testName: "manifestHead", 137 method: "HEAD", 138 url: "/v2/myorg/myrepo/manifests/sha256:681aef2367e055f33cb8a6ab9c3090931f6eefd0c3ef15c6e4a79bdadfdb8982", 139 wantRequest: &Request{ 140 Kind: ReqManifestHead, 141 Repo: "myorg/myrepo", 142 Digest: "sha256:681aef2367e055f33cb8a6ab9c3090931f6eefd0c3ef15c6e4a79bdadfdb8982", 143 }, 144 }} 145 146 func TestParseRequest(t *testing.T) { 147 for _, test := range parseRequestTests { 148 t.Run(test.testName, func(t *testing.T) { 149 u, err := url.Parse(test.url) 150 if err != nil { 151 t.Fatal(err) 152 } 153 rreq, err := Parse(test.method, u) 154 if test.wantError != "" { 155 qt.Assert(t, qt.ErrorMatches(err, test.wantError)) 156 // TODO http code 157 return 158 } 159 qt.Assert(t, qt.IsNil(err)) 160 qt.Assert(t, qt.DeepEquals(rreq, test.wantRequest)) 161 method, ustr := rreq.MustConstruct() 162 if test.wantConstruct == "" { 163 test.wantConstruct = test.url 164 } 165 166 qt.Check(t, qt.Equals(method, test.method)) 167 qt.Check(t, qt.Equals(canonURL(ustr), canonURL(test.wantConstruct))) 168 }) 169 } 170 } 171 172 func canonURL(ustr string) string { 173 u, err := url.Parse(ustr) 174 if err != nil { 175 panic(err) 176 } 177 qv := u.Query() 178 if len(qv) == 0 { 179 return ustr 180 } 181 u.RawQuery = qv.Encode() 182 return u.String() 183 }