config_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. package cliconfig
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. "testing"
  8. "github.com/docker/docker/cliconfig/configfile"
  9. "github.com/docker/docker/pkg/homedir"
  10. )
  11. func TestEmptyConfigDir(t *testing.T) {
  12. tmpHome, err := ioutil.TempDir("", "config-test")
  13. if err != nil {
  14. t.Fatal(err)
  15. }
  16. defer os.RemoveAll(tmpHome)
  17. SetConfigDir(tmpHome)
  18. config, err := Load("")
  19. if err != nil {
  20. t.Fatalf("Failed loading on empty config dir: %q", err)
  21. }
  22. expectedConfigFilename := filepath.Join(tmpHome, ConfigFileName)
  23. if config.Filename != expectedConfigFilename {
  24. t.Fatalf("Expected config filename %s, got %s", expectedConfigFilename, config.Filename)
  25. }
  26. // Now save it and make sure it shows up in new form
  27. saveConfigAndValidateNewFormat(t, config, tmpHome)
  28. }
  29. func TestMissingFile(t *testing.T) {
  30. tmpHome, err := ioutil.TempDir("", "config-test")
  31. if err != nil {
  32. t.Fatal(err)
  33. }
  34. defer os.RemoveAll(tmpHome)
  35. config, err := Load(tmpHome)
  36. if err != nil {
  37. t.Fatalf("Failed loading on missing file: %q", err)
  38. }
  39. // Now save it and make sure it shows up in new form
  40. saveConfigAndValidateNewFormat(t, config, tmpHome)
  41. }
  42. func TestSaveFileToDirs(t *testing.T) {
  43. tmpHome, err := ioutil.TempDir("", "config-test")
  44. if err != nil {
  45. t.Fatal(err)
  46. }
  47. defer os.RemoveAll(tmpHome)
  48. tmpHome += "/.docker"
  49. config, err := Load(tmpHome)
  50. if err != nil {
  51. t.Fatalf("Failed loading on missing file: %q", err)
  52. }
  53. // Now save it and make sure it shows up in new form
  54. saveConfigAndValidateNewFormat(t, config, tmpHome)
  55. }
  56. func TestEmptyFile(t *testing.T) {
  57. tmpHome, err := ioutil.TempDir("", "config-test")
  58. if err != nil {
  59. t.Fatal(err)
  60. }
  61. defer os.RemoveAll(tmpHome)
  62. fn := filepath.Join(tmpHome, ConfigFileName)
  63. if err := ioutil.WriteFile(fn, []byte(""), 0600); err != nil {
  64. t.Fatal(err)
  65. }
  66. _, err = Load(tmpHome)
  67. if err == nil {
  68. t.Fatalf("Was supposed to fail")
  69. }
  70. }
  71. func TestEmptyJson(t *testing.T) {
  72. tmpHome, err := ioutil.TempDir("", "config-test")
  73. if err != nil {
  74. t.Fatal(err)
  75. }
  76. defer os.RemoveAll(tmpHome)
  77. fn := filepath.Join(tmpHome, ConfigFileName)
  78. if err := ioutil.WriteFile(fn, []byte("{}"), 0600); err != nil {
  79. t.Fatal(err)
  80. }
  81. config, err := Load(tmpHome)
  82. if err != nil {
  83. t.Fatalf("Failed loading on empty json file: %q", err)
  84. }
  85. // Now save it and make sure it shows up in new form
  86. saveConfigAndValidateNewFormat(t, config, tmpHome)
  87. }
  88. func TestOldInvalidsAuth(t *testing.T) {
  89. invalids := map[string]string{
  90. `username = test`: "The Auth config file is empty",
  91. `username
  92. password`: "Invalid Auth config file",
  93. `username = test
  94. email`: "Invalid auth configuration file",
  95. }
  96. tmpHome, err := ioutil.TempDir("", "config-test")
  97. if err != nil {
  98. t.Fatal(err)
  99. }
  100. defer os.RemoveAll(tmpHome)
  101. homeKey := homedir.Key()
  102. homeVal := homedir.Get()
  103. defer func() { os.Setenv(homeKey, homeVal) }()
  104. os.Setenv(homeKey, tmpHome)
  105. for content, expectedError := range invalids {
  106. fn := filepath.Join(tmpHome, oldConfigfile)
  107. if err := ioutil.WriteFile(fn, []byte(content), 0600); err != nil {
  108. t.Fatal(err)
  109. }
  110. config, err := Load(tmpHome)
  111. // Use Contains instead of == since the file name will change each time
  112. if err == nil || !strings.Contains(err.Error(), expectedError) {
  113. t.Fatalf("Should have failed\nConfig: %v\nGot: %v\nExpected: %v", config, err, expectedError)
  114. }
  115. }
  116. }
  117. func TestOldValidAuth(t *testing.T) {
  118. tmpHome, err := ioutil.TempDir("", "config-test")
  119. if err != nil {
  120. t.Fatal(err)
  121. }
  122. if err != nil {
  123. t.Fatal(err)
  124. }
  125. defer os.RemoveAll(tmpHome)
  126. homeKey := homedir.Key()
  127. homeVal := homedir.Get()
  128. defer func() { os.Setenv(homeKey, homeVal) }()
  129. os.Setenv(homeKey, tmpHome)
  130. fn := filepath.Join(tmpHome, oldConfigfile)
  131. js := `username = am9lam9lOmhlbGxv
  132. email = user@example.com`
  133. if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
  134. t.Fatal(err)
  135. }
  136. config, err := Load(tmpHome)
  137. if err != nil {
  138. t.Fatal(err)
  139. }
  140. // defaultIndexserver is https://index.docker.io/v1/
  141. ac := config.AuthConfigs["https://index.docker.io/v1/"]
  142. if ac.Username != "joejoe" || ac.Password != "hello" {
  143. t.Fatalf("Missing data from parsing:\n%q", config)
  144. }
  145. // Now save it and make sure it shows up in new form
  146. configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
  147. expConfStr := `{
  148. "auths": {
  149. "https://index.docker.io/v1/": {
  150. "auth": "am9lam9lOmhlbGxv"
  151. }
  152. }
  153. }`
  154. if configStr != expConfStr {
  155. t.Fatalf("Should have save in new form: \n%s\n not \n%s", configStr, expConfStr)
  156. }
  157. }
  158. func TestOldJsonInvalid(t *testing.T) {
  159. tmpHome, err := ioutil.TempDir("", "config-test")
  160. if err != nil {
  161. t.Fatal(err)
  162. }
  163. defer os.RemoveAll(tmpHome)
  164. homeKey := homedir.Key()
  165. homeVal := homedir.Get()
  166. defer func() { os.Setenv(homeKey, homeVal) }()
  167. os.Setenv(homeKey, tmpHome)
  168. fn := filepath.Join(tmpHome, oldConfigfile)
  169. js := `{"https://index.docker.io/v1/":{"auth":"test","email":"user@example.com"}}`
  170. if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
  171. t.Fatal(err)
  172. }
  173. config, err := Load(tmpHome)
  174. // Use Contains instead of == since the file name will change each time
  175. if err == nil || !strings.Contains(err.Error(), "Invalid auth configuration file") {
  176. t.Fatalf("Expected an error got : %v, %v", config, err)
  177. }
  178. }
  179. func TestOldJson(t *testing.T) {
  180. tmpHome, err := ioutil.TempDir("", "config-test")
  181. if err != nil {
  182. t.Fatal(err)
  183. }
  184. defer os.RemoveAll(tmpHome)
  185. homeKey := homedir.Key()
  186. homeVal := homedir.Get()
  187. defer func() { os.Setenv(homeKey, homeVal) }()
  188. os.Setenv(homeKey, tmpHome)
  189. fn := filepath.Join(tmpHome, oldConfigfile)
  190. js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
  191. if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
  192. t.Fatal(err)
  193. }
  194. config, err := Load(tmpHome)
  195. if err != nil {
  196. t.Fatalf("Failed loading on empty json file: %q", err)
  197. }
  198. ac := config.AuthConfigs["https://index.docker.io/v1/"]
  199. if ac.Username != "joejoe" || ac.Password != "hello" {
  200. t.Fatalf("Missing data from parsing:\n%q", config)
  201. }
  202. // Now save it and make sure it shows up in new form
  203. configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
  204. expConfStr := `{
  205. "auths": {
  206. "https://index.docker.io/v1/": {
  207. "auth": "am9lam9lOmhlbGxv",
  208. "email": "user@example.com"
  209. }
  210. }
  211. }`
  212. if configStr != expConfStr {
  213. t.Fatalf("Should have save in new form: \n'%s'\n not \n'%s'\n", configStr, expConfStr)
  214. }
  215. }
  216. func TestNewJson(t *testing.T) {
  217. tmpHome, err := ioutil.TempDir("", "config-test")
  218. if err != nil {
  219. t.Fatal(err)
  220. }
  221. defer os.RemoveAll(tmpHome)
  222. fn := filepath.Join(tmpHome, ConfigFileName)
  223. js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv" } } }`
  224. if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
  225. t.Fatal(err)
  226. }
  227. config, err := Load(tmpHome)
  228. if err != nil {
  229. t.Fatalf("Failed loading on empty json file: %q", err)
  230. }
  231. ac := config.AuthConfigs["https://index.docker.io/v1/"]
  232. if ac.Username != "joejoe" || ac.Password != "hello" {
  233. t.Fatalf("Missing data from parsing:\n%q", config)
  234. }
  235. // Now save it and make sure it shows up in new form
  236. configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
  237. expConfStr := `{
  238. "auths": {
  239. "https://index.docker.io/v1/": {
  240. "auth": "am9lam9lOmhlbGxv"
  241. }
  242. }
  243. }`
  244. if configStr != expConfStr {
  245. t.Fatalf("Should have save in new form: \n%s\n not \n%s", configStr, expConfStr)
  246. }
  247. }
  248. func TestNewJsonNoEmail(t *testing.T) {
  249. tmpHome, err := ioutil.TempDir("", "config-test")
  250. if err != nil {
  251. t.Fatal(err)
  252. }
  253. defer os.RemoveAll(tmpHome)
  254. fn := filepath.Join(tmpHome, ConfigFileName)
  255. js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv" } } }`
  256. if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
  257. t.Fatal(err)
  258. }
  259. config, err := Load(tmpHome)
  260. if err != nil {
  261. t.Fatalf("Failed loading on empty json file: %q", err)
  262. }
  263. ac := config.AuthConfigs["https://index.docker.io/v1/"]
  264. if ac.Username != "joejoe" || ac.Password != "hello" {
  265. t.Fatalf("Missing data from parsing:\n%q", config)
  266. }
  267. // Now save it and make sure it shows up in new form
  268. configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
  269. expConfStr := `{
  270. "auths": {
  271. "https://index.docker.io/v1/": {
  272. "auth": "am9lam9lOmhlbGxv"
  273. }
  274. }
  275. }`
  276. if configStr != expConfStr {
  277. t.Fatalf("Should have save in new form: \n%s\n not \n%s", configStr, expConfStr)
  278. }
  279. }
  280. func TestJsonWithPsFormat(t *testing.T) {
  281. tmpHome, err := ioutil.TempDir("", "config-test")
  282. if err != nil {
  283. t.Fatal(err)
  284. }
  285. defer os.RemoveAll(tmpHome)
  286. fn := filepath.Join(tmpHome, ConfigFileName)
  287. js := `{
  288. "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
  289. "psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
  290. }`
  291. if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
  292. t.Fatal(err)
  293. }
  294. config, err := Load(tmpHome)
  295. if err != nil {
  296. t.Fatalf("Failed loading on empty json file: %q", err)
  297. }
  298. if config.PsFormat != `table {{.ID}}\t{{.Label "com.docker.label.cpu"}}` {
  299. t.Fatalf("Unknown ps format: %s\n", config.PsFormat)
  300. }
  301. // Now save it and make sure it shows up in new form
  302. configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
  303. if !strings.Contains(configStr, `"psFormat":`) ||
  304. !strings.Contains(configStr, "{{.ID}}") {
  305. t.Fatalf("Should have save in new form: %s", configStr)
  306. }
  307. }
  308. // Save it and make sure it shows up in new form
  309. func saveConfigAndValidateNewFormat(t *testing.T, config *configfile.ConfigFile, homeFolder string) string {
  310. if err := config.Save(); err != nil {
  311. t.Fatalf("Failed to save: %q", err)
  312. }
  313. buf, err := ioutil.ReadFile(filepath.Join(homeFolder, ConfigFileName))
  314. if err != nil {
  315. t.Fatal(err)
  316. }
  317. if !strings.Contains(string(buf), `"auths":`) {
  318. t.Fatalf("Should have save in new form: %s", string(buf))
  319. }
  320. return string(buf)
  321. }
  322. func TestConfigDir(t *testing.T) {
  323. tmpHome, err := ioutil.TempDir("", "config-test")
  324. if err != nil {
  325. t.Fatal(err)
  326. }
  327. defer os.RemoveAll(tmpHome)
  328. if ConfigDir() == tmpHome {
  329. t.Fatalf("Expected ConfigDir to be different than %s by default, but was the same", tmpHome)
  330. }
  331. // Update configDir
  332. SetConfigDir(tmpHome)
  333. if ConfigDir() != tmpHome {
  334. t.Fatalf("Expected ConfigDir to %s, but was %s", tmpHome, ConfigDir())
  335. }
  336. }
  337. func TestConfigFile(t *testing.T) {
  338. configFilename := "configFilename"
  339. configFile := NewConfigFile(configFilename)
  340. if configFile.Filename != configFilename {
  341. t.Fatalf("Expected %s, got %s", configFilename, configFile.Filename)
  342. }
  343. }
  344. func TestJsonReaderNoFile(t *testing.T) {
  345. js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } }`
  346. config, err := LoadFromReader(strings.NewReader(js))
  347. if err != nil {
  348. t.Fatalf("Failed loading on empty json file: %q", err)
  349. }
  350. ac := config.AuthConfigs["https://index.docker.io/v1/"]
  351. if ac.Username != "joejoe" || ac.Password != "hello" {
  352. t.Fatalf("Missing data from parsing:\n%q", config)
  353. }
  354. }
  355. func TestOldJsonReaderNoFile(t *testing.T) {
  356. js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
  357. config, err := LegacyLoadFromReader(strings.NewReader(js))
  358. if err != nil {
  359. t.Fatalf("Failed loading on empty json file: %q", err)
  360. }
  361. ac := config.AuthConfigs["https://index.docker.io/v1/"]
  362. if ac.Username != "joejoe" || ac.Password != "hello" {
  363. t.Fatalf("Missing data from parsing:\n%q", config)
  364. }
  365. }
  366. func TestJsonWithPsFormatNoFile(t *testing.T) {
  367. js := `{
  368. "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
  369. "psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
  370. }`
  371. config, err := LoadFromReader(strings.NewReader(js))
  372. if err != nil {
  373. t.Fatalf("Failed loading on empty json file: %q", err)
  374. }
  375. if config.PsFormat != `table {{.ID}}\t{{.Label "com.docker.label.cpu"}}` {
  376. t.Fatalf("Unknown ps format: %s\n", config.PsFormat)
  377. }
  378. }
  379. func TestJsonSaveWithNoFile(t *testing.T) {
  380. js := `{
  381. "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv" } },
  382. "psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
  383. }`
  384. config, err := LoadFromReader(strings.NewReader(js))
  385. err = config.Save()
  386. if err == nil {
  387. t.Fatalf("Expected error. File should not have been able to save with no file name.")
  388. }
  389. tmpHome, err := ioutil.TempDir("", "config-test")
  390. if err != nil {
  391. t.Fatalf("Failed to create a temp dir: %q", err)
  392. }
  393. defer os.RemoveAll(tmpHome)
  394. fn := filepath.Join(tmpHome, ConfigFileName)
  395. f, _ := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
  396. err = config.SaveToWriter(f)
  397. if err != nil {
  398. t.Fatalf("Failed saving to file: %q", err)
  399. }
  400. buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
  401. if err != nil {
  402. t.Fatal(err)
  403. }
  404. expConfStr := `{
  405. "auths": {
  406. "https://index.docker.io/v1/": {
  407. "auth": "am9lam9lOmhlbGxv"
  408. }
  409. },
  410. "psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
  411. }`
  412. if string(buf) != expConfStr {
  413. t.Fatalf("Should have save in new form: \n%s\nnot \n%s", string(buf), expConfStr)
  414. }
  415. }
  416. func TestLegacyJsonSaveWithNoFile(t *testing.T) {
  417. js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
  418. config, err := LegacyLoadFromReader(strings.NewReader(js))
  419. err = config.Save()
  420. if err == nil {
  421. t.Fatalf("Expected error. File should not have been able to save with no file name.")
  422. }
  423. tmpHome, err := ioutil.TempDir("", "config-test")
  424. if err != nil {
  425. t.Fatalf("Failed to create a temp dir: %q", err)
  426. }
  427. defer os.RemoveAll(tmpHome)
  428. fn := filepath.Join(tmpHome, ConfigFileName)
  429. f, _ := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
  430. if err = config.SaveToWriter(f); err != nil {
  431. t.Fatalf("Failed saving to file: %q", err)
  432. }
  433. buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
  434. if err != nil {
  435. t.Fatal(err)
  436. }
  437. expConfStr := `{
  438. "auths": {
  439. "https://index.docker.io/v1/": {
  440. "auth": "am9lam9lOmhlbGxv",
  441. "email": "user@example.com"
  442. }
  443. }
  444. }`
  445. if string(buf) != expConfStr {
  446. t.Fatalf("Should have save in new form: \n%s\n not \n%s", string(buf), expConfStr)
  447. }
  448. }