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  }