github.com/christopherobin/docker@v1.6.2/registry/v2/routes_test.go (about) 1 package v2 2 3 import ( 4 "encoding/json" 5 "net/http" 6 "net/http/httptest" 7 "reflect" 8 "testing" 9 10 "github.com/gorilla/mux" 11 ) 12 13 type routeTestCase struct { 14 RequestURI string 15 Vars map[string]string 16 RouteName string 17 StatusCode int 18 } 19 20 // TestRouter registers a test handler with all the routes and ensures that 21 // each route returns the expected path variables. Not method verification is 22 // present. This not meant to be exhaustive but as check to ensure that the 23 // expected variables are extracted. 24 // 25 // This may go away as the application structure comes together. 26 func TestRouter(t *testing.T) { 27 28 router := Router() 29 30 testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 31 testCase := routeTestCase{ 32 RequestURI: r.RequestURI, 33 Vars: mux.Vars(r), 34 RouteName: mux.CurrentRoute(r).GetName(), 35 } 36 37 enc := json.NewEncoder(w) 38 39 if err := enc.Encode(testCase); err != nil { 40 http.Error(w, err.Error(), http.StatusInternalServerError) 41 return 42 } 43 }) 44 45 // Startup test server 46 server := httptest.NewServer(router) 47 48 for _, testcase := range []routeTestCase{ 49 { 50 RouteName: RouteNameBase, 51 RequestURI: "/v2/", 52 Vars: map[string]string{}, 53 }, 54 { 55 RouteName: RouteNameManifest, 56 RequestURI: "/v2/foo/manifests/bar", 57 Vars: map[string]string{ 58 "name": "foo", 59 "reference": "bar", 60 }, 61 }, 62 { 63 RouteName: RouteNameManifest, 64 RequestURI: "/v2/foo/bar/manifests/tag", 65 Vars: map[string]string{ 66 "name": "foo/bar", 67 "reference": "tag", 68 }, 69 }, 70 { 71 RouteName: RouteNameTags, 72 RequestURI: "/v2/foo/bar/tags/list", 73 Vars: map[string]string{ 74 "name": "foo/bar", 75 }, 76 }, 77 { 78 RouteName: RouteNameBlob, 79 RequestURI: "/v2/foo/bar/blobs/tarsum.dev+foo:abcdef0919234", 80 Vars: map[string]string{ 81 "name": "foo/bar", 82 "digest": "tarsum.dev+foo:abcdef0919234", 83 }, 84 }, 85 { 86 RouteName: RouteNameBlob, 87 RequestURI: "/v2/foo/bar/blobs/sha256:abcdef0919234", 88 Vars: map[string]string{ 89 "name": "foo/bar", 90 "digest": "sha256:abcdef0919234", 91 }, 92 }, 93 { 94 RouteName: RouteNameBlobUpload, 95 RequestURI: "/v2/foo/bar/blobs/uploads/", 96 Vars: map[string]string{ 97 "name": "foo/bar", 98 }, 99 }, 100 { 101 RouteName: RouteNameBlobUploadChunk, 102 RequestURI: "/v2/foo/bar/blobs/uploads/uuid", 103 Vars: map[string]string{ 104 "name": "foo/bar", 105 "uuid": "uuid", 106 }, 107 }, 108 { 109 RouteName: RouteNameBlobUploadChunk, 110 RequestURI: "/v2/foo/bar/blobs/uploads/D95306FA-FAD3-4E36-8D41-CF1C93EF8286", 111 Vars: map[string]string{ 112 "name": "foo/bar", 113 "uuid": "D95306FA-FAD3-4E36-8D41-CF1C93EF8286", 114 }, 115 }, 116 { 117 RouteName: RouteNameBlobUploadChunk, 118 RequestURI: "/v2/foo/bar/blobs/uploads/RDk1MzA2RkEtRkFEMy00RTM2LThENDEtQ0YxQzkzRUY4Mjg2IA==", 119 Vars: map[string]string{ 120 "name": "foo/bar", 121 "uuid": "RDk1MzA2RkEtRkFEMy00RTM2LThENDEtQ0YxQzkzRUY4Mjg2IA==", 122 }, 123 }, 124 { 125 // Check ambiguity: ensure we can distinguish between tags for 126 // "foo/bar/image/image" and image for "foo/bar/image" with tag 127 // "tags" 128 RouteName: RouteNameManifest, 129 RequestURI: "/v2/foo/bar/manifests/manifests/tags", 130 Vars: map[string]string{ 131 "name": "foo/bar/manifests", 132 "reference": "tags", 133 }, 134 }, 135 { 136 // This case presents an ambiguity between foo/bar with tag="tags" 137 // and list tags for "foo/bar/manifest" 138 RouteName: RouteNameTags, 139 RequestURI: "/v2/foo/bar/manifests/tags/list", 140 Vars: map[string]string{ 141 "name": "foo/bar/manifests", 142 }, 143 }, 144 { 145 RouteName: RouteNameBlobUploadChunk, 146 RequestURI: "/v2/foo/../../blob/uploads/D95306FA-FAD3-4E36-8D41-CF1C93EF8286", 147 StatusCode: http.StatusNotFound, 148 }, 149 } { 150 // Register the endpoint 151 router.GetRoute(testcase.RouteName).Handler(testHandler) 152 u := server.URL + testcase.RequestURI 153 154 resp, err := http.Get(u) 155 156 if err != nil { 157 t.Fatalf("error issuing get request: %v", err) 158 } 159 160 if testcase.StatusCode == 0 { 161 // Override default, zero-value 162 testcase.StatusCode = http.StatusOK 163 } 164 165 if resp.StatusCode != testcase.StatusCode { 166 t.Fatalf("unexpected status for %s: %v %v", u, resp.Status, resp.StatusCode) 167 } 168 169 if testcase.StatusCode != http.StatusOK { 170 // We don't care about json response. 171 continue 172 } 173 174 dec := json.NewDecoder(resp.Body) 175 176 var actualRouteInfo routeTestCase 177 if err := dec.Decode(&actualRouteInfo); err != nil { 178 t.Fatalf("error reading json response: %v", err) 179 } 180 // Needs to be set out of band 181 actualRouteInfo.StatusCode = resp.StatusCode 182 183 if actualRouteInfo.RouteName != testcase.RouteName { 184 t.Fatalf("incorrect route %q matched, expected %q", actualRouteInfo.RouteName, testcase.RouteName) 185 } 186 187 if !reflect.DeepEqual(actualRouteInfo, testcase) { 188 t.Fatalf("actual does not equal expected: %#v != %#v", actualRouteInfo, testcase) 189 } 190 } 191 192 }