github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+incompatible/util/ui/request_logger_file_writer_test.go (about) 1 package ui_test 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 "time" 11 12 . "github.com/liamawhite/cli-with-i18n/util/ui" 13 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 . "github.com/onsi/gomega/gbytes" 17 ) 18 19 var _ = Describe("Request Logger File Writer", func() { 20 var ( 21 testUI *UI 22 display *RequestLoggerFileWriter 23 tmpdir string 24 logFile1 string 25 logFile2 string 26 ) 27 28 BeforeEach(func() { 29 testUI = NewTestUI(NewBuffer(), NewBuffer(), NewBuffer()) 30 }) 31 32 Describe("Valid file paths", func() { 33 BeforeEach(func() { 34 var err error 35 tmpdir, err = ioutil.TempDir("", "request_logger") 36 Expect(err).ToNot(HaveOccurred()) 37 38 logFile1 = filepath.Join(tmpdir, "tmp_sub_dir", "tmpfile1") 39 logFile2 = filepath.Join(tmpdir, "tmp", "sub", "dir", ".", "tmpfile2") 40 display = testUI.RequestLoggerFileWriter([]string{logFile1, logFile2}) 41 Expect(display.Start()).ToNot(HaveOccurred()) 42 }) 43 44 AfterEach(func() { 45 Expect(os.RemoveAll(tmpdir)).NotTo(HaveOccurred()) 46 }) 47 48 Describe("DisplayBody", func() { 49 It("writes the redacted value", func() { 50 err := display.DisplayBody([]byte("this is a body")) 51 Expect(err).ToNot(HaveOccurred()) 52 53 err = display.Stop() 54 Expect(err).ToNot(HaveOccurred()) 55 56 contents, err := ioutil.ReadFile(logFile1) 57 Expect(err).ToNot(HaveOccurred()) 58 Expect(string(contents)).To(Equal(RedactedValue + "\n")) 59 60 contents, err = ioutil.ReadFile(logFile2) 61 Expect(err).ToNot(HaveOccurred()) 62 Expect(string(contents)).To(Equal(RedactedValue + "\n")) 63 }) 64 }) 65 66 Describe("DisplayDump", func() { 67 It("creates the intermediate dirs and writes the dump to file", func() { 68 err := display.DisplayDump("this is a dump of stuff") 69 Expect(err).ToNot(HaveOccurred()) 70 71 err = display.Stop() 72 Expect(err).ToNot(HaveOccurred()) 73 74 contents, err := ioutil.ReadFile(logFile1) 75 Expect(err).ToNot(HaveOccurred()) 76 Expect(string(contents)).To(Equal("this is a dump of stuff\n")) 77 78 contents, err = ioutil.ReadFile(logFile2) 79 Expect(err).ToNot(HaveOccurred()) 80 Expect(string(contents)).To(Equal("this is a dump of stuff\n")) 81 }) 82 83 It("redacts auth tokens", func() { 84 dump := `GET /apps/ce03a2e2-95c0-4f3b-abb9-32718d408c8b/stream HTTP/1.1 85 Host: wss://doppler.bosh-lite.com:443 86 Upgrade: websocket 87 Connection: Upgrade 88 Sec-WebSocket-Version: 13 89 Sec-WebSocket-Key: [HIDDEN] 90 Authorization: bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImtleS0xIiwidHlwIjoiSldUIn0.eyJqdGkiOiI3YzRmYWEyZjI5MmQ0MTQ5ODM5NGE3OTU0Y2E3ZWNlMCIsInN1YiI6IjIyMjNiM2IzLTE3ZTktNDJkNi1iNzQzLThjZjcyZWIwOWRlNSIsInNjb3BlIjpbInJvdXRpbmcucm91dGVyX2dyb3Vwcy5yZWFkIiwiY2xvdWRfY29udHJvbGxlci5yZWFkIiwicGFzc3dvcmQud3JpdGUiLCJjbG91ZF9jb250cm9sbGVyLndyaXRlIiwib3BlbmlkIiwicm91dGluZy5yb3V0ZXJfZ3JvdXBzLndyaXRlIiwiZG9wcGxlci5maXJlaG9zZSIsInNjaW0ud3JpdGUiLCJzY2ltLnJlYWQiLCJjbG91ZF9jb250cm9sbGVyLmFkbWluIiwidWFhLnVzZXIiXSwiY2xpZW50X2lkIjoiY2YiLCJjaWQiOiJjZiIsImF6cCI6ImNmIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9pZCI6IjIyMjNiM2IzLTE3ZTktNDJkNi1iNzQzLThjZjcyZWIwOWRlNSIsIm9yaWdpbiI6InVhYSIsInVzZXJfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbiIsInJldl9zaWciOiI4NDBiMDBhMyIsImlhdCI6MTQ5NjQyNTU5NiwiZXhwIjoxNDk2NDI2MTk2LCJpc3MiOiJodHRwczovL3VhYS5ib3NoLWxpdGUuY29tL29hdXRoL3Rva2VuIiwiemlkIjoidWFhIiwiYXVkIjpbInNjaW0iLCJjbG91ZF9jb250cm9sbGVyIiwicGFzc3dvcmQiLCJjZiIsInVhYSIsIm9wZW5pZCIsImRvcHBsZXIiLCJyb3V0aW5nLnJvdXRlcl9ncm91cHMiXX0.TFDmHviKcs-eeNoz79dVwOl-k_dHTdqHkyztont2qnBDchNSpWvR5Yba54MMG8uTUHM72YbCopxdyaLY-g8s5wJFGLaBocrDgqswUh3mQRvynQG6_zne1h_0oHXnm0U-ZPnTyV8qjtHUoLvks4GOuktXc6ZE3NriWODpKIU5WdMgEbvyhuTnUEn88rQnmGJbKvHOIilulb6avSkZfTEq1o8w4VLCeRDlVLNh5JzCUtGzLfImNb31ks_Wv6HuI8kFjQZ5PQiTYjlhkuDQOcNSaAyWxQ_7425hiA7x8omBgEr-uST7GsxLvgoHqQaDH0JSTgMmO_GaN_QD52JVuru9og 91 Origin: wss://doppler.bosh-lite.com:443` 92 err := display.DisplayDump(dump) 93 Expect(err).ToNot(HaveOccurred()) 94 95 err = display.Stop() 96 Expect(err).ToNot(HaveOccurred()) 97 98 raw, err := ioutil.ReadFile(logFile1) 99 Expect(err).ToNot(HaveOccurred()) 100 contents := string(raw) 101 102 Expect(contents).To(MatchRegexp("Connection: Upgrade")) 103 Expect(contents).To(MatchRegexp("Authorization: \\[PRIVATE DATA HIDDEN\\]")) 104 Expect(contents).To(MatchRegexp("Origin: wss://doppler.bosh-lite.com:443")) 105 106 raw, err = ioutil.ReadFile(logFile2) 107 Expect(err).ToNot(HaveOccurred()) 108 contents = string(raw) 109 110 Expect(contents).To(MatchRegexp("Connection: Upgrade")) 111 Expect(contents).To(MatchRegexp("Authorization: \\[PRIVATE DATA HIDDEN\\]")) 112 Expect(contents).To(MatchRegexp("Origin: wss://doppler.bosh-lite.com:443")) 113 }) 114 }) 115 116 Describe("DisplayHeader", func() { 117 It("writes the header key and value", func() { 118 err := display.DisplayHeader("Header", "Value") 119 Expect(err).ToNot(HaveOccurred()) 120 121 err = display.Stop() 122 Expect(err).ToNot(HaveOccurred()) 123 124 contents, err := ioutil.ReadFile(logFile1) 125 Expect(err).ToNot(HaveOccurred()) 126 Expect(string(contents)).To(Equal("Header: Value\n\n")) 127 128 contents, err = ioutil.ReadFile(logFile2) 129 Expect(err).ToNot(HaveOccurred()) 130 Expect(string(contents)).To(Equal("Header: Value\n\n")) 131 }) 132 }) 133 134 Describe("DisplayHost", func() { 135 It("writes the host", func() { 136 err := display.DisplayHost("banana") 137 Expect(err).ToNot(HaveOccurred()) 138 139 err = display.Stop() 140 Expect(err).ToNot(HaveOccurred()) 141 142 contents, err := ioutil.ReadFile(logFile1) 143 Expect(err).ToNot(HaveOccurred()) 144 Expect(string(contents)).To(Equal("Host: banana\n\n")) 145 146 contents, err = ioutil.ReadFile(logFile2) 147 Expect(err).ToNot(HaveOccurred()) 148 Expect(string(contents)).To(Equal("Host: banana\n\n")) 149 }) 150 }) 151 152 Describe("DisplayJSONBody", func() { 153 Context("when provided well formed JSON", func() { 154 It("writes a formatted output", func() { 155 raw := `{"a":"b", "c":"d", "don't escape HTML":"<&>"}` 156 formatted := `{ 157 "a": "b", 158 "c": "d", 159 "don't escape HTML": "<&>" 160 } 161 162 ` // Additonal spaces required 163 err := display.DisplayJSONBody([]byte(raw)) 164 Expect(err).ToNot(HaveOccurred()) 165 166 err = display.Stop() 167 Expect(err).ToNot(HaveOccurred()) 168 169 contents, err := ioutil.ReadFile(logFile1) 170 Expect(err).ToNot(HaveOccurred()) 171 Expect(string(contents)).To(Equal(formatted)) 172 173 contents, err = ioutil.ReadFile(logFile2) 174 Expect(err).ToNot(HaveOccurred()) 175 Expect(string(contents)).To(Equal(formatted)) 176 }) 177 }) 178 179 Context("when the body is empty", func() { 180 It("does not write the body", func() { 181 err := display.DisplayJSONBody(nil) 182 Expect(err).ToNot(HaveOccurred()) 183 184 err = display.Stop() 185 Expect(err).ToNot(HaveOccurred()) 186 187 contents, err := ioutil.ReadFile(logFile1) 188 Expect(err).ToNot(HaveOccurred()) 189 Expect(string(contents)).To(Equal("\n")) 190 191 contents, err = ioutil.ReadFile(logFile2) 192 Expect(err).ToNot(HaveOccurred()) 193 Expect(string(contents)).To(Equal("\n")) 194 }) 195 }) 196 197 Context("when provided malformed JSON", func() { 198 It("displays the raw body", func() { 199 raw := `[{"data":1, "banana": 2}]` 200 err := display.DisplayJSONBody([]byte(raw)) 201 Expect(err).ToNot(HaveOccurred()) 202 203 err = display.Stop() 204 Expect(err).ToNot(HaveOccurred()) 205 206 contents, err := ioutil.ReadFile(logFile1) 207 Expect(err).ToNot(HaveOccurred()) 208 Expect(string(contents)).To(Equal(raw + "\n\n")) 209 210 contents, err = ioutil.ReadFile(logFile2) 211 Expect(err).ToNot(HaveOccurred()) 212 Expect(string(contents)).To(Equal(raw + "\n\n")) 213 }) 214 }) 215 }) 216 217 Describe("DisplayMessage", func() { 218 It("writes the message", func() { 219 msg := "i am a message!!!!" 220 err := display.DisplayMessage(msg) 221 Expect(err).ToNot(HaveOccurred()) 222 223 err = display.Stop() 224 Expect(err).ToNot(HaveOccurred()) 225 226 contents, err := ioutil.ReadFile(logFile1) 227 Expect(err).ToNot(HaveOccurred()) 228 Expect(string(contents)).To(ContainSubstring(msg)) 229 230 contents, err = ioutil.ReadFile(logFile2) 231 Expect(err).ToNot(HaveOccurred()) 232 Expect(string(contents)).To(ContainSubstring(msg)) 233 }) 234 }) 235 236 Describe("DisplayRequestHeader", func() { 237 It("writes the method, uri and http protocol", func() { 238 err := display.DisplayRequestHeader("GET", "/v2/spaces/guid/summary", "HTTP/1.1") 239 Expect(err).ToNot(HaveOccurred()) 240 241 err = display.Stop() 242 Expect(err).ToNot(HaveOccurred()) 243 244 contents, err := ioutil.ReadFile(logFile1) 245 Expect(err).ToNot(HaveOccurred()) 246 Expect(string(contents)).To(Equal("GET /v2/spaces/guid/summary HTTP/1.1\n\n")) 247 248 contents, err = ioutil.ReadFile(logFile2) 249 Expect(err).ToNot(HaveOccurred()) 250 Expect(string(contents)).To(Equal("GET /v2/spaces/guid/summary HTTP/1.1\n\n")) 251 }) 252 }) 253 254 Describe("DisplayResponseHeader", func() { 255 It("writes the method, uri and http protocol", func() { 256 err := display.DisplayResponseHeader("HTTP/1.1", "200 OK") 257 Expect(err).ToNot(HaveOccurred()) 258 259 err = display.Stop() 260 Expect(err).ToNot(HaveOccurred()) 261 262 contents, err := ioutil.ReadFile(logFile1) 263 Expect(err).ToNot(HaveOccurred()) 264 Expect(string(contents)).To(Equal("HTTP/1.1 200 OK\n\n")) 265 266 contents, err = ioutil.ReadFile(logFile2) 267 Expect(err).ToNot(HaveOccurred()) 268 Expect(string(contents)).To(Equal("HTTP/1.1 200 OK\n\n")) 269 }) 270 }) 271 272 Describe("DisplayType", func() { 273 It("writes the passed type and time in localized ISO 8601", func() { 274 passedTime := time.Now() 275 err := display.DisplayType("banana", passedTime) 276 Expect(err).ToNot(HaveOccurred()) 277 278 err = display.Stop() 279 Expect(err).ToNot(HaveOccurred()) 280 281 contents, err := ioutil.ReadFile(logFile1) 282 Expect(err).ToNot(HaveOccurred()) 283 Expect(string(contents)).To(Equal(fmt.Sprintf("banana: [%s]\n\n", passedTime.Format(time.RFC3339)))) 284 285 contents, err = ioutil.ReadFile(logFile2) 286 Expect(err).ToNot(HaveOccurred()) 287 Expect(string(contents)).To(Equal(fmt.Sprintf("banana: [%s]\n\n", passedTime.Format(time.RFC3339)))) 288 }) 289 }) 290 291 Describe("HandleInternalError", func() { 292 It("sends error to standard error", func() { 293 err := errors.New("foobar") 294 display.HandleInternalError(err) 295 Expect(testUI.Err).To(Say("foobar")) 296 Expect(display.Stop()).NotTo(HaveOccurred()) 297 }) 298 }) 299 300 Describe("Start and Stop", func() { 301 BeforeEach(func() { 302 // Cleanup old display output directory 303 Expect(display.Stop()).NotTo(HaveOccurred()) 304 logFile1 = filepath.Join(tmpdir, "tmp_sub_dir", "tmpfile3") 305 logFile2 = filepath.Join(tmpdir, "tmp", "sub", "dir", ".", "tmpfile4") 306 display = testUI.RequestLoggerFileWriter([]string{logFile1, logFile2}) 307 }) 308 309 It("locks and then unlocks the mutex properly", func() { // and creates the intermediate dirs 310 c := make(chan bool) 311 go func() { 312 Expect(display.Start()).ToNot(HaveOccurred()) 313 c <- true 314 }() 315 Eventually(c).Should(Receive()) 316 Expect(display.Stop()).NotTo(HaveOccurred()) 317 }) 318 }) 319 }) 320 321 Describe("when the log file path is invalid", func() { 322 var pathName string 323 324 BeforeEach(func() { 325 var err error 326 tmpdir, err = ioutil.TempDir("", "request_logger") 327 Expect(err).ToNot(HaveOccurred()) 328 329 pathName = filepath.Join(tmpdir, "foo") 330 }) 331 332 AfterEach(func() { 333 Expect(display.Stop()).NotTo(HaveOccurred()) 334 Expect(os.RemoveAll(tmpdir)).NotTo(HaveOccurred()) 335 }) 336 337 It("returns the os error when we unsuccessfully try to write to a file", func() { 338 Expect(os.Mkdir(pathName, os.ModeDir|os.ModePerm)).NotTo(HaveOccurred()) 339 display = testUI.RequestLoggerFileWriter([]string{pathName}) 340 err := display.Start() 341 342 Expect(err).To(MatchError(fmt.Sprintf("open %s: is a directory", pathName))) 343 }) 344 345 It("returns the os error when the parent directory for the log file is in the root directory", func() { 346 file, err := os.OpenFile(pathName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) 347 Expect(err).ToNot(HaveOccurred()) 348 _, err = file.WriteString("hello world") 349 Expect(err).ToNot(HaveOccurred()) 350 err = file.Close() 351 Expect(err).ToNot(HaveOccurred()) 352 353 display = testUI.RequestLoggerFileWriter([]string{filepath.Join(pathName, "bar")}) 354 err = display.Start() 355 356 pathName = strings.Replace(pathName, `\`, `\\`, -1) 357 Expect(err).To(MatchError(MatchRegexp(fmt.Sprintf("mkdir %s", pathName)))) 358 }) 359 }) 360 })