image_test.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. package formatter
  2. import (
  3. "bytes"
  4. "fmt"
  5. "strings"
  6. "testing"
  7. "time"
  8. "github.com/docker/docker/api/types"
  9. "github.com/docker/docker/pkg/stringid"
  10. "github.com/docker/docker/pkg/testutil/assert"
  11. )
  12. func TestImageContext(t *testing.T) {
  13. imageID := stringid.GenerateRandomID()
  14. unix := time.Now().Unix()
  15. var ctx imageContext
  16. cases := []struct {
  17. imageCtx imageContext
  18. expValue string
  19. expHeader string
  20. call func() string
  21. }{
  22. {imageContext{
  23. i: types.ImageSummary{ID: imageID},
  24. trunc: true,
  25. }, stringid.TruncateID(imageID), imageIDHeader, ctx.ID},
  26. {imageContext{
  27. i: types.ImageSummary{ID: imageID},
  28. trunc: false,
  29. }, imageID, imageIDHeader, ctx.ID},
  30. {imageContext{
  31. i: types.ImageSummary{Size: 10, VirtualSize: 10},
  32. trunc: true,
  33. }, "10 B", sizeHeader, ctx.Size},
  34. {imageContext{
  35. i: types.ImageSummary{Created: unix},
  36. trunc: true,
  37. }, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
  38. // FIXME
  39. // {imageContext{
  40. // i: types.ImageSummary{Created: unix},
  41. // trunc: true,
  42. // }, units.HumanDuration(time.Unix(unix, 0)), createdSinceHeader, ctx.CreatedSince},
  43. {imageContext{
  44. i: types.ImageSummary{},
  45. repo: "busybox",
  46. }, "busybox", repositoryHeader, ctx.Repository},
  47. {imageContext{
  48. i: types.ImageSummary{},
  49. tag: "latest",
  50. }, "latest", tagHeader, ctx.Tag},
  51. {imageContext{
  52. i: types.ImageSummary{},
  53. digest: "sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a",
  54. }, "sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a", digestHeader, ctx.Digest},
  55. }
  56. for _, c := range cases {
  57. ctx = c.imageCtx
  58. v := c.call()
  59. if strings.Contains(v, ",") {
  60. compareMultipleValues(t, v, c.expValue)
  61. } else if v != c.expValue {
  62. t.Fatalf("Expected %s, was %s\n", c.expValue, v)
  63. }
  64. h := ctx.FullHeader()
  65. if h != c.expHeader {
  66. t.Fatalf("Expected %s, was %s\n", c.expHeader, h)
  67. }
  68. }
  69. }
  70. func TestImageContextWrite(t *testing.T) {
  71. unixTime := time.Now().AddDate(0, 0, -1).Unix()
  72. expectedTime := time.Unix(unixTime, 0).String()
  73. cases := []struct {
  74. context ImageContext
  75. expected string
  76. }{
  77. // Errors
  78. {
  79. ImageContext{
  80. Context: Context{
  81. Format: "{{InvalidFunction}}",
  82. },
  83. },
  84. `Template parsing error: template: :1: function "InvalidFunction" not defined
  85. `,
  86. },
  87. {
  88. ImageContext{
  89. Context: Context{
  90. Format: "{{nil}}",
  91. },
  92. },
  93. `Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
  94. `,
  95. },
  96. // Table Format
  97. {
  98. ImageContext{
  99. Context: Context{
  100. Format: NewImageFormat("table", false, false),
  101. },
  102. },
  103. `REPOSITORY TAG IMAGE ID CREATED SIZE
  104. image tag1 imageID1 24 hours ago 0 B
  105. image tag2 imageID2 24 hours ago 0 B
  106. <none> <none> imageID3 24 hours ago 0 B
  107. `,
  108. },
  109. {
  110. ImageContext{
  111. Context: Context{
  112. Format: NewImageFormat("table {{.Repository}}", false, false),
  113. },
  114. },
  115. "REPOSITORY\nimage\nimage\n<none>\n",
  116. },
  117. {
  118. ImageContext{
  119. Context: Context{
  120. Format: NewImageFormat("table {{.Repository}}", false, true),
  121. },
  122. Digest: true,
  123. },
  124. `REPOSITORY DIGEST
  125. image sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
  126. image <none>
  127. <none> <none>
  128. `,
  129. },
  130. {
  131. ImageContext{
  132. Context: Context{
  133. Format: NewImageFormat("table {{.Repository}}", true, false),
  134. },
  135. },
  136. "REPOSITORY\nimage\nimage\n<none>\n",
  137. },
  138. {
  139. ImageContext{
  140. Context: Context{
  141. Format: NewImageFormat("table", true, false),
  142. },
  143. },
  144. "imageID1\nimageID2\nimageID3\n",
  145. },
  146. {
  147. ImageContext{
  148. Context: Context{
  149. Format: NewImageFormat("table", false, true),
  150. },
  151. Digest: true,
  152. },
  153. `REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
  154. image tag1 sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf imageID1 24 hours ago 0 B
  155. image tag2 <none> imageID2 24 hours ago 0 B
  156. <none> <none> <none> imageID3 24 hours ago 0 B
  157. `,
  158. },
  159. {
  160. ImageContext{
  161. Context: Context{
  162. Format: NewImageFormat("table", true, true),
  163. },
  164. Digest: true,
  165. },
  166. "imageID1\nimageID2\nimageID3\n",
  167. },
  168. // Raw Format
  169. {
  170. ImageContext{
  171. Context: Context{
  172. Format: NewImageFormat("raw", false, false),
  173. },
  174. },
  175. fmt.Sprintf(`repository: image
  176. tag: tag1
  177. image_id: imageID1
  178. created_at: %s
  179. virtual_size: 0 B
  180. repository: image
  181. tag: tag2
  182. image_id: imageID2
  183. created_at: %s
  184. virtual_size: 0 B
  185. repository: <none>
  186. tag: <none>
  187. image_id: imageID3
  188. created_at: %s
  189. virtual_size: 0 B
  190. `, expectedTime, expectedTime, expectedTime),
  191. },
  192. {
  193. ImageContext{
  194. Context: Context{
  195. Format: NewImageFormat("raw", false, true),
  196. },
  197. Digest: true,
  198. },
  199. fmt.Sprintf(`repository: image
  200. tag: tag1
  201. digest: sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
  202. image_id: imageID1
  203. created_at: %s
  204. virtual_size: 0 B
  205. repository: image
  206. tag: tag2
  207. digest: <none>
  208. image_id: imageID2
  209. created_at: %s
  210. virtual_size: 0 B
  211. repository: <none>
  212. tag: <none>
  213. digest: <none>
  214. image_id: imageID3
  215. created_at: %s
  216. virtual_size: 0 B
  217. `, expectedTime, expectedTime, expectedTime),
  218. },
  219. {
  220. ImageContext{
  221. Context: Context{
  222. Format: NewImageFormat("raw", true, false),
  223. },
  224. },
  225. `image_id: imageID1
  226. image_id: imageID2
  227. image_id: imageID3
  228. `,
  229. },
  230. // Custom Format
  231. {
  232. ImageContext{
  233. Context: Context{
  234. Format: NewImageFormat("{{.Repository}}", false, false),
  235. },
  236. },
  237. "image\nimage\n<none>\n",
  238. },
  239. {
  240. ImageContext{
  241. Context: Context{
  242. Format: NewImageFormat("{{.Repository}}", false, true),
  243. },
  244. Digest: true,
  245. },
  246. "image\nimage\n<none>\n",
  247. },
  248. }
  249. for _, testcase := range cases {
  250. images := []types.ImageSummary{
  251. {ID: "imageID1", RepoTags: []string{"image:tag1"}, RepoDigests: []string{"image@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"}, Created: unixTime},
  252. {ID: "imageID2", RepoTags: []string{"image:tag2"}, Created: unixTime},
  253. {ID: "imageID3", RepoTags: []string{"<none>:<none>"}, RepoDigests: []string{"<none>@<none>"}, Created: unixTime},
  254. }
  255. out := bytes.NewBufferString("")
  256. testcase.context.Output = out
  257. err := ImageWrite(testcase.context, images)
  258. if err != nil {
  259. assert.Error(t, err, testcase.expected)
  260. } else {
  261. assert.Equal(t, out.String(), testcase.expected)
  262. }
  263. }
  264. }
  265. func TestImageContextWriteWithNoImage(t *testing.T) {
  266. out := bytes.NewBufferString("")
  267. images := []types.ImageSummary{}
  268. contexts := []struct {
  269. context ImageContext
  270. expected string
  271. }{
  272. {
  273. ImageContext{
  274. Context: Context{
  275. Format: NewImageFormat("{{.Repository}}", false, false),
  276. Output: out,
  277. },
  278. },
  279. "",
  280. },
  281. {
  282. ImageContext{
  283. Context: Context{
  284. Format: NewImageFormat("table {{.Repository}}", false, false),
  285. Output: out,
  286. },
  287. },
  288. "REPOSITORY\n",
  289. },
  290. {
  291. ImageContext{
  292. Context: Context{
  293. Format: NewImageFormat("{{.Repository}}", false, true),
  294. Output: out,
  295. },
  296. },
  297. "",
  298. },
  299. {
  300. ImageContext{
  301. Context: Context{
  302. Format: NewImageFormat("table {{.Repository}}", false, true),
  303. Output: out,
  304. },
  305. },
  306. "REPOSITORY DIGEST\n",
  307. },
  308. }
  309. for _, context := range contexts {
  310. ImageWrite(context.context, images)
  311. assert.Equal(t, out.String(), context.expected)
  312. // Clean buffer
  313. out.Reset()
  314. }
  315. }