github.com/dougm/docker@v1.5.0/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/bar/manifests/tag",
    57  			Vars: map[string]string{
    58  				"name": "foo/bar",
    59  				"tag":  "tag",
    60  			},
    61  		},
    62  		{
    63  			RouteName:  RouteNameTags,
    64  			RequestURI: "/v2/foo/bar/tags/list",
    65  			Vars: map[string]string{
    66  				"name": "foo/bar",
    67  			},
    68  		},
    69  		{
    70  			RouteName:  RouteNameBlob,
    71  			RequestURI: "/v2/foo/bar/blobs/tarsum.dev+foo:abcdef0919234",
    72  			Vars: map[string]string{
    73  				"name":   "foo/bar",
    74  				"digest": "tarsum.dev+foo:abcdef0919234",
    75  			},
    76  		},
    77  		{
    78  			RouteName:  RouteNameBlob,
    79  			RequestURI: "/v2/foo/bar/blobs/sha256:abcdef0919234",
    80  			Vars: map[string]string{
    81  				"name":   "foo/bar",
    82  				"digest": "sha256:abcdef0919234",
    83  			},
    84  		},
    85  		{
    86  			RouteName:  RouteNameBlobUpload,
    87  			RequestURI: "/v2/foo/bar/blobs/uploads/",
    88  			Vars: map[string]string{
    89  				"name": "foo/bar",
    90  			},
    91  		},
    92  		{
    93  			RouteName:  RouteNameBlobUploadChunk,
    94  			RequestURI: "/v2/foo/bar/blobs/uploads/uuid",
    95  			Vars: map[string]string{
    96  				"name": "foo/bar",
    97  				"uuid": "uuid",
    98  			},
    99  		},
   100  		{
   101  			RouteName:  RouteNameBlobUploadChunk,
   102  			RequestURI: "/v2/foo/bar/blobs/uploads/D95306FA-FAD3-4E36-8D41-CF1C93EF8286",
   103  			Vars: map[string]string{
   104  				"name": "foo/bar",
   105  				"uuid": "D95306FA-FAD3-4E36-8D41-CF1C93EF8286",
   106  			},
   107  		},
   108  		{
   109  			RouteName:  RouteNameBlobUploadChunk,
   110  			RequestURI: "/v2/foo/bar/blobs/uploads/RDk1MzA2RkEtRkFEMy00RTM2LThENDEtQ0YxQzkzRUY4Mjg2IA==",
   111  			Vars: map[string]string{
   112  				"name": "foo/bar",
   113  				"uuid": "RDk1MzA2RkEtRkFEMy00RTM2LThENDEtQ0YxQzkzRUY4Mjg2IA==",
   114  			},
   115  		},
   116  		{
   117  			// Check ambiguity: ensure we can distinguish between tags for
   118  			// "foo/bar/image/image" and image for "foo/bar/image" with tag
   119  			// "tags"
   120  			RouteName:  RouteNameManifest,
   121  			RequestURI: "/v2/foo/bar/manifests/manifests/tags",
   122  			Vars: map[string]string{
   123  				"name": "foo/bar/manifests",
   124  				"tag":  "tags",
   125  			},
   126  		},
   127  		{
   128  			// This case presents an ambiguity between foo/bar with tag="tags"
   129  			// and list tags for "foo/bar/manifest"
   130  			RouteName:  RouteNameTags,
   131  			RequestURI: "/v2/foo/bar/manifests/tags/list",
   132  			Vars: map[string]string{
   133  				"name": "foo/bar/manifests",
   134  			},
   135  		},
   136  		{
   137  			RouteName:  RouteNameBlobUploadChunk,
   138  			RequestURI: "/v2/foo/../../blob/uploads/D95306FA-FAD3-4E36-8D41-CF1C93EF8286",
   139  			StatusCode: http.StatusNotFound,
   140  		},
   141  	} {
   142  		// Register the endpoint
   143  		router.GetRoute(testcase.RouteName).Handler(testHandler)
   144  		u := server.URL + testcase.RequestURI
   145  
   146  		resp, err := http.Get(u)
   147  
   148  		if err != nil {
   149  			t.Fatalf("error issuing get request: %v", err)
   150  		}
   151  
   152  		if testcase.StatusCode == 0 {
   153  			// Override default, zero-value
   154  			testcase.StatusCode = http.StatusOK
   155  		}
   156  
   157  		if resp.StatusCode != testcase.StatusCode {
   158  			t.Fatalf("unexpected status for %s: %v %v", u, resp.Status, resp.StatusCode)
   159  		}
   160  
   161  		if testcase.StatusCode != http.StatusOK {
   162  			// We don't care about json response.
   163  			continue
   164  		}
   165  
   166  		dec := json.NewDecoder(resp.Body)
   167  
   168  		var actualRouteInfo routeTestCase
   169  		if err := dec.Decode(&actualRouteInfo); err != nil {
   170  			t.Fatalf("error reading json response: %v", err)
   171  		}
   172  		// Needs to be set out of band
   173  		actualRouteInfo.StatusCode = resp.StatusCode
   174  
   175  		if actualRouteInfo.RouteName != testcase.RouteName {
   176  			t.Fatalf("incorrect route %q matched, expected %q", actualRouteInfo.RouteName, testcase.RouteName)
   177  		}
   178  
   179  		if !reflect.DeepEqual(actualRouteInfo, testcase) {
   180  			t.Fatalf("actual does not equal expected: %#v != %#v", actualRouteInfo, testcase)
   181  		}
   182  	}
   183  
   184  }