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