registry_test.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. package registry
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "strings"
  7. "testing"
  8. "github.com/dotcloud/docker/utils"
  9. )
  10. var (
  11. IMAGE_ID = "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d"
  12. TOKEN = []string{"fake-token"}
  13. REPO = "foo42/bar"
  14. )
  15. func spawnTestRegistry(t *testing.T) *Registry {
  16. authConfig := &AuthConfig{}
  17. r, err := NewRegistry(authConfig, utils.NewHTTPRequestFactory(), makeURL("/v1/"), true)
  18. if err != nil {
  19. t.Fatal(err)
  20. }
  21. return r
  22. }
  23. func TestPingRegistryEndpoint(t *testing.T) {
  24. regInfo, err := pingRegistryEndpoint(makeURL("/v1/"))
  25. if err != nil {
  26. t.Fatal(err)
  27. }
  28. assertEqual(t, regInfo.Standalone, true, "Expected standalone to be true (default)")
  29. }
  30. func TestGetRemoteHistory(t *testing.T) {
  31. r := spawnTestRegistry(t)
  32. hist, err := r.GetRemoteHistory(IMAGE_ID, makeURL("/v1/"), TOKEN)
  33. if err != nil {
  34. t.Fatal(err)
  35. }
  36. assertEqual(t, len(hist), 2, "Expected 2 images in history")
  37. assertEqual(t, hist[0], IMAGE_ID, "Expected "+IMAGE_ID+"as first ancestry")
  38. assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
  39. "Unexpected second ancestry")
  40. }
  41. func TestLookupRemoteImage(t *testing.T) {
  42. r := spawnTestRegistry(t)
  43. found := r.LookupRemoteImage(IMAGE_ID, makeURL("/v1/"), TOKEN)
  44. assertEqual(t, found, true, "Expected remote lookup to succeed")
  45. found = r.LookupRemoteImage("abcdef", makeURL("/v1/"), TOKEN)
  46. assertEqual(t, found, false, "Expected remote lookup to fail")
  47. }
  48. func TestGetRemoteImageJSON(t *testing.T) {
  49. r := spawnTestRegistry(t)
  50. json, size, err := r.GetRemoteImageJSON(IMAGE_ID, makeURL("/v1/"), TOKEN)
  51. if err != nil {
  52. t.Fatal(err)
  53. }
  54. assertEqual(t, size, 154, "Expected size 154")
  55. if len(json) <= 0 {
  56. t.Fatal("Expected non-empty json")
  57. }
  58. _, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"), TOKEN)
  59. if err == nil {
  60. t.Fatal("Expected image not found error")
  61. }
  62. }
  63. func TestGetRemoteImageLayer(t *testing.T) {
  64. r := spawnTestRegistry(t)
  65. data, err := r.GetRemoteImageLayer(IMAGE_ID, makeURL("/v1/"), TOKEN, 0)
  66. if err != nil {
  67. t.Fatal(err)
  68. }
  69. if data == nil {
  70. t.Fatal("Expected non-nil data result")
  71. }
  72. _, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), TOKEN, 0)
  73. if err == nil {
  74. t.Fatal("Expected image not found error")
  75. }
  76. }
  77. func TestGetRemoteTags(t *testing.T) {
  78. r := spawnTestRegistry(t)
  79. tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO, TOKEN)
  80. if err != nil {
  81. t.Fatal(err)
  82. }
  83. assertEqual(t, len(tags), 1, "Expected one tag")
  84. assertEqual(t, tags["latest"], IMAGE_ID, "Expected tag latest to map to "+IMAGE_ID)
  85. _, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz", TOKEN)
  86. if err == nil {
  87. t.Fatal("Expected error when fetching tags for bogus repo")
  88. }
  89. }
  90. func TestGetRepositoryData(t *testing.T) {
  91. r := spawnTestRegistry(t)
  92. parsedUrl, err := url.Parse(makeURL("/v1/"))
  93. if err != nil {
  94. t.Fatal(err)
  95. }
  96. host := "http://" + parsedUrl.Host + "/v1/"
  97. data, err := r.GetRepositoryData("foo42/bar")
  98. if err != nil {
  99. t.Fatal(err)
  100. }
  101. assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList")
  102. assertEqual(t, len(data.Endpoints), 2,
  103. fmt.Sprintf("Expected 2 endpoints in Endpoints, found %d instead", len(data.Endpoints)))
  104. assertEqual(t, data.Endpoints[0], host,
  105. fmt.Sprintf("Expected first endpoint to be %s but found %s instead", host, data.Endpoints[0]))
  106. assertEqual(t, data.Endpoints[1], "http://test.example.com/v1/",
  107. fmt.Sprintf("Expected first endpoint to be http://test.example.com/v1/ but found %s instead", data.Endpoints[1]))
  108. }
  109. func TestPushImageJSONRegistry(t *testing.T) {
  110. r := spawnTestRegistry(t)
  111. imgData := &ImgData{
  112. ID: "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
  113. Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
  114. }
  115. err := r.PushImageJSONRegistry(imgData, []byte{0x42, 0xdf, 0x0}, makeURL("/v1/"), TOKEN)
  116. if err != nil {
  117. t.Fatal(err)
  118. }
  119. }
  120. func TestPushImageLayerRegistry(t *testing.T) {
  121. r := spawnTestRegistry(t)
  122. layer := strings.NewReader("")
  123. _, _, err := r.PushImageLayerRegistry(IMAGE_ID, layer, makeURL("/v1/"), TOKEN, []byte{})
  124. if err != nil {
  125. t.Fatal(err)
  126. }
  127. }
  128. func TestResolveRepositoryName(t *testing.T) {
  129. _, _, err := ResolveRepositoryName("https://github.com/dotcloud/docker")
  130. assertEqual(t, err, ErrInvalidRepositoryName, "Expected error invalid repo name")
  131. ep, repo, err := ResolveRepositoryName("fooo/bar")
  132. if err != nil {
  133. t.Fatal(err)
  134. }
  135. assertEqual(t, ep, IndexServerAddress(), "Expected endpoint to be index server address")
  136. assertEqual(t, repo, "fooo/bar", "Expected resolved repo to be foo/bar")
  137. u := makeURL("")[7:]
  138. ep, repo, err = ResolveRepositoryName(u + "/private/moonbase")
  139. if err != nil {
  140. t.Fatal(err)
  141. }
  142. assertEqual(t, ep, u, "Expected endpoint to be "+u)
  143. assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase")
  144. ep, repo, err = ResolveRepositoryName("ubuntu-12.04-base")
  145. if err != nil {
  146. t.Fatal(err)
  147. }
  148. assertEqual(t, ep, IndexServerAddress(), "Expected endpoint to be "+IndexServerAddress())
  149. assertEqual(t, repo, "ubuntu-12.04-base", "Expected endpoint to be ubuntu-12.04-base")
  150. }
  151. func TestPushRegistryTag(t *testing.T) {
  152. r := spawnTestRegistry(t)
  153. err := r.PushRegistryTag("foo42/bar", IMAGE_ID, "stable", makeURL("/v1/"), TOKEN)
  154. if err != nil {
  155. t.Fatal(err)
  156. }
  157. }
  158. func TestPushImageJSONIndex(t *testing.T) {
  159. r := spawnTestRegistry(t)
  160. imgData := []*ImgData{
  161. {
  162. ID: "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
  163. Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
  164. },
  165. {
  166. ID: "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
  167. Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
  168. },
  169. }
  170. repoData, err := r.PushImageJSONIndex("foo42/bar", imgData, false, nil)
  171. if err != nil {
  172. t.Fatal(err)
  173. }
  174. if repoData == nil {
  175. t.Fatal("Expected RepositoryData object")
  176. }
  177. repoData, err = r.PushImageJSONIndex("foo42/bar", imgData, true, []string{r.indexEndpoint})
  178. if err != nil {
  179. t.Fatal(err)
  180. }
  181. if repoData == nil {
  182. t.Fatal("Expected RepositoryData object")
  183. }
  184. }
  185. func TestSearchRepositories(t *testing.T) {
  186. r := spawnTestRegistry(t)
  187. results, err := r.SearchRepositories("fakequery")
  188. if err != nil {
  189. t.Fatal(err)
  190. }
  191. if results == nil {
  192. t.Fatal("Expected non-nil SearchResults object")
  193. }
  194. assertEqual(t, results.NumResults, 1, "Expected 1 search results")
  195. assertEqual(t, results.Query, "fakequery", "Expected 'fakequery' as query")
  196. assertEqual(t, results.Results[0].StarCount, 42, "Expected 'fakeimage' a ot hae 42 stars")
  197. }
  198. func TestValidRepositoryName(t *testing.T) {
  199. if err := validateRepositoryName("docker/docker"); err != nil {
  200. t.Fatal(err)
  201. }
  202. if err := validateRepositoryName("docker/Docker"); err == nil {
  203. t.Log("Repository name should be invalid")
  204. t.Fail()
  205. }
  206. if err := validateRepositoryName("docker///docker"); err == nil {
  207. t.Log("Repository name should be invalid")
  208. t.Fail()
  209. }
  210. }
  211. func TestTrustedLocation(t *testing.T) {
  212. for _, url := range []string{"http://example.com", "https://example.com:7777", "http://docker.io", "http://test.docker.io", "https://fakedocker.com"} {
  213. req, _ := http.NewRequest("GET", url, nil)
  214. if trustedLocation(req) == true {
  215. t.Fatalf("'%s' shouldn't be detected as a trusted location", url)
  216. }
  217. }
  218. for _, url := range []string{"https://docker.io", "https://test.docker.io:80"} {
  219. req, _ := http.NewRequest("GET", url, nil)
  220. if trustedLocation(req) == false {
  221. t.Fatalf("'%s' should be detected as a trusted location", url)
  222. }
  223. }
  224. }
  225. func TestAddRequiredHeadersToRedirectedRequests(t *testing.T) {
  226. for _, urls := range [][]string{
  227. {"http://docker.io", "https://docker.com"},
  228. {"https://foo.docker.io:7777", "http://bar.docker.com"},
  229. {"https://foo.docker.io", "https://example.com"},
  230. } {
  231. reqFrom, _ := http.NewRequest("GET", urls[0], nil)
  232. reqFrom.Header.Add("Content-Type", "application/json")
  233. reqFrom.Header.Add("Authorization", "super_secret")
  234. reqTo, _ := http.NewRequest("GET", urls[1], nil)
  235. AddRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom})
  236. if len(reqTo.Header) != 1 {
  237. t.Fatalf("Expected 1 headers, got %d", len(reqTo.Header))
  238. }
  239. if reqTo.Header.Get("Content-Type") != "application/json" {
  240. t.Fatal("'Content-Type' should be 'application/json'")
  241. }
  242. if reqTo.Header.Get("Authorization") != "" {
  243. t.Fatal("'Authorization' should be empty")
  244. }
  245. }
  246. for _, urls := range [][]string{
  247. {"https://docker.io", "https://docker.com"},
  248. {"https://foo.docker.io:7777", "https://bar.docker.com"},
  249. } {
  250. reqFrom, _ := http.NewRequest("GET", urls[0], nil)
  251. reqFrom.Header.Add("Content-Type", "application/json")
  252. reqFrom.Header.Add("Authorization", "super_secret")
  253. reqTo, _ := http.NewRequest("GET", urls[1], nil)
  254. AddRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom})
  255. if len(reqTo.Header) != 2 {
  256. t.Fatalf("Expected 2 headers, got %d", len(reqTo.Header))
  257. }
  258. if reqTo.Header.Get("Content-Type") != "application/json" {
  259. t.Fatal("'Content-Type' should be 'application/json'")
  260. }
  261. if reqTo.Header.Get("Authorization") != "super_secret" {
  262. t.Fatal("'Authorization' should be 'super_secret'")
  263. }
  264. }
  265. }