github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/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/jsonlog" 12 "github.com/docker/docker/pkg/term" 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 70 func TestJSONMessageDisplay(t *testing.T) { 71 now := time.Now() 72 messages := map[JSONMessage][]string{ 73 // Empty 74 JSONMessage{}: {"\n", "\n"}, 75 // Status 76 JSONMessage{ 77 Status: "status", 78 }: { 79 "status\n", 80 "status\n", 81 }, 82 // General 83 JSONMessage{ 84 Time: now.Unix(), 85 ID: "ID", 86 From: "From", 87 Status: "status", 88 }: { 89 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)), 90 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(now.Unix(), 0).Format(jsonlog.RFC3339NanoFixed)), 91 }, 92 // General, with nano precision time 93 JSONMessage{ 94 TimeNano: now.UnixNano(), 95 ID: "ID", 96 From: "From", 97 Status: "status", 98 }: { 99 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)), 100 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)), 101 }, 102 // General, with both times Nano is preferred 103 JSONMessage{ 104 Time: now.Unix(), 105 TimeNano: now.UnixNano(), 106 ID: "ID", 107 From: "From", 108 Status: "status", 109 }: { 110 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)), 111 fmt.Sprintf("%v ID: (from From) status\n", time.Unix(0, now.UnixNano()).Format(jsonlog.RFC3339NanoFixed)), 112 }, 113 // Stream over status 114 JSONMessage{ 115 Status: "status", 116 Stream: "stream", 117 }: { 118 "stream", 119 "stream", 120 }, 121 // With progress message 122 JSONMessage{ 123 Status: "status", 124 ProgressMessage: "progressMessage", 125 }: { 126 "status progressMessage", 127 "status progressMessage", 128 }, 129 // With progress, stream empty 130 JSONMessage{ 131 Status: "status", 132 Stream: "", 133 Progress: &JSONProgress{Current: 1}, 134 }: { 135 "", 136 fmt.Sprintf("%c[1K%c[K\rstatus 1B\r", 27, 27), 137 }, 138 } 139 140 // The tests :) 141 for jsonMessage, expectedMessages := range messages { 142 // Without terminal 143 data := bytes.NewBuffer([]byte{}) 144 if err := jsonMessage.Display(data, nil); err != nil { 145 t.Fatal(err) 146 } 147 if data.String() != expectedMessages[0] { 148 t.Fatalf("Expected %q,got %q", expectedMessages[0], data.String()) 149 } 150 // With terminal 151 data = bytes.NewBuffer([]byte{}) 152 if err := jsonMessage.Display(data, &noTermInfo{}); err != nil { 153 t.Fatal(err) 154 } 155 if data.String() != expectedMessages[1] { 156 t.Fatalf("\nExpected %q\n got %q", expectedMessages[1], data.String()) 157 } 158 } 159 } 160 161 // Test JSONMessage with an Error. It will return an error with the text as error, not the meaning of the HTTP code. 162 func TestJSONMessageDisplayWithJSONError(t *testing.T) { 163 data := bytes.NewBuffer([]byte{}) 164 jsonMessage := JSONMessage{Error: &JSONError{404, "Can't find it"}} 165 166 err := jsonMessage.Display(data, &noTermInfo{}) 167 if err == nil || err.Error() != "Can't find it" { 168 t.Fatalf("Expected a JSONError 404, got %q", err) 169 } 170 171 jsonMessage = JSONMessage{Error: &JSONError{401, "Anything"}} 172 err = jsonMessage.Display(data, &noTermInfo{}) 173 if err == nil || err.Error() != "Authentication is required." { 174 t.Fatalf("Expected an error \"Authentication is required.\", got %q", err) 175 } 176 } 177 178 func TestDisplayJSONMessagesStreamInvalidJSON(t *testing.T) { 179 var ( 180 inFd uintptr 181 ) 182 data := bytes.NewBuffer([]byte{}) 183 reader := strings.NewReader("This is not a 'valid' JSON []") 184 inFd, _ = term.GetFdInfo(reader) 185 186 if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err == nil && err.Error()[:17] != "invalid character" { 187 t.Fatalf("Should have thrown an error (invalid character in ..), got %q", err) 188 } 189 } 190 191 func TestDisplayJSONMessagesStream(t *testing.T) { 192 var ( 193 inFd uintptr 194 ) 195 196 messages := map[string][]string{ 197 // empty string 198 "": { 199 "", 200 ""}, 201 // Without progress & ID 202 "{ \"status\": \"status\" }": { 203 "status\n", 204 "status\n", 205 }, 206 // Without progress, with ID 207 "{ \"id\": \"ID\",\"status\": \"status\" }": { 208 "ID: status\n", 209 fmt.Sprintf("ID: status\n"), 210 }, 211 // With progress 212 "{ \"id\": \"ID\", \"status\": \"status\", \"progress\": \"ProgressMessage\" }": { 213 "ID: status ProgressMessage", 214 fmt.Sprintf("\n%c[%dAID: status ProgressMessage%c[%dB", 27, 1, 27, 1), 215 }, 216 // With progressDetail 217 "{ \"id\": \"ID\", \"status\": \"status\", \"progressDetail\": { \"Current\": 1} }": { 218 "", // progressbar is disabled in non-terminal 219 fmt.Sprintf("\n%c[%dA%c[1K%c[K\rID: status 1B\r%c[%dB", 27, 1, 27, 27, 27, 1), 220 }, 221 } 222 223 // Use $TERM which is unlikely to exist, forcing DisplayJSONMessageStream to 224 // (hopefully) use &noTermInfo. 225 origTerm := os.Getenv("TERM") 226 os.Setenv("TERM", "xyzzy-non-existent-terminfo") 227 228 for jsonMessage, expectedMessages := range messages { 229 data := bytes.NewBuffer([]byte{}) 230 reader := strings.NewReader(jsonMessage) 231 inFd, _ = term.GetFdInfo(reader) 232 233 // Without terminal 234 if err := DisplayJSONMessagesStream(reader, data, inFd, false, nil); err != nil { 235 t.Fatal(err) 236 } 237 if data.String() != expectedMessages[0] { 238 t.Fatalf("Expected an %q, got %q", expectedMessages[0], data.String()) 239 } 240 241 // With terminal 242 data = bytes.NewBuffer([]byte{}) 243 reader = strings.NewReader(jsonMessage) 244 if err := DisplayJSONMessagesStream(reader, data, inFd, true, nil); err != nil { 245 t.Fatal(err) 246 } 247 if data.String() != expectedMessages[1] { 248 t.Fatalf("\nExpected %q\n got %q", expectedMessages[1], data.String()) 249 } 250 } 251 os.Setenv("TERM", origTerm) 252 253 }