github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/actor/v3action/logging_test.go (about) 1 package v3action_test 2 3 import ( 4 "errors" 5 "time" 6 7 . "code.cloudfoundry.org/cli/actor/v3action" 8 "code.cloudfoundry.org/cli/actor/v3action/v3actionfakes" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 10 noaaErrors "github.com/cloudfoundry/noaa/errors" 11 "github.com/cloudfoundry/sonde-go/events" 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 ) 15 16 var _ = Describe("Logging Actions", func() { 17 var ( 18 actor *Actor 19 fakeNOAAClient *v3actionfakes.FakeNOAAClient 20 fakeCloudControllerClient *v3actionfakes.FakeCloudControllerClient 21 ) 22 23 BeforeEach(func() { 24 fakeNOAAClient = new(v3actionfakes.FakeNOAAClient) 25 fakeCloudControllerClient = new(v3actionfakes.FakeCloudControllerClient) 26 actor = NewActor(fakeCloudControllerClient, nil, nil, nil) 27 }) 28 29 Describe("LogMessage", func() { 30 Describe("Staging", func() { 31 Context("when the log is a staging log", func() { 32 It("returns true", func() { 33 message := NewLogMessage("", 0, time.Now(), "STG", "") 34 Expect(message.Staging()).To(BeTrue()) 35 }) 36 }) 37 38 Context("when the log is any other kind of log", func() { 39 It("returns true", func() { 40 message := NewLogMessage("", 0, time.Now(), "APP", "") 41 Expect(message.Staging()).To(BeFalse()) 42 }) 43 }) 44 }) 45 }) 46 47 Describe("GetStreamingLogs", func() { 48 var ( 49 expectedAppGUID string 50 51 messages <-chan *LogMessage 52 errs <-chan error 53 eventStream chan *events.LogMessage 54 errStream chan error 55 ) 56 57 BeforeEach(func() { 58 expectedAppGUID = "some-app-guid" 59 60 eventStream = make(chan *events.LogMessage, 100) 61 errStream = make(chan error) 62 }) 63 64 // If tests panic due to this close, it is likely you have a failing 65 // expectation and the channels are being closed because the test has 66 // failed/short circuited and is going through teardown. 67 AfterEach(func() { 68 close(eventStream) 69 close(errStream) 70 71 Eventually(messages).Should(BeClosed()) 72 Eventually(errs).Should(BeClosed()) 73 }) 74 75 JustBeforeEach(func() { 76 messages, errs = actor.GetStreamingLogs(expectedAppGUID, fakeNOAAClient) 77 }) 78 79 Context("when receiving events", func() { 80 BeforeEach(func() { 81 fakeNOAAClient.TailingLogsStub = func(appGUID string, authToken string) (<-chan *events.LogMessage, <-chan error) { 82 Expect(appGUID).To(Equal(expectedAppGUID)) 83 Expect(authToken).To(BeEmpty()) 84 85 go func() { 86 outMessage := events.LogMessage_OUT 87 ts1 := int64(10) 88 sourceType := "some-source-type" 89 sourceInstance := "some-source-instance" 90 91 eventStream <- &events.LogMessage{ 92 Message: []byte("message-1"), 93 MessageType: &outMessage, 94 Timestamp: &ts1, 95 SourceType: &sourceType, 96 SourceInstance: &sourceInstance, 97 } 98 99 errMessage := events.LogMessage_ERR 100 ts2 := int64(20) 101 102 eventStream <- &events.LogMessage{ 103 Message: []byte("message-2"), 104 MessageType: &errMessage, 105 Timestamp: &ts2, 106 SourceType: &sourceType, 107 SourceInstance: &sourceInstance, 108 } 109 }() 110 111 return eventStream, errStream 112 } 113 }) 114 115 It("converts them to log messages and passes them through the messages channel", func() { 116 message := <-messages 117 Expect(message.Message()).To(Equal("message-1")) 118 Expect(message.Type()).To(Equal("OUT")) 119 Expect(message.Timestamp()).To(Equal(time.Unix(0, 10))) 120 Expect(message.SourceType()).To(Equal("some-source-type")) 121 Expect(message.SourceInstance()).To(Equal("some-source-instance")) 122 123 message = <-messages 124 Expect(message.Message()).To(Equal("message-2")) 125 Expect(message.Type()).To(Equal("ERR")) 126 Expect(message.Timestamp()).To(Equal(time.Unix(0, 20))) 127 Expect(message.SourceType()).To(Equal("some-source-type")) 128 Expect(message.SourceInstance()).To(Equal("some-source-instance")) 129 }) 130 131 It("sorts the logs by timestamp", func() { 132 outMessage := events.LogMessage_OUT 133 sourceType := "some-source-type" 134 sourceInstance := "some-source-instance" 135 136 ts3 := int64(0) 137 eventStream <- &events.LogMessage{ 138 Message: []byte("message-3"), 139 MessageType: &outMessage, 140 Timestamp: &ts3, 141 SourceType: &sourceType, 142 SourceInstance: &sourceInstance, 143 } 144 145 errMessage := events.LogMessage_ERR 146 ts4 := int64(15) 147 eventStream <- &events.LogMessage{ 148 Message: []byte("message-4"), 149 MessageType: &errMessage, 150 Timestamp: &ts4, 151 SourceType: &sourceType, 152 SourceInstance: &sourceInstance, 153 } 154 155 message := <-messages 156 Expect(message.Timestamp()).To(Equal(time.Unix(0, 0))) 157 158 message = <-messages 159 Expect(message.Timestamp()).To(Equal(time.Unix(0, 10))) 160 161 message = <-messages 162 Expect(message.Timestamp()).To(Equal(time.Unix(0, 15))) 163 164 message = <-messages 165 Expect(message.Timestamp()).To(Equal(time.Unix(0, 20))) 166 }) 167 }) 168 169 Context("when receiving errors", func() { 170 var ( 171 err1 error 172 err2 error 173 174 waiting chan bool 175 ) 176 177 Describe("nil error", func() { 178 BeforeEach(func() { 179 waiting = make(chan bool) 180 fakeNOAAClient.TailingLogsStub = func(_ string, _ string) (<-chan *events.LogMessage, <-chan error) { 181 go func() { 182 errStream <- nil 183 close(waiting) 184 }() 185 186 return eventStream, errStream 187 } 188 }) 189 190 It("does not pass the nil along", func() { 191 Eventually(waiting).Should(BeClosed()) 192 Consistently(errs).ShouldNot(Receive()) 193 }) 194 }) 195 196 Describe("unexpected error", func() { 197 BeforeEach(func() { 198 err1 = errors.New("ZOMG") 199 err2 = errors.New("Fiddlesticks") 200 201 fakeNOAAClient.TailingLogsStub = func(_ string, _ string) (<-chan *events.LogMessage, <-chan error) { 202 go func() { 203 errStream <- err1 204 errStream <- err2 205 }() 206 207 return eventStream, errStream 208 } 209 }) 210 211 It("passes them through the errors channel", func() { 212 Eventually(errs).Should(Receive(Equal(err1))) 213 Eventually(errs).Should(Receive(Equal(err2))) 214 }) 215 }) 216 217 Describe("NOAA's RetryError", func() { 218 Context("when NOAA is able to recover", func() { 219 BeforeEach(func() { 220 fakeNOAAClient.TailingLogsStub = func(_ string, _ string) (<-chan *events.LogMessage, <-chan error) { 221 go func() { 222 errStream <- noaaErrors.NewRetryError(errors.New("error 1")) 223 224 outMessage := events.LogMessage_OUT 225 ts1 := int64(10) 226 sourceType := "some-source-type" 227 sourceInstance := "some-source-instance" 228 229 eventStream <- &events.LogMessage{ 230 Message: []byte("message-1"), 231 MessageType: &outMessage, 232 Timestamp: &ts1, 233 SourceType: &sourceType, 234 SourceInstance: &sourceInstance, 235 } 236 }() 237 238 return eventStream, errStream 239 } 240 }) 241 242 It("continues without issue", func() { 243 Eventually(messages).Should(Receive()) 244 Consistently(errs).ShouldNot(Receive()) 245 }) 246 }) 247 }) 248 }) 249 }) 250 251 Describe("GetStreamingLogsForApplicationByNameAndSpace", func() { 252 Context("when the application can be found", func() { 253 var ( 254 expectedAppGUID string 255 256 eventStream chan *events.LogMessage 257 errStream chan error 258 259 messages <-chan *LogMessage 260 logErrs <-chan error 261 ) 262 263 // If tests panic due to this close, it is likely you have a failing 264 // expectation and the channels are being closed because the test has 265 // failed/short circuited and is going through teardown. 266 AfterEach(func() { 267 close(eventStream) 268 close(errStream) 269 270 Eventually(messages).Should(BeClosed()) 271 Eventually(logErrs).Should(BeClosed()) 272 }) 273 274 BeforeEach(func() { 275 expectedAppGUID = "some-app-guid" 276 277 eventStream = make(chan *events.LogMessage) 278 errStream = make(chan error) 279 fakeCloudControllerClient.GetApplicationsReturns( 280 []ccv3.Application{ 281 { 282 Name: "some-app", 283 GUID: expectedAppGUID, 284 }, 285 }, 286 ccv3.Warnings{"some-app-warnings"}, 287 nil, 288 ) 289 290 fakeNOAAClient.TailingLogsStub = func(appGUID string, authToken string) (<-chan *events.LogMessage, <-chan error) { 291 Expect(appGUID).To(Equal(expectedAppGUID)) 292 Expect(authToken).To(BeEmpty()) 293 294 go func() { 295 outMessage := events.LogMessage_OUT 296 ts1 := int64(10) 297 sourceType := "some-source-type" 298 sourceInstance := "some-source-instance" 299 300 eventStream <- &events.LogMessage{ 301 Message: []byte("message-1"), 302 MessageType: &outMessage, 303 Timestamp: &ts1, 304 SourceType: &sourceType, 305 SourceInstance: &sourceInstance, 306 } 307 308 errMessage := events.LogMessage_ERR 309 ts2 := int64(20) 310 311 eventStream <- &events.LogMessage{ 312 Message: []byte("message-2"), 313 MessageType: &errMessage, 314 Timestamp: &ts2, 315 SourceType: &sourceType, 316 SourceInstance: &sourceInstance, 317 } 318 }() 319 320 return eventStream, errStream 321 } 322 }) 323 324 It("converts them to log messages and passes them through the messages channel", func() { 325 var err error 326 var warnings Warnings 327 messages, logErrs, warnings, err = actor.GetStreamingLogsForApplicationByNameAndSpace("some-app", "some-space-guid", fakeNOAAClient) 328 329 Expect(err).ToNot(HaveOccurred()) 330 Expect(warnings).To(ConsistOf("some-app-warnings")) 331 332 message := <-messages 333 Expect(message.Message()).To(Equal("message-1")) 334 Expect(message.Type()).To(Equal("OUT")) 335 Expect(message.Timestamp()).To(Equal(time.Unix(0, 10))) 336 Expect(message.SourceType()).To(Equal("some-source-type")) 337 Expect(message.SourceInstance()).To(Equal("some-source-instance")) 338 339 message = <-messages 340 Expect(message.Message()).To(Equal("message-2")) 341 Expect(message.Type()).To(Equal("ERR")) 342 Expect(message.Timestamp()).To(Equal(time.Unix(0, 20))) 343 Expect(message.SourceType()).To(Equal("some-source-type")) 344 Expect(message.SourceInstance()).To(Equal("some-source-instance")) 345 }) 346 }) 347 348 Context("when finding the application errors", func() { 349 var expectedErr error 350 351 BeforeEach(func() { 352 expectedErr = errors.New("ZOMG") 353 fakeCloudControllerClient.GetApplicationsReturns( 354 nil, 355 ccv3.Warnings{"some-app-warnings"}, 356 expectedErr, 357 ) 358 }) 359 360 It("returns error and warnings", func() { 361 _, _, warnings, err := actor.GetStreamingLogsForApplicationByNameAndSpace("some-app", "some-space-guid", fakeNOAAClient) 362 Expect(err).To(MatchError(expectedErr)) 363 Expect(warnings).To(ConsistOf("some-app-warnings")) 364 365 Expect(fakeNOAAClient.TailingLogsCallCount()).To(Equal(0)) 366 }) 367 }) 368 }) 369 })