formatter_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. package formatter
  2. import (
  3. "bytes"
  4. "fmt"
  5. "testing"
  6. "time"
  7. "github.com/docker/engine-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\nubuntu\nubuntu\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\n",
  223. },
  224. {
  225. ContainerContext{
  226. Context: Context{
  227. Format: "table {{.Image}}\t{{.Size}}",
  228. Output: out,
  229. },
  230. },
  231. "IMAGE SIZE\n",
  232. },
  233. {
  234. ContainerContext{
  235. Context: Context{
  236. Format: "table {{.Image}}\t{{.Size}}",
  237. Output: out,
  238. },
  239. Size: true,
  240. },
  241. "IMAGE SIZE\n",
  242. },
  243. }
  244. for _, context := range contexts {
  245. context.context.Containers = containers
  246. context.context.Write()
  247. actual := out.String()
  248. if actual != context.expected {
  249. t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
  250. }
  251. // Clean buffer
  252. out.Reset()
  253. }
  254. }
  255. func TestImageContextWrite(t *testing.T) {
  256. unixTime := time.Now().AddDate(0, 0, -1).Unix()
  257. expectedTime := time.Unix(unixTime, 0).String()
  258. contexts := []struct {
  259. context ImageContext
  260. expected string
  261. }{
  262. // Errors
  263. {
  264. ImageContext{
  265. Context: Context{
  266. Format: "{{InvalidFunction}}",
  267. },
  268. },
  269. `Template parsing error: template: :1: function "InvalidFunction" not defined
  270. `,
  271. },
  272. {
  273. ImageContext{
  274. Context: Context{
  275. Format: "{{nil}}",
  276. },
  277. },
  278. `Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
  279. `,
  280. },
  281. // Table Format
  282. {
  283. ImageContext{
  284. Context: Context{
  285. Format: "table",
  286. },
  287. },
  288. `REPOSITORY TAG IMAGE ID CREATED SIZE
  289. image tag1 imageID1 24 hours ago 0 B
  290. image tag2 imageID2 24 hours ago 0 B
  291. <none> <none> imageID3 24 hours ago 0 B
  292. `,
  293. },
  294. {
  295. ImageContext{
  296. Context: Context{
  297. Format: "table {{.Repository}}",
  298. },
  299. },
  300. "REPOSITORY\nimage\nimage\n<none>\n",
  301. },
  302. {
  303. ImageContext{
  304. Context: Context{
  305. Format: "table {{.Repository}}",
  306. },
  307. Digest: true,
  308. },
  309. `REPOSITORY DIGEST
  310. image sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
  311. image <none>
  312. <none> <none>
  313. `,
  314. },
  315. {
  316. ImageContext{
  317. Context: Context{
  318. Format: "table {{.Repository}}",
  319. Quiet: true,
  320. },
  321. },
  322. "REPOSITORY\nimage\nimage\n<none>\n",
  323. },
  324. {
  325. ImageContext{
  326. Context: Context{
  327. Format: "table",
  328. Quiet: true,
  329. },
  330. },
  331. "imageID1\nimageID2\nimageID3\n",
  332. },
  333. {
  334. ImageContext{
  335. Context: Context{
  336. Format: "table",
  337. Quiet: false,
  338. },
  339. Digest: true,
  340. },
  341. `REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
  342. image tag1 sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf imageID1 24 hours ago 0 B
  343. image tag2 <none> imageID2 24 hours ago 0 B
  344. <none> <none> <none> imageID3 24 hours ago 0 B
  345. `,
  346. },
  347. {
  348. ImageContext{
  349. Context: Context{
  350. Format: "table",
  351. Quiet: true,
  352. },
  353. Digest: true,
  354. },
  355. "imageID1\nimageID2\nimageID3\n",
  356. },
  357. // Raw Format
  358. {
  359. ImageContext{
  360. Context: Context{
  361. Format: "raw",
  362. },
  363. },
  364. fmt.Sprintf(`repository: image
  365. tag: tag1
  366. image_id: imageID1
  367. created_at: %s
  368. virtual_size: 0 B
  369. repository: image
  370. tag: tag2
  371. image_id: imageID2
  372. created_at: %s
  373. virtual_size: 0 B
  374. repository: <none>
  375. tag: <none>
  376. image_id: imageID3
  377. created_at: %s
  378. virtual_size: 0 B
  379. `, expectedTime, expectedTime, expectedTime),
  380. },
  381. {
  382. ImageContext{
  383. Context: Context{
  384. Format: "raw",
  385. },
  386. Digest: true,
  387. },
  388. fmt.Sprintf(`repository: image
  389. tag: tag1
  390. digest: sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
  391. image_id: imageID1
  392. created_at: %s
  393. virtual_size: 0 B
  394. repository: image
  395. tag: tag2
  396. digest: <none>
  397. image_id: imageID2
  398. created_at: %s
  399. virtual_size: 0 B
  400. repository: <none>
  401. tag: <none>
  402. digest: <none>
  403. image_id: imageID3
  404. created_at: %s
  405. virtual_size: 0 B
  406. `, expectedTime, expectedTime, expectedTime),
  407. },
  408. {
  409. ImageContext{
  410. Context: Context{
  411. Format: "raw",
  412. Quiet: true,
  413. },
  414. },
  415. `image_id: imageID1
  416. image_id: imageID2
  417. image_id: imageID3
  418. `,
  419. },
  420. // Custom Format
  421. {
  422. ImageContext{
  423. Context: Context{
  424. Format: "{{.Repository}}",
  425. },
  426. },
  427. "image\nimage\n<none>\n",
  428. },
  429. {
  430. ImageContext{
  431. Context: Context{
  432. Format: "{{.Repository}}",
  433. },
  434. Digest: true,
  435. },
  436. "image\nimage\n<none>\n",
  437. },
  438. }
  439. for _, context := range contexts {
  440. images := []types.Image{
  441. {ID: "imageID1", RepoTags: []string{"image:tag1"}, RepoDigests: []string{"image@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"}, Created: unixTime},
  442. {ID: "imageID2", RepoTags: []string{"image:tag2"}, Created: unixTime},
  443. {ID: "imageID3", RepoTags: []string{"<none>:<none>"}, RepoDigests: []string{"<none>@<none>"}, Created: unixTime},
  444. }
  445. out := bytes.NewBufferString("")
  446. context.context.Output = out
  447. context.context.Images = images
  448. context.context.Write()
  449. actual := out.String()
  450. if actual != context.expected {
  451. t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
  452. }
  453. // Clean buffer
  454. out.Reset()
  455. }
  456. }
  457. func TestImageContextWriteWithNoImage(t *testing.T) {
  458. out := bytes.NewBufferString("")
  459. images := []types.Image{}
  460. contexts := []struct {
  461. context ImageContext
  462. expected string
  463. }{
  464. {
  465. ImageContext{
  466. Context: Context{
  467. Format: "{{.Repository}}",
  468. Output: out,
  469. },
  470. },
  471. "",
  472. },
  473. {
  474. ImageContext{
  475. Context: Context{
  476. Format: "table {{.Repository}}",
  477. Output: out,
  478. },
  479. },
  480. "REPOSITORY\n",
  481. },
  482. {
  483. ImageContext{
  484. Context: Context{
  485. Format: "{{.Repository}}",
  486. Output: out,
  487. },
  488. Digest: true,
  489. },
  490. "",
  491. },
  492. {
  493. ImageContext{
  494. Context: Context{
  495. Format: "table {{.Repository}}",
  496. Output: out,
  497. },
  498. Digest: true,
  499. },
  500. "REPOSITORY DIGEST\n",
  501. },
  502. }
  503. for _, context := range contexts {
  504. context.context.Images = images
  505. context.context.Write()
  506. actual := out.String()
  507. if actual != context.expected {
  508. t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
  509. }
  510. // Clean buffer
  511. out.Reset()
  512. }
  513. }