github.com/wulonghui/docker@v1.8.0-rc2/registry/registry_test.go (about)

     1  package registry
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"net/http/httputil"
     7  	"net/url"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/docker/distribution/registry/client/transport"
    12  	"github.com/docker/docker/cliconfig"
    13  )
    14  
    15  var (
    16  	token = []string{"fake-token"}
    17  )
    18  
    19  const (
    20  	imageID = "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d"
    21  	REPO    = "foo42/bar"
    22  )
    23  
    24  func spawnTestRegistrySession(t *testing.T) *Session {
    25  	authConfig := &cliconfig.AuthConfig{}
    26  	endpoint, err := NewEndpoint(makeIndex("/v1/"), nil)
    27  	if err != nil {
    28  		t.Fatal(err)
    29  	}
    30  	var tr http.RoundTripper = debugTransport{NewTransport(nil), t.Log}
    31  	tr = transport.NewTransport(AuthTransport(tr, authConfig, false), DockerHeaders(nil)...)
    32  	client := HTTPClient(tr)
    33  	r, err := NewSession(client, authConfig, endpoint)
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	// In a normal scenario for the v1 registry, the client should send a `X-Docker-Token: true`
    38  	// header while authenticating, in order to retrieve a token that can be later used to
    39  	// perform authenticated actions.
    40  	//
    41  	// The mock v1 registry does not support that, (TODO(tiborvass): support it), instead,
    42  	// it will consider authenticated any request with the header `X-Docker-Token: fake-token`.
    43  	//
    44  	// Because we know that the client's transport is an `*authTransport` we simply cast it,
    45  	// in order to set the internal cached token to the fake token, and thus send that fake token
    46  	// upon every subsequent requests.
    47  	r.client.Transport.(*authTransport).token = token
    48  	return r
    49  }
    50  
    51  func TestPingRegistryEndpoint(t *testing.T) {
    52  	testPing := func(index *IndexInfo, expectedStandalone bool, assertMessage string) {
    53  		ep, err := NewEndpoint(index, nil)
    54  		if err != nil {
    55  			t.Fatal(err)
    56  		}
    57  		regInfo, err := ep.Ping()
    58  		if err != nil {
    59  			t.Fatal(err)
    60  		}
    61  
    62  		assertEqual(t, regInfo.Standalone, expectedStandalone, assertMessage)
    63  	}
    64  
    65  	testPing(makeIndex("/v1/"), true, "Expected standalone to be true (default)")
    66  	testPing(makeHTTPSIndex("/v1/"), true, "Expected standalone to be true (default)")
    67  	testPing(makePublicIndex(), false, "Expected standalone to be false for public index")
    68  }
    69  
    70  func TestEndpoint(t *testing.T) {
    71  	// Simple wrapper to fail test if err != nil
    72  	expandEndpoint := func(index *IndexInfo) *Endpoint {
    73  		endpoint, err := NewEndpoint(index, nil)
    74  		if err != nil {
    75  			t.Fatal(err)
    76  		}
    77  		return endpoint
    78  	}
    79  
    80  	assertInsecureIndex := func(index *IndexInfo) {
    81  		index.Secure = true
    82  		_, err := NewEndpoint(index, nil)
    83  		assertNotEqual(t, err, nil, index.Name+": Expected error for insecure index")
    84  		assertEqual(t, strings.Contains(err.Error(), "insecure-registry"), true, index.Name+": Expected insecure-registry  error for insecure index")
    85  		index.Secure = false
    86  	}
    87  
    88  	assertSecureIndex := func(index *IndexInfo) {
    89  		index.Secure = true
    90  		_, err := NewEndpoint(index, nil)
    91  		assertNotEqual(t, err, nil, index.Name+": Expected cert error for secure index")
    92  		assertEqual(t, strings.Contains(err.Error(), "certificate signed by unknown authority"), true, index.Name+": Expected cert error for secure index")
    93  		index.Secure = false
    94  	}
    95  
    96  	index := &IndexInfo{}
    97  	index.Name = makeURL("/v1/")
    98  	endpoint := expandEndpoint(index)
    99  	assertEqual(t, endpoint.String(), index.Name, "Expected endpoint to be "+index.Name)
   100  	if endpoint.Version != APIVersion1 {
   101  		t.Fatal("Expected endpoint to be v1")
   102  	}
   103  	assertInsecureIndex(index)
   104  
   105  	index.Name = makeURL("")
   106  	endpoint = expandEndpoint(index)
   107  	assertEqual(t, endpoint.String(), index.Name+"/v1/", index.Name+": Expected endpoint to be "+index.Name+"/v1/")
   108  	if endpoint.Version != APIVersion1 {
   109  		t.Fatal("Expected endpoint to be v1")
   110  	}
   111  	assertInsecureIndex(index)
   112  
   113  	httpURL := makeURL("")
   114  	index.Name = strings.SplitN(httpURL, "://", 2)[1]
   115  	endpoint = expandEndpoint(index)
   116  	assertEqual(t, endpoint.String(), httpURL+"/v1/", index.Name+": Expected endpoint to be "+httpURL+"/v1/")
   117  	if endpoint.Version != APIVersion1 {
   118  		t.Fatal("Expected endpoint to be v1")
   119  	}
   120  	assertInsecureIndex(index)
   121  
   122  	index.Name = makeHTTPSURL("/v1/")
   123  	endpoint = expandEndpoint(index)
   124  	assertEqual(t, endpoint.String(), index.Name, "Expected endpoint to be "+index.Name)
   125  	if endpoint.Version != APIVersion1 {
   126  		t.Fatal("Expected endpoint to be v1")
   127  	}
   128  	assertSecureIndex(index)
   129  
   130  	index.Name = makeHTTPSURL("")
   131  	endpoint = expandEndpoint(index)
   132  	assertEqual(t, endpoint.String(), index.Name+"/v1/", index.Name+": Expected endpoint to be "+index.Name+"/v1/")
   133  	if endpoint.Version != APIVersion1 {
   134  		t.Fatal("Expected endpoint to be v1")
   135  	}
   136  	assertSecureIndex(index)
   137  
   138  	httpsURL := makeHTTPSURL("")
   139  	index.Name = strings.SplitN(httpsURL, "://", 2)[1]
   140  	endpoint = expandEndpoint(index)
   141  	assertEqual(t, endpoint.String(), httpsURL+"/v1/", index.Name+": Expected endpoint to be "+httpsURL+"/v1/")
   142  	if endpoint.Version != APIVersion1 {
   143  		t.Fatal("Expected endpoint to be v1")
   144  	}
   145  	assertSecureIndex(index)
   146  
   147  	badEndpoints := []string{
   148  		"http://127.0.0.1/v1/",
   149  		"https://127.0.0.1/v1/",
   150  		"http://127.0.0.1",
   151  		"https://127.0.0.1",
   152  		"127.0.0.1",
   153  	}
   154  	for _, address := range badEndpoints {
   155  		index.Name = address
   156  		_, err := NewEndpoint(index, nil)
   157  		checkNotEqual(t, err, nil, "Expected error while expanding bad endpoint")
   158  	}
   159  }
   160  
   161  func TestGetRemoteHistory(t *testing.T) {
   162  	r := spawnTestRegistrySession(t)
   163  	hist, err := r.GetRemoteHistory(imageID, makeURL("/v1/"))
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  	assertEqual(t, len(hist), 2, "Expected 2 images in history")
   168  	assertEqual(t, hist[0], imageID, "Expected "+imageID+"as first ancestry")
   169  	assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
   170  		"Unexpected second ancestry")
   171  }
   172  
   173  func TestLookupRemoteImage(t *testing.T) {
   174  	r := spawnTestRegistrySession(t)
   175  	err := r.LookupRemoteImage(imageID, makeURL("/v1/"))
   176  	assertEqual(t, err, nil, "Expected error of remote lookup to nil")
   177  	if err := r.LookupRemoteImage("abcdef", makeURL("/v1/")); err == nil {
   178  		t.Fatal("Expected error of remote lookup to not nil")
   179  	}
   180  }
   181  
   182  func TestGetRemoteImageJSON(t *testing.T) {
   183  	r := spawnTestRegistrySession(t)
   184  	json, size, err := r.GetRemoteImageJSON(imageID, makeURL("/v1/"))
   185  	if err != nil {
   186  		t.Fatal(err)
   187  	}
   188  	assertEqual(t, size, 154, "Expected size 154")
   189  	if len(json) <= 0 {
   190  		t.Fatal("Expected non-empty json")
   191  	}
   192  
   193  	_, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"))
   194  	if err == nil {
   195  		t.Fatal("Expected image not found error")
   196  	}
   197  }
   198  
   199  func TestGetRemoteImageLayer(t *testing.T) {
   200  	r := spawnTestRegistrySession(t)
   201  	data, err := r.GetRemoteImageLayer(imageID, makeURL("/v1/"), 0)
   202  	if err != nil {
   203  		t.Fatal(err)
   204  	}
   205  	if data == nil {
   206  		t.Fatal("Expected non-nil data result")
   207  	}
   208  
   209  	_, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), 0)
   210  	if err == nil {
   211  		t.Fatal("Expected image not found error")
   212  	}
   213  }
   214  
   215  func TestGetRemoteTag(t *testing.T) {
   216  	r := spawnTestRegistrySession(t)
   217  	tag, err := r.GetRemoteTag([]string{makeURL("/v1/")}, REPO, "test")
   218  	if err != nil {
   219  		t.Fatal(err)
   220  	}
   221  	assertEqual(t, tag, imageID, "Expected tag test to map to "+imageID)
   222  
   223  	_, err = r.GetRemoteTag([]string{makeURL("/v1/")}, "foo42/baz", "foo")
   224  	if err != ErrRepoNotFound {
   225  		t.Fatal("Expected ErrRepoNotFound error when fetching tag for bogus repo")
   226  	}
   227  }
   228  
   229  func TestGetRemoteTags(t *testing.T) {
   230  	r := spawnTestRegistrySession(t)
   231  	tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO)
   232  	if err != nil {
   233  		t.Fatal(err)
   234  	}
   235  	assertEqual(t, len(tags), 2, "Expected two tags")
   236  	assertEqual(t, tags["latest"], imageID, "Expected tag latest to map to "+imageID)
   237  	assertEqual(t, tags["test"], imageID, "Expected tag test to map to "+imageID)
   238  
   239  	_, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz")
   240  	if err != ErrRepoNotFound {
   241  		t.Fatal("Expected ErrRepoNotFound error when fetching tags for bogus repo")
   242  	}
   243  }
   244  
   245  func TestGetRepositoryData(t *testing.T) {
   246  	r := spawnTestRegistrySession(t)
   247  	parsedURL, err := url.Parse(makeURL("/v1/"))
   248  	if err != nil {
   249  		t.Fatal(err)
   250  	}
   251  	host := "http://" + parsedURL.Host + "/v1/"
   252  	data, err := r.GetRepositoryData("foo42/bar")
   253  	if err != nil {
   254  		t.Fatal(err)
   255  	}
   256  	assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList")
   257  	assertEqual(t, len(data.Endpoints), 2,
   258  		fmt.Sprintf("Expected 2 endpoints in Endpoints, found %d instead", len(data.Endpoints)))
   259  	assertEqual(t, data.Endpoints[0], host,
   260  		fmt.Sprintf("Expected first endpoint to be %s but found %s instead", host, data.Endpoints[0]))
   261  	assertEqual(t, data.Endpoints[1], "http://test.example.com/v1/",
   262  		fmt.Sprintf("Expected first endpoint to be http://test.example.com/v1/ but found %s instead", data.Endpoints[1]))
   263  
   264  }
   265  
   266  func TestPushImageJSONRegistry(t *testing.T) {
   267  	r := spawnTestRegistrySession(t)
   268  	imgData := &ImgData{
   269  		ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
   270  		Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
   271  	}
   272  
   273  	err := r.PushImageJSONRegistry(imgData, []byte{0x42, 0xdf, 0x0}, makeURL("/v1/"))
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  }
   278  
   279  func TestPushImageLayerRegistry(t *testing.T) {
   280  	r := spawnTestRegistrySession(t)
   281  	layer := strings.NewReader("")
   282  	_, _, err := r.PushImageLayerRegistry(imageID, layer, makeURL("/v1/"), []byte{})
   283  	if err != nil {
   284  		t.Fatal(err)
   285  	}
   286  }
   287  
   288  func TestValidateRepositoryName(t *testing.T) {
   289  	validRepoNames := []string{
   290  		"docker/docker",
   291  		"library/debian",
   292  		"debian",
   293  		"docker.io/docker/docker",
   294  		"docker.io/library/debian",
   295  		"docker.io/debian",
   296  		"index.docker.io/docker/docker",
   297  		"index.docker.io/library/debian",
   298  		"index.docker.io/debian",
   299  		"127.0.0.1:5000/docker/docker",
   300  		"127.0.0.1:5000/library/debian",
   301  		"127.0.0.1:5000/debian",
   302  		"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
   303  	}
   304  	invalidRepoNames := []string{
   305  		"https://github.com/docker/docker",
   306  		"docker/Docker",
   307  		"-docker",
   308  		"-docker/docker",
   309  		"-docker.io/docker/docker",
   310  		"docker///docker",
   311  		"docker.io/docker/Docker",
   312  		"docker.io/docker///docker",
   313  		"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
   314  		"docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
   315  	}
   316  
   317  	for _, name := range invalidRepoNames {
   318  		err := ValidateRepositoryName(name)
   319  		assertNotEqual(t, err, nil, "Expected invalid repo name: "+name)
   320  	}
   321  
   322  	for _, name := range validRepoNames {
   323  		err := ValidateRepositoryName(name)
   324  		assertEqual(t, err, nil, "Expected valid repo name: "+name)
   325  	}
   326  
   327  	err := ValidateRepositoryName(invalidRepoNames[0])
   328  	assertEqual(t, err, ErrInvalidRepositoryName, "Expected ErrInvalidRepositoryName: "+invalidRepoNames[0])
   329  }
   330  
   331  func TestParseRepositoryInfo(t *testing.T) {
   332  	expectedRepoInfos := map[string]RepositoryInfo{
   333  		"fooo/bar": {
   334  			Index: &IndexInfo{
   335  				Name:     IndexName,
   336  				Official: true,
   337  			},
   338  			RemoteName:    "fooo/bar",
   339  			LocalName:     "fooo/bar",
   340  			CanonicalName: "docker.io/fooo/bar",
   341  			Official:      false,
   342  		},
   343  		"library/ubuntu": {
   344  			Index: &IndexInfo{
   345  				Name:     IndexName,
   346  				Official: true,
   347  			},
   348  			RemoteName:    "library/ubuntu",
   349  			LocalName:     "ubuntu",
   350  			CanonicalName: "docker.io/library/ubuntu",
   351  			Official:      true,
   352  		},
   353  		"nonlibrary/ubuntu": {
   354  			Index: &IndexInfo{
   355  				Name:     IndexName,
   356  				Official: true,
   357  			},
   358  			RemoteName:    "nonlibrary/ubuntu",
   359  			LocalName:     "nonlibrary/ubuntu",
   360  			CanonicalName: "docker.io/nonlibrary/ubuntu",
   361  			Official:      false,
   362  		},
   363  		"ubuntu": {
   364  			Index: &IndexInfo{
   365  				Name:     IndexName,
   366  				Official: true,
   367  			},
   368  			RemoteName:    "library/ubuntu",
   369  			LocalName:     "ubuntu",
   370  			CanonicalName: "docker.io/library/ubuntu",
   371  			Official:      true,
   372  		},
   373  		"other/library": {
   374  			Index: &IndexInfo{
   375  				Name:     IndexName,
   376  				Official: true,
   377  			},
   378  			RemoteName:    "other/library",
   379  			LocalName:     "other/library",
   380  			CanonicalName: "docker.io/other/library",
   381  			Official:      false,
   382  		},
   383  		"127.0.0.1:8000/private/moonbase": {
   384  			Index: &IndexInfo{
   385  				Name:     "127.0.0.1:8000",
   386  				Official: false,
   387  			},
   388  			RemoteName:    "private/moonbase",
   389  			LocalName:     "127.0.0.1:8000/private/moonbase",
   390  			CanonicalName: "127.0.0.1:8000/private/moonbase",
   391  			Official:      false,
   392  		},
   393  		"127.0.0.1:8000/privatebase": {
   394  			Index: &IndexInfo{
   395  				Name:     "127.0.0.1:8000",
   396  				Official: false,
   397  			},
   398  			RemoteName:    "privatebase",
   399  			LocalName:     "127.0.0.1:8000/privatebase",
   400  			CanonicalName: "127.0.0.1:8000/privatebase",
   401  			Official:      false,
   402  		},
   403  		"localhost:8000/private/moonbase": {
   404  			Index: &IndexInfo{
   405  				Name:     "localhost:8000",
   406  				Official: false,
   407  			},
   408  			RemoteName:    "private/moonbase",
   409  			LocalName:     "localhost:8000/private/moonbase",
   410  			CanonicalName: "localhost:8000/private/moonbase",
   411  			Official:      false,
   412  		},
   413  		"localhost:8000/privatebase": {
   414  			Index: &IndexInfo{
   415  				Name:     "localhost:8000",
   416  				Official: false,
   417  			},
   418  			RemoteName:    "privatebase",
   419  			LocalName:     "localhost:8000/privatebase",
   420  			CanonicalName: "localhost:8000/privatebase",
   421  			Official:      false,
   422  		},
   423  		"example.com/private/moonbase": {
   424  			Index: &IndexInfo{
   425  				Name:     "example.com",
   426  				Official: false,
   427  			},
   428  			RemoteName:    "private/moonbase",
   429  			LocalName:     "example.com/private/moonbase",
   430  			CanonicalName: "example.com/private/moonbase",
   431  			Official:      false,
   432  		},
   433  		"example.com/privatebase": {
   434  			Index: &IndexInfo{
   435  				Name:     "example.com",
   436  				Official: false,
   437  			},
   438  			RemoteName:    "privatebase",
   439  			LocalName:     "example.com/privatebase",
   440  			CanonicalName: "example.com/privatebase",
   441  			Official:      false,
   442  		},
   443  		"example.com:8000/private/moonbase": {
   444  			Index: &IndexInfo{
   445  				Name:     "example.com:8000",
   446  				Official: false,
   447  			},
   448  			RemoteName:    "private/moonbase",
   449  			LocalName:     "example.com:8000/private/moonbase",
   450  			CanonicalName: "example.com:8000/private/moonbase",
   451  			Official:      false,
   452  		},
   453  		"example.com:8000/privatebase": {
   454  			Index: &IndexInfo{
   455  				Name:     "example.com:8000",
   456  				Official: false,
   457  			},
   458  			RemoteName:    "privatebase",
   459  			LocalName:     "example.com:8000/privatebase",
   460  			CanonicalName: "example.com:8000/privatebase",
   461  			Official:      false,
   462  		},
   463  		"localhost/private/moonbase": {
   464  			Index: &IndexInfo{
   465  				Name:     "localhost",
   466  				Official: false,
   467  			},
   468  			RemoteName:    "private/moonbase",
   469  			LocalName:     "localhost/private/moonbase",
   470  			CanonicalName: "localhost/private/moonbase",
   471  			Official:      false,
   472  		},
   473  		"localhost/privatebase": {
   474  			Index: &IndexInfo{
   475  				Name:     "localhost",
   476  				Official: false,
   477  			},
   478  			RemoteName:    "privatebase",
   479  			LocalName:     "localhost/privatebase",
   480  			CanonicalName: "localhost/privatebase",
   481  			Official:      false,
   482  		},
   483  		IndexName + "/public/moonbase": {
   484  			Index: &IndexInfo{
   485  				Name:     IndexName,
   486  				Official: true,
   487  			},
   488  			RemoteName:    "public/moonbase",
   489  			LocalName:     "public/moonbase",
   490  			CanonicalName: "docker.io/public/moonbase",
   491  			Official:      false,
   492  		},
   493  		"index." + IndexName + "/public/moonbase": {
   494  			Index: &IndexInfo{
   495  				Name:     IndexName,
   496  				Official: true,
   497  			},
   498  			RemoteName:    "public/moonbase",
   499  			LocalName:     "public/moonbase",
   500  			CanonicalName: "docker.io/public/moonbase",
   501  			Official:      false,
   502  		},
   503  		"ubuntu-12.04-base": {
   504  			Index: &IndexInfo{
   505  				Name:     IndexName,
   506  				Official: true,
   507  			},
   508  			RemoteName:    "library/ubuntu-12.04-base",
   509  			LocalName:     "ubuntu-12.04-base",
   510  			CanonicalName: "docker.io/library/ubuntu-12.04-base",
   511  			Official:      true,
   512  		},
   513  		IndexName + "/ubuntu-12.04-base": {
   514  			Index: &IndexInfo{
   515  				Name:     IndexName,
   516  				Official: true,
   517  			},
   518  			RemoteName:    "library/ubuntu-12.04-base",
   519  			LocalName:     "ubuntu-12.04-base",
   520  			CanonicalName: "docker.io/library/ubuntu-12.04-base",
   521  			Official:      true,
   522  		},
   523  		"index." + IndexName + "/ubuntu-12.04-base": {
   524  			Index: &IndexInfo{
   525  				Name:     IndexName,
   526  				Official: true,
   527  			},
   528  			RemoteName:    "library/ubuntu-12.04-base",
   529  			LocalName:     "ubuntu-12.04-base",
   530  			CanonicalName: "docker.io/library/ubuntu-12.04-base",
   531  			Official:      true,
   532  		},
   533  	}
   534  
   535  	for reposName, expectedRepoInfo := range expectedRepoInfos {
   536  		repoInfo, err := ParseRepositoryInfo(reposName)
   537  		if err != nil {
   538  			t.Error(err)
   539  		} else {
   540  			checkEqual(t, repoInfo.Index.Name, expectedRepoInfo.Index.Name, reposName)
   541  			checkEqual(t, repoInfo.RemoteName, expectedRepoInfo.RemoteName, reposName)
   542  			checkEqual(t, repoInfo.LocalName, expectedRepoInfo.LocalName, reposName)
   543  			checkEqual(t, repoInfo.CanonicalName, expectedRepoInfo.CanonicalName, reposName)
   544  			checkEqual(t, repoInfo.Index.Official, expectedRepoInfo.Index.Official, reposName)
   545  			checkEqual(t, repoInfo.Official, expectedRepoInfo.Official, reposName)
   546  		}
   547  	}
   548  }
   549  
   550  func TestNewIndexInfo(t *testing.T) {
   551  	testIndexInfo := func(config *ServiceConfig, expectedIndexInfos map[string]*IndexInfo) {
   552  		for indexName, expectedIndexInfo := range expectedIndexInfos {
   553  			index, err := config.NewIndexInfo(indexName)
   554  			if err != nil {
   555  				t.Fatal(err)
   556  			} else {
   557  				checkEqual(t, index.Name, expectedIndexInfo.Name, indexName+" name")
   558  				checkEqual(t, index.Official, expectedIndexInfo.Official, indexName+" is official")
   559  				checkEqual(t, index.Secure, expectedIndexInfo.Secure, indexName+" is secure")
   560  				checkEqual(t, len(index.Mirrors), len(expectedIndexInfo.Mirrors), indexName+" mirrors")
   561  			}
   562  		}
   563  	}
   564  
   565  	config := NewServiceConfig(nil)
   566  	noMirrors := []string{}
   567  	expectedIndexInfos := map[string]*IndexInfo{
   568  		IndexName: {
   569  			Name:     IndexName,
   570  			Official: true,
   571  			Secure:   true,
   572  			Mirrors:  noMirrors,
   573  		},
   574  		"index." + IndexName: {
   575  			Name:     IndexName,
   576  			Official: true,
   577  			Secure:   true,
   578  			Mirrors:  noMirrors,
   579  		},
   580  		"example.com": {
   581  			Name:     "example.com",
   582  			Official: false,
   583  			Secure:   true,
   584  			Mirrors:  noMirrors,
   585  		},
   586  		"127.0.0.1:5000": {
   587  			Name:     "127.0.0.1:5000",
   588  			Official: false,
   589  			Secure:   false,
   590  			Mirrors:  noMirrors,
   591  		},
   592  	}
   593  	testIndexInfo(config, expectedIndexInfos)
   594  
   595  	publicMirrors := []string{"http://mirror1.local", "http://mirror2.local"}
   596  	config = makeServiceConfig(publicMirrors, []string{"example.com"})
   597  
   598  	expectedIndexInfos = map[string]*IndexInfo{
   599  		IndexName: {
   600  			Name:     IndexName,
   601  			Official: true,
   602  			Secure:   true,
   603  			Mirrors:  publicMirrors,
   604  		},
   605  		"index." + IndexName: {
   606  			Name:     IndexName,
   607  			Official: true,
   608  			Secure:   true,
   609  			Mirrors:  publicMirrors,
   610  		},
   611  		"example.com": {
   612  			Name:     "example.com",
   613  			Official: false,
   614  			Secure:   false,
   615  			Mirrors:  noMirrors,
   616  		},
   617  		"example.com:5000": {
   618  			Name:     "example.com:5000",
   619  			Official: false,
   620  			Secure:   true,
   621  			Mirrors:  noMirrors,
   622  		},
   623  		"127.0.0.1": {
   624  			Name:     "127.0.0.1",
   625  			Official: false,
   626  			Secure:   false,
   627  			Mirrors:  noMirrors,
   628  		},
   629  		"127.0.0.1:5000": {
   630  			Name:     "127.0.0.1:5000",
   631  			Official: false,
   632  			Secure:   false,
   633  			Mirrors:  noMirrors,
   634  		},
   635  		"other.com": {
   636  			Name:     "other.com",
   637  			Official: false,
   638  			Secure:   true,
   639  			Mirrors:  noMirrors,
   640  		},
   641  	}
   642  	testIndexInfo(config, expectedIndexInfos)
   643  
   644  	config = makeServiceConfig(nil, []string{"42.42.0.0/16"})
   645  	expectedIndexInfos = map[string]*IndexInfo{
   646  		"example.com": {
   647  			Name:     "example.com",
   648  			Official: false,
   649  			Secure:   false,
   650  			Mirrors:  noMirrors,
   651  		},
   652  		"example.com:5000": {
   653  			Name:     "example.com:5000",
   654  			Official: false,
   655  			Secure:   false,
   656  			Mirrors:  noMirrors,
   657  		},
   658  		"127.0.0.1": {
   659  			Name:     "127.0.0.1",
   660  			Official: false,
   661  			Secure:   false,
   662  			Mirrors:  noMirrors,
   663  		},
   664  		"127.0.0.1:5000": {
   665  			Name:     "127.0.0.1:5000",
   666  			Official: false,
   667  			Secure:   false,
   668  			Mirrors:  noMirrors,
   669  		},
   670  		"other.com": {
   671  			Name:     "other.com",
   672  			Official: false,
   673  			Secure:   true,
   674  			Mirrors:  noMirrors,
   675  		},
   676  	}
   677  	testIndexInfo(config, expectedIndexInfos)
   678  }
   679  
   680  func TestPushRegistryTag(t *testing.T) {
   681  	r := spawnTestRegistrySession(t)
   682  	err := r.PushRegistryTag("foo42/bar", imageID, "stable", makeURL("/v1/"))
   683  	if err != nil {
   684  		t.Fatal(err)
   685  	}
   686  }
   687  
   688  func TestPushImageJSONIndex(t *testing.T) {
   689  	r := spawnTestRegistrySession(t)
   690  	imgData := []*ImgData{
   691  		{
   692  			ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
   693  			Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
   694  		},
   695  		{
   696  			ID:       "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
   697  			Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
   698  		},
   699  	}
   700  	repoData, err := r.PushImageJSONIndex("foo42/bar", imgData, false, nil)
   701  	if err != nil {
   702  		t.Fatal(err)
   703  	}
   704  	if repoData == nil {
   705  		t.Fatal("Expected RepositoryData object")
   706  	}
   707  	repoData, err = r.PushImageJSONIndex("foo42/bar", imgData, true, []string{r.indexEndpoint.String()})
   708  	if err != nil {
   709  		t.Fatal(err)
   710  	}
   711  	if repoData == nil {
   712  		t.Fatal("Expected RepositoryData object")
   713  	}
   714  }
   715  
   716  func TestSearchRepositories(t *testing.T) {
   717  	r := spawnTestRegistrySession(t)
   718  	results, err := r.SearchRepositories("fakequery")
   719  	if err != nil {
   720  		t.Fatal(err)
   721  	}
   722  	if results == nil {
   723  		t.Fatal("Expected non-nil SearchResults object")
   724  	}
   725  	assertEqual(t, results.NumResults, 1, "Expected 1 search results")
   726  	assertEqual(t, results.Query, "fakequery", "Expected 'fakequery' as query")
   727  	assertEqual(t, results.Results[0].StarCount, 42, "Expected 'fakeimage' to have 42 stars")
   728  }
   729  
   730  func TestValidRemoteName(t *testing.T) {
   731  	validRepositoryNames := []string{
   732  		// Sanity check.
   733  		"docker/docker",
   734  
   735  		// Allow 64-character non-hexadecimal names (hexadecimal names are forbidden).
   736  		"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
   737  
   738  		// Allow embedded hyphens.
   739  		"docker-rules/docker",
   740  
   741  		//Username doc and image name docker being tested.
   742  		"doc/docker",
   743  
   744  		// single character names are now allowed.
   745  		"d/docker",
   746  		"jess/t",
   747  	}
   748  	for _, repositoryName := range validRepositoryNames {
   749  		if err := validateRemoteName(repositoryName); err != nil {
   750  			t.Errorf("Repository name should be valid: %v. Error: %v", repositoryName, err)
   751  		}
   752  	}
   753  
   754  	invalidRepositoryNames := []string{
   755  		// Disallow capital letters.
   756  		"docker/Docker",
   757  
   758  		// Only allow one slash.
   759  		"docker///docker",
   760  
   761  		// Disallow 64-character hexadecimal.
   762  		"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
   763  
   764  		// Disallow leading and trailing hyphens in namespace.
   765  		"-docker/docker",
   766  		"docker-/docker",
   767  		"-docker-/docker",
   768  
   769  		// Don't allow underscores everywhere (as opposed to hyphens).
   770  		"____/____",
   771  
   772  		"_docker/_docker",
   773  
   774  		// Disallow consecutive hyphens.
   775  		"dock--er/docker",
   776  
   777  		// No repository.
   778  		"docker/",
   779  
   780  		//namespace too long
   781  		"this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255/docker",
   782  	}
   783  	for _, repositoryName := range invalidRepositoryNames {
   784  		if err := validateRemoteName(repositoryName); err == nil {
   785  			t.Errorf("Repository name should be invalid: %v", repositoryName)
   786  		}
   787  	}
   788  }
   789  
   790  func TestTrustedLocation(t *testing.T) {
   791  	for _, url := range []string{"http://example.com", "https://example.com:7777", "http://docker.io", "http://test.docker.com", "https://fakedocker.com"} {
   792  		req, _ := http.NewRequest("GET", url, nil)
   793  		if trustedLocation(req) == true {
   794  			t.Fatalf("'%s' shouldn't be detected as a trusted location", url)
   795  		}
   796  	}
   797  
   798  	for _, url := range []string{"https://docker.io", "https://test.docker.com:80"} {
   799  		req, _ := http.NewRequest("GET", url, nil)
   800  		if trustedLocation(req) == false {
   801  			t.Fatalf("'%s' should be detected as a trusted location", url)
   802  		}
   803  	}
   804  }
   805  
   806  func TestAddRequiredHeadersToRedirectedRequests(t *testing.T) {
   807  	for _, urls := range [][]string{
   808  		{"http://docker.io", "https://docker.com"},
   809  		{"https://foo.docker.io:7777", "http://bar.docker.com"},
   810  		{"https://foo.docker.io", "https://example.com"},
   811  	} {
   812  		reqFrom, _ := http.NewRequest("GET", urls[0], nil)
   813  		reqFrom.Header.Add("Content-Type", "application/json")
   814  		reqFrom.Header.Add("Authorization", "super_secret")
   815  		reqTo, _ := http.NewRequest("GET", urls[1], nil)
   816  
   817  		addRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom})
   818  
   819  		if len(reqTo.Header) != 1 {
   820  			t.Fatalf("Expected 1 headers, got %d", len(reqTo.Header))
   821  		}
   822  
   823  		if reqTo.Header.Get("Content-Type") != "application/json" {
   824  			t.Fatal("'Content-Type' should be 'application/json'")
   825  		}
   826  
   827  		if reqTo.Header.Get("Authorization") != "" {
   828  			t.Fatal("'Authorization' should be empty")
   829  		}
   830  	}
   831  
   832  	for _, urls := range [][]string{
   833  		{"https://docker.io", "https://docker.com"},
   834  		{"https://foo.docker.io:7777", "https://bar.docker.com"},
   835  	} {
   836  		reqFrom, _ := http.NewRequest("GET", urls[0], nil)
   837  		reqFrom.Header.Add("Content-Type", "application/json")
   838  		reqFrom.Header.Add("Authorization", "super_secret")
   839  		reqTo, _ := http.NewRequest("GET", urls[1], nil)
   840  
   841  		addRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom})
   842  
   843  		if len(reqTo.Header) != 2 {
   844  			t.Fatalf("Expected 2 headers, got %d", len(reqTo.Header))
   845  		}
   846  
   847  		if reqTo.Header.Get("Content-Type") != "application/json" {
   848  			t.Fatal("'Content-Type' should be 'application/json'")
   849  		}
   850  
   851  		if reqTo.Header.Get("Authorization") != "super_secret" {
   852  			t.Fatal("'Authorization' should be 'super_secret'")
   853  		}
   854  	}
   855  }
   856  
   857  func TestIsSecureIndex(t *testing.T) {
   858  	tests := []struct {
   859  		addr               string
   860  		insecureRegistries []string
   861  		expected           bool
   862  	}{
   863  		{IndexName, nil, true},
   864  		{"example.com", []string{}, true},
   865  		{"example.com", []string{"example.com"}, false},
   866  		{"localhost", []string{"localhost:5000"}, false},
   867  		{"localhost:5000", []string{"localhost:5000"}, false},
   868  		{"localhost", []string{"example.com"}, false},
   869  		{"127.0.0.1:5000", []string{"127.0.0.1:5000"}, false},
   870  		{"localhost", nil, false},
   871  		{"localhost:5000", nil, false},
   872  		{"127.0.0.1", nil, false},
   873  		{"localhost", []string{"example.com"}, false},
   874  		{"127.0.0.1", []string{"example.com"}, false},
   875  		{"example.com", nil, true},
   876  		{"example.com", []string{"example.com"}, false},
   877  		{"127.0.0.1", []string{"example.com"}, false},
   878  		{"127.0.0.1:5000", []string{"example.com"}, false},
   879  		{"example.com:5000", []string{"42.42.0.0/16"}, false},
   880  		{"example.com", []string{"42.42.0.0/16"}, false},
   881  		{"example.com:5000", []string{"42.42.42.42/8"}, false},
   882  		{"127.0.0.1:5000", []string{"127.0.0.0/8"}, false},
   883  		{"42.42.42.42:5000", []string{"42.1.1.1/8"}, false},
   884  		{"invalid.domain.com", []string{"42.42.0.0/16"}, true},
   885  		{"invalid.domain.com", []string{"invalid.domain.com"}, false},
   886  		{"invalid.domain.com:5000", []string{"invalid.domain.com"}, true},
   887  		{"invalid.domain.com:5000", []string{"invalid.domain.com:5000"}, false},
   888  	}
   889  	for _, tt := range tests {
   890  		config := makeServiceConfig(nil, tt.insecureRegistries)
   891  		if sec := config.isSecureIndex(tt.addr); sec != tt.expected {
   892  			t.Errorf("isSecureIndex failed for %q %v, expected %v got %v", tt.addr, tt.insecureRegistries, tt.expected, sec)
   893  		}
   894  	}
   895  }
   896  
   897  type debugTransport struct {
   898  	http.RoundTripper
   899  	log func(...interface{})
   900  }
   901  
   902  func (tr debugTransport) RoundTrip(req *http.Request) (*http.Response, error) {
   903  	dump, err := httputil.DumpRequestOut(req, false)
   904  	if err != nil {
   905  		tr.log("could not dump request")
   906  	}
   907  	tr.log(string(dump))
   908  	resp, err := tr.RoundTripper.RoundTrip(req)
   909  	if err != nil {
   910  		return nil, err
   911  	}
   912  	dump, err = httputil.DumpResponse(resp, false)
   913  	if err != nil {
   914  		tr.log("could not dump response")
   915  	}
   916  	tr.log(string(dump))
   917  	return resp, err
   918  }