github.com/ld86/docker@v1.7.1-rc3/registry/registry_test.go (about)

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