formatter_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. package formatter
  2. import (
  3. "bytes"
  4. "fmt"
  5. "testing"
  6. "time"
  7. "github.com/docker/docker/api/types"
  8. )
  9. func TestContainerContextWrite(t *testing.T) {
  10. unixTime := time.Now().AddDate(0, 0, -1).Unix()
  11. expectedTime := time.Unix(unixTime, 0).String()
  12. contexts := []struct {
  13. context ContainerContext
  14. expected string
  15. }{
  16. // Errors
  17. {
  18. ContainerContext{
  19. Context: Context{
  20. Format: "{{InvalidFunction}}",
  21. },
  22. },
  23. `Template parsing error: template: :1: function "InvalidFunction" not defined
  24. `,
  25. },
  26. {
  27. ContainerContext{
  28. Context: Context{
  29. Format: "{{nil}}",
  30. },
  31. },
  32. `Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
  33. `,
  34. },
  35. // Table Format
  36. {
  37. ContainerContext{
  38. Context: Context{
  39. Format: "table",
  40. },
  41. },
  42. `CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  43. containerID1 ubuntu "" 24 hours ago foobar_baz
  44. containerID2 ubuntu "" 24 hours ago foobar_bar
  45. `,
  46. },
  47. {
  48. ContainerContext{
  49. Context: Context{
  50. Format: "table {{.Image}}",
  51. },
  52. },
  53. "IMAGE\nubuntu\nubuntu\n",
  54. },
  55. {
  56. ContainerContext{
  57. Context: Context{
  58. Format: "table {{.Image}}",
  59. },
  60. Size: true,
  61. },
  62. "IMAGE SIZE\nubuntu 0 B\nubuntu 0 B\n",
  63. },
  64. {
  65. ContainerContext{
  66. Context: Context{
  67. Format: "table {{.Image}}",
  68. Quiet: true,
  69. },
  70. },
  71. "IMAGE\nubuntu\nubuntu\n",
  72. },
  73. {
  74. ContainerContext{
  75. Context: Context{
  76. Format: "table",
  77. Quiet: true,
  78. },
  79. },
  80. "containerID1\ncontainerID2\n",
  81. },
  82. // Raw Format
  83. {
  84. ContainerContext{
  85. Context: Context{
  86. Format: "raw",
  87. },
  88. },
  89. fmt.Sprintf(`container_id: containerID1
  90. image: ubuntu
  91. command: ""
  92. created_at: %s
  93. status:
  94. names: foobar_baz
  95. labels:
  96. ports:
  97. container_id: containerID2
  98. image: ubuntu
  99. command: ""
  100. created_at: %s
  101. status:
  102. names: foobar_bar
  103. labels:
  104. ports:
  105. `, expectedTime, expectedTime),
  106. },
  107. {
  108. ContainerContext{
  109. Context: Context{
  110. Format: "raw",
  111. },
  112. Size: true,
  113. },
  114. fmt.Sprintf(`container_id: containerID1
  115. image: ubuntu
  116. command: ""
  117. created_at: %s
  118. status:
  119. names: foobar_baz
  120. labels:
  121. ports:
  122. size: 0 B
  123. container_id: containerID2
  124. image: ubuntu
  125. command: ""
  126. created_at: %s
  127. status:
  128. names: foobar_bar
  129. labels:
  130. ports:
  131. size: 0 B
  132. `, expectedTime, expectedTime),
  133. },
  134. {
  135. ContainerContext{
  136. Context: Context{
  137. Format: "raw",
  138. Quiet: true,
  139. },
  140. },
  141. "container_id: containerID1\ncontainer_id: containerID2\n",
  142. },
  143. // Custom Format
  144. {
  145. ContainerContext{
  146. Context: Context{
  147. Format: "{{.Image}}",
  148. },
  149. },
  150. "ubuntu\nubuntu\n",
  151. },
  152. {
  153. ContainerContext{
  154. Context: Context{
  155. Format: "{{.Image}}",
  156. },
  157. Size: true,
  158. },
  159. "ubuntu\nubuntu\n",
  160. },
  161. }
  162. for _, context := range contexts {
  163. containers := []types.Container{
  164. {ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unixTime},
  165. {ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unixTime},
  166. }
  167. out := bytes.NewBufferString("")
  168. context.context.Output = out
  169. context.context.Containers = containers
  170. context.context.Write()
  171. actual := out.String()
  172. if actual != context.expected {
  173. t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
  174. }
  175. // Clean buffer
  176. out.Reset()
  177. }
  178. }
  179. func TestContainerContextWriteWithNoContainers(t *testing.T) {
  180. out := bytes.NewBufferString("")
  181. containers := []types.Container{}
  182. contexts := []struct {
  183. context ContainerContext
  184. expected string
  185. }{
  186. {
  187. ContainerContext{
  188. Context: Context{
  189. Format: "{{.Image}}",
  190. Output: out,
  191. },
  192. },
  193. "",
  194. },
  195. {
  196. ContainerContext{
  197. Context: Context{
  198. Format: "table {{.Image}}",
  199. Output: out,
  200. },
  201. },
  202. "IMAGE\n",
  203. },
  204. {
  205. ContainerContext{
  206. Context: Context{
  207. Format: "{{.Image}}",
  208. Output: out,
  209. },
  210. Size: true,
  211. },
  212. "",
  213. },
  214. {
  215. ContainerContext{
  216. Context: Context{
  217. Format: "table {{.Image}}",
  218. Output: out,
  219. },
  220. Size: true,
  221. },
  222. "IMAGE SIZE\n",
  223. },
  224. }
  225. for _, context := range contexts {
  226. context.context.Containers = containers
  227. context.context.Write()
  228. actual := out.String()
  229. if actual != context.expected {
  230. t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
  231. }
  232. // Clean buffer
  233. out.Reset()
  234. }
  235. }
  236. func TestImageContextWrite(t *testing.T) {
  237. unixTime := time.Now().AddDate(0, 0, -1).Unix()
  238. expectedTime := time.Unix(unixTime, 0).String()
  239. contexts := []struct {
  240. context ImageContext
  241. expected string
  242. }{
  243. // Errors
  244. {
  245. ImageContext{
  246. Context: Context{
  247. Format: "{{InvalidFunction}}",
  248. },
  249. },
  250. `Template parsing error: template: :1: function "InvalidFunction" not defined
  251. `,
  252. },
  253. {
  254. ImageContext{
  255. Context: Context{
  256. Format: "{{nil}}",
  257. },
  258. },
  259. `Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
  260. `,
  261. },
  262. // Table Format
  263. {
  264. ImageContext{
  265. Context: Context{
  266. Format: "table",
  267. },
  268. },
  269. `REPOSITORY TAG IMAGE ID CREATED SIZE
  270. image tag1 imageID1 24 hours ago 0 B
  271. image <none> imageID1 24 hours ago 0 B
  272. image tag2 imageID2 24 hours ago 0 B
  273. <none> <none> imageID3 24 hours ago 0 B
  274. `,
  275. },
  276. {
  277. ImageContext{
  278. Context: Context{
  279. Format: "table {{.Repository}}",
  280. },
  281. },
  282. "REPOSITORY\nimage\nimage\nimage\n<none>\n",
  283. },
  284. {
  285. ImageContext{
  286. Context: Context{
  287. Format: "table {{.Repository}}",
  288. },
  289. Digest: true,
  290. },
  291. `REPOSITORY DIGEST
  292. image <none>
  293. image sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
  294. image <none>
  295. <none> <none>
  296. `,
  297. },
  298. {
  299. ImageContext{
  300. Context: Context{
  301. Format: "table {{.Repository}}",
  302. Quiet: true,
  303. },
  304. },
  305. "REPOSITORY\nimage\nimage\nimage\n<none>\n",
  306. },
  307. {
  308. ImageContext{
  309. Context: Context{
  310. Format: "table",
  311. Quiet: true,
  312. },
  313. },
  314. "imageID1\nimageID1\nimageID2\nimageID3\n",
  315. },
  316. {
  317. ImageContext{
  318. Context: Context{
  319. Format: "table",
  320. Quiet: false,
  321. },
  322. Digest: true,
  323. },
  324. `REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
  325. image tag1 <none> imageID1 24 hours ago 0 B
  326. image <none> sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf imageID1 24 hours ago 0 B
  327. image tag2 <none> imageID2 24 hours ago 0 B
  328. <none> <none> <none> imageID3 24 hours ago 0 B
  329. `,
  330. },
  331. {
  332. ImageContext{
  333. Context: Context{
  334. Format: "table",
  335. Quiet: true,
  336. },
  337. Digest: true,
  338. },
  339. "imageID1\nimageID1\nimageID2\nimageID3\n",
  340. },
  341. // Raw Format
  342. {
  343. ImageContext{
  344. Context: Context{
  345. Format: "raw",
  346. },
  347. },
  348. fmt.Sprintf(`repository: image
  349. tag: tag1
  350. image_id: imageID1
  351. created_at: %s
  352. virtual_size: 0 B
  353. repository: image
  354. tag: <none>
  355. image_id: imageID1
  356. created_at: %s
  357. virtual_size: 0 B
  358. repository: image
  359. tag: tag2
  360. image_id: imageID2
  361. created_at: %s
  362. virtual_size: 0 B
  363. repository: <none>
  364. tag: <none>
  365. image_id: imageID3
  366. created_at: %s
  367. virtual_size: 0 B
  368. `, expectedTime, expectedTime, expectedTime, expectedTime),
  369. },
  370. {
  371. ImageContext{
  372. Context: Context{
  373. Format: "raw",
  374. },
  375. Digest: true,
  376. },
  377. fmt.Sprintf(`repository: image
  378. tag: tag1
  379. digest: <none>
  380. image_id: imageID1
  381. created_at: %s
  382. virtual_size: 0 B
  383. repository: image
  384. tag: <none>
  385. digest: sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
  386. image_id: imageID1
  387. created_at: %s
  388. virtual_size: 0 B
  389. repository: image
  390. tag: tag2
  391. digest: <none>
  392. image_id: imageID2
  393. created_at: %s
  394. virtual_size: 0 B
  395. repository: <none>
  396. tag: <none>
  397. digest: <none>
  398. image_id: imageID3
  399. created_at: %s
  400. virtual_size: 0 B
  401. `, expectedTime, expectedTime, expectedTime, expectedTime),
  402. },
  403. {
  404. ImageContext{
  405. Context: Context{
  406. Format: "raw",
  407. Quiet: true,
  408. },
  409. },
  410. `image_id: imageID1
  411. image_id: imageID1
  412. image_id: imageID2
  413. image_id: imageID3
  414. `,
  415. },
  416. // Custom Format
  417. {
  418. ImageContext{
  419. Context: Context{
  420. Format: "{{.Repository}}",
  421. },
  422. },
  423. "image\nimage\nimage\n<none>\n",
  424. },
  425. {
  426. ImageContext{
  427. Context: Context{
  428. Format: "{{.Repository}}",
  429. },
  430. Digest: true,
  431. },
  432. "image\nimage\nimage\n<none>\n",
  433. },
  434. }
  435. for _, context := range contexts {
  436. images := []types.Image{
  437. {ID: "imageID1", RepoTags: []string{"image:tag1"}, RepoDigests: []string{"image@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"}, Created: unixTime},
  438. {ID: "imageID2", RepoTags: []string{"image:tag2"}, Created: unixTime},
  439. {ID: "imageID3", RepoTags: []string{"<none>:<none>"}, RepoDigests: []string{"<none>@<none>"}, Created: unixTime},
  440. }
  441. out := bytes.NewBufferString("")
  442. context.context.Output = out
  443. context.context.Images = images
  444. context.context.Write()
  445. actual := out.String()
  446. if actual != context.expected {
  447. t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
  448. }
  449. // Clean buffer
  450. out.Reset()
  451. }
  452. }
  453. func TestImageContextWriteWithNoImage(t *testing.T) {
  454. out := bytes.NewBufferString("")
  455. images := []types.Image{}
  456. contexts := []struct {
  457. context ImageContext
  458. expected string
  459. }{
  460. {
  461. ImageContext{
  462. Context: Context{
  463. Format: "{{.Repository}}",
  464. Output: out,
  465. },
  466. },
  467. "",
  468. },
  469. {
  470. ImageContext{
  471. Context: Context{
  472. Format: "table {{.Repository}}",
  473. Output: out,
  474. },
  475. },
  476. "REPOSITORY\n",
  477. },
  478. {
  479. ImageContext{
  480. Context: Context{
  481. Format: "{{.Repository}}",
  482. Output: out,
  483. },
  484. Digest: true,
  485. },
  486. "",
  487. },
  488. {
  489. ImageContext{
  490. Context: Context{
  491. Format: "table {{.Repository}}",
  492. Output: out,
  493. },
  494. Digest: true,
  495. },
  496. "REPOSITORY DIGEST\n",
  497. },
  498. }
  499. for _, context := range contexts {
  500. context.context.Images = images
  501. context.context.Write()
  502. actual := out.String()
  503. if actual != context.expected {
  504. t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
  505. }
  506. // Clean buffer
  507. out.Reset()
  508. }
  509. }