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