github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/pkg/jsonmessage/jsonmessage_test.go (about) 1 package jsonmessage // import "github.com/docker/docker/pkg/jsonmessage" 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/docker/docker/pkg/term" 12 "github.com/gotestyourself/gotestyourself/assert" 13 is "github.com/gotestyourself/gotestyourself/assert/cmp" 14 ) 15 16 func TestError(t *testing.T) { 17 je := JSONError{404, "Not found"} 18 assert.Assert(t, is.Error(&je, "Not found")) 19 } 20 21 func TestProgressString(t *testing.T) { 22 type expected struct { 23 short string 24 long string 25 } 26 27 shortAndLong := func(short, long string) expected { 28 return expected{short: short, long: long} 29 } 30 31 start := time.Date(2017, 12, 3, 15, 10, 1, 0, time.UTC) 32 timeAfter := func(delta time.Duration) func() time.Time { 33 return func() time.Time { 34 return start.Add(delta) 35 } 36 } 37 38 var testcases = []struct { 39 name string 40 progress JSONProgress 41 expected expected 42 }{ 43 { 44 name: "no progress", 45 }, 46 { 47 name: "progress 1", 48 progress: JSONProgress{Current: 1}, 49 expected: shortAndLong(" 1B", " 1B"), 50 }, 51 { 52 name: "some progress with a start time", 53 progress: JSONProgress{ 54 Current: 20, 55 Total: 100, 56 Start: start.Unix(), 57 nowFunc: timeAfter(time.Second), 58 }, 59 expected: shortAndLong( 60 " 20B/100B 4s", 61 "[==========> ] 20B/100B 4s", 62 ), 63 }, 64 { 65 name: "some progress without a start time", 66 progress: JSONProgress{Current: 50, Total: 100}, 67 expected: shortAndLong( 68 " 50B/100B", 69 "[=========================> ] 50B/100B", 70 ), 71 }, 72 { 73 name: "current more than total is not negative gh#7136", 74 progress: JSONProgress{Current: 50, Total: 40}, 75 expected: shortAndLong( 76 " 50B", 77 "[==================================================>] 50B", 78 ), 79 }, 80 { 81 name: "with units", 82 progress: JSONProgress{Current: 50, Total: 100, Units: "units"}, 83 expected: shortAndLong( 84 "50/100 units", 85 "[=========================> ] 50/100 units", 86 ), 87 }, 88 { 89 name: "current more than total with units is not negative ", 90 progress: JSONProgress{Current: 50, Total: 40, Units: "units"}, 91 expected: shortAndLong( 92 "50 units", 93 "[==================================================>] 50 units", 94 ), 95 }, 96 { 97 name: "hide counts", 98 progress: JSONProgress{Current: 50, Total: 100, HideCounts: true}, 99 expected: shortAndLong( 100 "", 101 "[=========================> ] ", 102 ), 103 }, 104 } 105 106 for _, testcase := range testcases { 107 t.Run(testcase.name, func(t *testing.T) { 108 testcase.progress.winSize = 100 109 assert.Equal(t, testcase.progress.String(), testcase.expected.short) 110 111 testcase.progress.winSize = 200 112 assert.Equal(t, testcase.progress.String(), testcase.expected.long) 113 }) 114 } 115 } 116 117 func TestJSONMessageDisplay(t *testing.T) { 118 now := time.Now() 119 messages := map[JSONMessage][]string{ 120 // Empty 121 {}: {"\n", "\n"}, 122 // Status 123 { 124 Status: "status", 125 }: { 126 "status\n", 127 "status\n", 128 }, 129 // General 130 { 131 Time: now.Unix(), 132 ID: "ID", 133 From: "From", 134 Status: "status", 135 }: { 136 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(RFC3339NanoFixed)), 137 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(RFC3339NanoFixed)), 138 }, 139 // General, with nano precision time 140 { 141 TimeNano: now.UnixNano(), 142 ID: "ID", 143 From: "From", 144 Status: "status", 145 }: { 146 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(RFC3339NanoFixed)), 147 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(RFC3339NanoFixed)), 148 }, 149 // General, with both times Nano is preferred 150 { 151 Time: now.Unix(), 152 TimeNano: now.UnixNano(), 153 ID: "ID", 154 From: "From", 155 Status: "status", 156 }: { 157 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(RFC3339NanoFixed)), 158 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(RFC3339NanoFixed)), 159 }, 160 // Stream over status 161 { 162 Status: "status", 163 Stream: "stream", 164 }: { 165 "stream", 166 "stream", 167 }, 168 // With progress message 169 { 170 Status: "status", 171 ProgressMessage: "progressMessage", 172 }: { 173 "status progressMessage", 174 "status progressMessage", 175 }, 176 // With progress, stream empty 177 { 178 Status: "status", 179 Stream: "", 180 Progress: &JSONProgress{Current: 1}, 181 }: { 182 "", 183 fmt.Sprintf("%c[1K%c[K\rstatus 1B\r", 27, 27), 184 }, 185 } 186 187 // The tests :) 188 for jsonMessage, expectedMessages := range messages { 189 // Without terminal 190 data := bytes.NewBuffer([]byte{}) 191 if err := jsonMessage.Display(data, nil); err != nil { 192 t.Fatal(err) 193 } 194 if data.String() != expectedMessages[0] { 195 t.Fatalf("Expected %q,got %q", expectedMessages[0], data.String()) 196 } 197 // With terminal 198 data = bytes.NewBuffer([]byte{}) 199 if err := jsonMessage.Display(data, &noTermInfo{}); err != nil { 200 t.Fatal(err) 201 } 202 if data.String() != expectedMessages[1] { 203 t.Fatalf("\nExpected %q\n got %q", expectedMessages[1], data.String()) 204 } 205 } 206 } 207 208 // Test JSONMessage with an Error. It will return an error with the text as error, not the meaning of the HTTP code. 209 func TestJSONMessageDisplayWithJSONError(t *testing.T) { 210 data := bytes.NewBuffer([]byte{}) 211 jsonMessage := JSONMessage{Error: &JSONError{404, "Can't find it"}} 212 213 err := jsonMessage.Display(data, &noTermInfo{}) 214 if err == nil || err.Error() != "Can't find it" { 215 t.Fatalf("Expected a JSONError 404, got %q", err) 216 } 217 218 jsonMessage = JSONMessage{Error: &JSONError{401, "Anything"}} 219 err = jsonMessage.Display(data, &noTermInfo{}) 220 assert.Check(t, is.Error(err, "authentication is required")) 221 } 222 223 func TestDisplayJSONMessagesStreamInvalidJSON(t *testing.T) { 224 var ( 225 inFd uintptr 226 ) 227 data := bytes.NewBuffer([]byte{}) 228 reader := strings.NewReader("This is not a 'valid' JSON []") 229 inFd, _ = term.GetFdInfo(reader) 230 231 if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err == nil && err.Error()[:17] != "invalid character" { 232 t.Fatalf("Should have thrown an error (invalid character in ..), got %q", err) 233 } 234 } 235 236 func TestDisplayJSONMessagesStream(t *testing.T) { 237 var ( 238 inFd uintptr 239 ) 240 241 messages := map[string][]string{ 242 // empty string 243 "": { 244 "", 245 ""}, 246 // Without progress & ID 247 "{ \"status\": \"status\" }": { 248 "status\n", 249 "status\n", 250 }, 251 // Without progress, with ID 252 "{ \"id\": \"ID\",\"status\": \"status\" }": { 253 "ID: status\n", 254 fmt.Sprintf("ID: status\n"), 255 }, 256 // With progress 257 "{ \"id\": \"ID\", \"status\": \"status\", \"progress\": \"ProgressMessage\" }": { 258 "ID: status ProgressMessage", 259 fmt.Sprintf("\n%c[%dAID: status ProgressMessage%c[%dB", 27, 1, 27, 1), 260 }, 261 // With progressDetail 262 "{ \"id\": \"ID\", \"status\": \"status\", \"progressDetail\": { \"Current\": 1} }": { 263 "", // progressbar is disabled in non-terminal 264 fmt.Sprintf("\n%c[%dA%c[1K%c[K\rID: status 1B\r%c[%dB", 27, 1, 27, 27, 27, 1), 265 }, 266 } 267 268 // Use $TERM which is unlikely to exist, forcing DisplayJSONMessageStream to 269 // (hopefully) use &noTermInfo. 270 origTerm := os.Getenv("TERM") 271 os.Setenv("TERM", "xyzzy-non-existent-terminfo") 272 273 for jsonMessage, expectedMessages := range messages { 274 data := bytes.NewBuffer([]byte{}) 275 reader := strings.NewReader(jsonMessage) 276 inFd, _ = term.GetFdInfo(reader) 277 278 // Without terminal 279 if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err != nil { 280 t.Fatal(err) 281 } 282 if data.String() != expectedMessages[0] { 283 t.Fatalf("Expected an %q, got %q", expectedMessages[0], data.String()) 284 } 285 286 // With terminal 287 data = bytes.NewBuffer([]byte{}) 288 reader = strings.NewReader(jsonMessage) 289 if err := DisplayJSONMessagesStream(reader, data, inFd, true, nil); err != nil { 290 t.Fatal(err) 291 } 292 if data.String() != expectedMessages[1] { 293 t.Fatalf("\nExpected %q\n got %q", expectedMessages[1], data.String()) 294 } 295 } 296 os.Setenv("TERM", origTerm) 297 298 }