github.com/khulnasoft/cli@v0.0.0-20240402070845-01bcad7beefa/cli/command/image/formatter_history_test.go (about) 1 package image 2 3 import ( 4 "bytes" 5 "strconv" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/docker/docker/api/types/image" 11 "github.com/docker/docker/pkg/stringid" 12 "github.com/khulnasoft/cli/cli/command/formatter" 13 "github.com/khulnasoft/cli/internal/test" 14 "gotest.tools/v3/assert" 15 ) 16 17 type historyCase struct { 18 historyCtx historyContext 19 expValue string 20 call func() string 21 } 22 23 func TestHistoryContext_ID(t *testing.T) { 24 id := stringid.GenerateRandomID() 25 26 var ctx historyContext 27 cases := []historyCase{ 28 { 29 historyContext{ 30 h: image.HistoryResponseItem{ID: id}, 31 trunc: false, 32 }, id, ctx.ID, 33 }, 34 { 35 historyContext{ 36 h: image.HistoryResponseItem{ID: id}, 37 trunc: true, 38 }, stringid.TruncateID(id), ctx.ID, 39 }, 40 } 41 42 for _, c := range cases { 43 ctx = c.historyCtx 44 v := c.call() 45 if strings.Contains(v, ",") { 46 test.CompareMultipleValues(t, v, c.expValue) 47 } else if v != c.expValue { 48 t.Fatalf("Expected %s, was %s\n", c.expValue, v) 49 } 50 } 51 } 52 53 func TestHistoryContext_CreatedSince(t *testing.T) { 54 longerAgo := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) 55 dateStr := longerAgo.Local().Format(time.RFC3339) 56 var ctx historyContext 57 cases := []historyCase{ 58 { 59 historyContext{ 60 h: image.HistoryResponseItem{Created: time.Now().AddDate(0, 0, -7).Unix()}, 61 trunc: false, 62 human: true, 63 }, "7 days ago", ctx.CreatedSince, 64 }, 65 { 66 historyContext{ 67 h: image.HistoryResponseItem{Created: longerAgo.Unix()}, 68 trunc: false, 69 human: false, 70 }, dateStr, ctx.CreatedSince, 71 }, 72 { 73 // The zero time is not displayed. 74 historyContext{ 75 h: image.HistoryResponseItem{Created: 0}, 76 trunc: false, 77 human: true, 78 }, "N/A", ctx.CreatedSince, 79 }, 80 { 81 // A time before the year 2000 is not displayed. 82 historyContext{ 83 h: image.HistoryResponseItem{Created: time.Date(1980, time.November, 10, 10, 23, 0, 0, time.UTC).Unix()}, 84 trunc: false, 85 human: true, 86 }, "N/A", ctx.CreatedSince, 87 }, 88 { 89 // A time after 2000 is displayed. 90 historyContext{ 91 h: image.HistoryResponseItem{Created: time.Now().AddDate(-11, 0, 0).Unix()}, 92 trunc: false, 93 human: true, 94 }, "11 years ago", ctx.CreatedSince, 95 }, 96 } 97 98 for _, c := range cases { 99 ctx = c.historyCtx 100 v := c.call() 101 if strings.Contains(v, ",") { 102 test.CompareMultipleValues(t, v, c.expValue) 103 } else if v != c.expValue { 104 t.Fatalf("Expected %q, was %q\n", c.expValue, v) 105 } 106 } 107 } 108 109 func TestHistoryContext_CreatedBy(t *testing.T) { 110 withTabs := `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:lll 111 expected := `/bin/sh -c apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 && echo "deb http://nginx.org/packages/mainline/debian/ jessie nginx" >> /etc/apt/sources.list && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates nginx=${NGINX_VERSION} nginx-module-xslt nginx-module-geoip nginx-module-image-filter nginx-module-perl nginx-module-njs gettext-base && rm -rf /var/lib/apt/lists/*` //nolint:lll 112 113 var ctx historyContext 114 cases := []historyCase{ 115 { 116 historyContext{ 117 h: image.HistoryResponseItem{CreatedBy: withTabs}, 118 trunc: false, 119 }, expected, ctx.CreatedBy, 120 }, 121 { 122 historyContext{ 123 h: image.HistoryResponseItem{CreatedBy: withTabs}, 124 trunc: true, 125 }, formatter.Ellipsis(expected, 45), ctx.CreatedBy, 126 }, 127 } 128 129 for _, c := range cases { 130 ctx = c.historyCtx 131 v := c.call() 132 if strings.Contains(v, ",") { 133 test.CompareMultipleValues(t, v, c.expValue) 134 } else if v != c.expValue { 135 t.Fatalf("Expected %s, was %s\n", c.expValue, v) 136 } 137 } 138 } 139 140 func TestHistoryContext_Size(t *testing.T) { 141 size := int64(182964289) 142 expected := "183MB" 143 144 var ctx historyContext 145 cases := []historyCase{ 146 { 147 historyContext{ 148 h: image.HistoryResponseItem{Size: size}, 149 trunc: false, 150 human: true, 151 }, expected, ctx.Size, 152 }, { 153 historyContext{ 154 h: image.HistoryResponseItem{Size: size}, 155 trunc: false, 156 human: false, 157 }, strconv.Itoa(182964289), ctx.Size, 158 }, 159 } 160 161 for _, c := range cases { 162 ctx = c.historyCtx 163 v := c.call() 164 if strings.Contains(v, ",") { 165 test.CompareMultipleValues(t, v, c.expValue) 166 } else if v != c.expValue { 167 t.Fatalf("Expected %s, was %s\n", c.expValue, v) 168 } 169 } 170 } 171 172 func TestHistoryContext_Comment(t *testing.T) { 173 comment := "Some comment" 174 175 var ctx historyContext 176 cases := []historyCase{ 177 { 178 historyContext{ 179 h: image.HistoryResponseItem{Comment: comment}, 180 trunc: false, 181 }, comment, ctx.Comment, 182 }, 183 } 184 185 for _, c := range cases { 186 ctx = c.historyCtx 187 v := c.call() 188 if strings.Contains(v, ",") { 189 test.CompareMultipleValues(t, v, c.expValue) 190 } else if v != c.expValue { 191 t.Fatalf("Expected %s, was %s\n", c.expValue, v) 192 } 193 } 194 } 195 196 func TestHistoryContext_Table(t *testing.T) { 197 out := bytes.NewBufferString("") 198 unixTime := time.Now().AddDate(0, 0, -1).Unix() 199 oldDate := time.Now().AddDate(-17, 0, 0).Unix() 200 histories := []image.HistoryResponseItem{ 201 { 202 ID: "imageID1", 203 Created: unixTime, 204 CreatedBy: "/bin/bash ls && npm i && npm run test && karma -c karma.conf.js start && npm start && more commands here && the list goes on", 205 Size: int64(182964289), 206 Comment: "Hi", 207 Tags: []string{"image:tag2"}, 208 }, 209 {ID: "imageID2", Created: unixTime, CreatedBy: "/bin/bash echo", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}}, 210 {ID: "imageID3", Created: unixTime, CreatedBy: "/bin/bash ls", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}}, 211 {ID: "imageID4", Created: unixTime, CreatedBy: "/bin/bash grep", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}}, 212 {ID: "imageID5", Created: 0, CreatedBy: "/bin/bash echo", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}}, 213 {ID: "imageID6", Created: oldDate, CreatedBy: "/bin/bash echo", Size: int64(182964289), Comment: "Hi", Tags: []string{"image:tag2"}}, 214 } 215 216 //nolint:dupword // ignore "Duplicate words (CREATED) found" 217 const expectedNoTrunc = `IMAGE CREATED CREATED BY SIZE COMMENT 218 imageID1 24 hours ago /bin/bash ls && npm i && npm run test && karma -c karma.conf.js start && npm start && more commands here && the list goes on 183MB Hi 219 imageID2 24 hours ago /bin/bash echo 183MB Hi 220 imageID3 24 hours ago /bin/bash ls 183MB Hi 221 imageID4 24 hours ago /bin/bash grep 183MB Hi 222 imageID5 N/A /bin/bash echo 183MB Hi 223 imageID6 17 years ago /bin/bash echo 183MB Hi 224 ` 225 //nolint:dupword // ignore "Duplicate words (CREATED) found" 226 const expectedTrunc = `IMAGE CREATED CREATED BY SIZE COMMENT 227 imageID1 24 hours ago /bin/bash ls && npm i && npm run test && kar… 183MB Hi 228 imageID2 24 hours ago /bin/bash echo 183MB Hi 229 imageID3 24 hours ago /bin/bash ls 183MB Hi 230 imageID4 24 hours ago /bin/bash grep 183MB Hi 231 imageID5 N/A /bin/bash echo 183MB Hi 232 imageID6 17 years ago /bin/bash echo 183MB Hi 233 ` 234 235 cases := []struct { 236 context formatter.Context 237 expected string 238 }{ 239 { 240 formatter.Context{ 241 Format: NewHistoryFormat("table", false, true), 242 Trunc: true, 243 Output: out, 244 }, 245 expectedTrunc, 246 }, 247 { 248 formatter.Context{ 249 Format: NewHistoryFormat("table", false, true), 250 Trunc: false, 251 Output: out, 252 }, 253 expectedNoTrunc, 254 }, 255 } 256 257 for _, tc := range cases { 258 tc := tc 259 t.Run(string(tc.context.Format), func(t *testing.T) { 260 err := HistoryWrite(tc.context, true, histories) 261 assert.NilError(t, err) 262 assert.Equal(t, out.String(), tc.expected) 263 // Clean buffer 264 out.Reset() 265 }) 266 } 267 }