github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/actor/v2action/logging_test.go (about) 1 package v2action_test 2 3 import ( 4 "errors" 5 "time" 6 7 . "code.cloudfoundry.org/cli/actor/v2action" 8 "code.cloudfoundry.org/cli/actor/v2action/v2actionfakes" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2" 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 *v2actionfakes.FakeNOAAClient 20 fakeCloudControllerClient *v2actionfakes.FakeCloudControllerClient 21 ) 22 23 BeforeEach(func() { 24 fakeNOAAClient = new(v2actionfakes.FakeNOAAClient) 25 fakeCloudControllerClient = new(v2actionfakes.FakeCloudControllerClient) 26 actor = NewActor(fakeCloudControllerClient, 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 outMessage := events.LogMessage_OUT 86 ts1 := int64(10) 87 sourceType := "some-source-type" 88 sourceInstance := "some-source-instance" 89 90 eventStream <- &events.LogMessage{ 91 Message: []byte("message-1"), 92 MessageType: &outMessage, 93 Timestamp: &ts1, 94 SourceType: &sourceType, 95 SourceInstance: &sourceInstance, 96 } 97 98 errMessage := events.LogMessage_ERR 99 ts2 := int64(20) 100 101 eventStream <- &events.LogMessage{ 102 Message: []byte("message-2"), 103 MessageType: &errMessage, 104 Timestamp: &ts2, 105 SourceType: &sourceType, 106 SourceInstance: &sourceInstance, 107 } 108 109 return eventStream, errStream 110 } 111 }) 112 113 It("converts them to log messages and passes them through the messages channel", func() { 114 message := <-messages 115 Expect(message.Message()).To(Equal("message-1")) 116 Expect(message.Type()).To(Equal("OUT")) 117 Expect(message.Timestamp()).To(Equal(time.Unix(0, 10))) 118 Expect(message.SourceType()).To(Equal("some-source-type")) 119 Expect(message.SourceInstance()).To(Equal("some-source-instance")) 120 121 message = <-messages 122 Expect(message.Message()).To(Equal("message-2")) 123 Expect(message.Type()).To(Equal("ERR")) 124 Expect(message.Timestamp()).To(Equal(time.Unix(0, 20))) 125 Expect(message.SourceType()).To(Equal("some-source-type")) 126 Expect(message.SourceInstance()).To(Equal("some-source-instance")) 127 }) 128 129 It("sorts the logs by timestamp", func() { 130 outMessage := events.LogMessage_OUT 131 sourceType := "some-source-type" 132 sourceInstance := "some-source-instance" 133 134 ts3 := int64(0) 135 eventStream <- &events.LogMessage{ 136 Message: []byte("message-3"), 137 MessageType: &outMessage, 138 Timestamp: &ts3, 139 SourceType: &sourceType, 140 SourceInstance: &sourceInstance, 141 } 142 143 errMessage := events.LogMessage_ERR 144 ts4 := int64(15) 145 eventStream <- &events.LogMessage{ 146 Message: []byte("message-4"), 147 MessageType: &errMessage, 148 Timestamp: &ts4, 149 SourceType: &sourceType, 150 SourceInstance: &sourceInstance, 151 } 152 153 message := <-messages 154 Expect(message.Timestamp()).To(Equal(time.Unix(0, 0))) 155 156 message = <-messages 157 Expect(message.Timestamp()).To(Equal(time.Unix(0, 10))) 158 159 message = <-messages 160 Expect(message.Timestamp()).To(Equal(time.Unix(0, 15))) 161 162 message = <-messages 163 Expect(message.Timestamp()).To(Equal(time.Unix(0, 20))) 164 }) 165 }) 166 167 Context("when receiving errors", func() { 168 var ( 169 err1 error 170 err2 error 171 172 waiting chan bool 173 ) 174 175 Describe("nil error", func() { 176 BeforeEach(func() { 177 waiting = make(chan bool) 178 fakeNOAAClient.TailingLogsStub = func(_ string, _ string) (<-chan *events.LogMessage, <-chan error) { 179 go func() { 180 errStream <- nil 181 close(waiting) 182 }() 183 184 return eventStream, errStream 185 } 186 }) 187 188 It("does not pass the nil along", func() { 189 Eventually(waiting).Should(BeClosed()) 190 Consistently(errs).ShouldNot(Receive()) 191 }) 192 }) 193 194 Describe("unexpected error", func() { 195 BeforeEach(func() { 196 err1 = errors.New("ZOMG") 197 err2 = errors.New("Fiddlesticks") 198 199 fakeNOAAClient.TailingLogsStub = func(_ string, _ string) (<-chan *events.LogMessage, <-chan error) { 200 go func() { 201 errStream <- err1 202 errStream <- err2 203 }() 204 205 return eventStream, errStream 206 } 207 }) 208 209 It("passes them through the errors channel", func() { 210 Eventually(errs).Should(Receive(Equal(err1))) 211 Eventually(errs).Should(Receive(Equal(err2))) 212 }) 213 }) 214 215 Describe("NOAA's RetryError", func() { 216 Context("when NOAA is able to recover", func() { 217 BeforeEach(func() { 218 fakeNOAAClient.TailingLogsStub = func(_ string, _ string) (<-chan *events.LogMessage, <-chan error) { 219 go func() { 220 errStream <- noaaErrors.NewRetryError(errors.New("error 1")) 221 222 outMessage := events.LogMessage_OUT 223 ts1 := int64(10) 224 sourceType := "some-source-type" 225 sourceInstance := "some-source-instance" 226 227 eventStream <- &events.LogMessage{ 228 Message: []byte("message-1"), 229 MessageType: &outMessage, 230 Timestamp: &ts1, 231 SourceType: &sourceType, 232 SourceInstance: &sourceInstance, 233 } 234 }() 235 236 return eventStream, errStream 237 } 238 }) 239 240 It("continues without issue", func() { 241 Eventually(messages).Should(Receive()) 242 Consistently(errs).ShouldNot(Receive()) 243 }) 244 }) 245 }) 246 }) 247 }) 248 249 Describe("GetRecentLogsForApplicationByNameAndSpace", func() { 250 Context("when the application can be found", func() { 251 BeforeEach(func() { 252 fakeCloudControllerClient.GetApplicationsReturns( 253 []ccv2.Application{ 254 { 255 Name: "some-app", 256 GUID: "some-app-guid", 257 }, 258 }, 259 ccv2.Warnings{"some-app-warnings"}, 260 nil, 261 ) 262 }) 263 264 Context("when NOAA returns logs", func() { 265 BeforeEach(func() { 266 outMessage := events.LogMessage_OUT 267 ts1 := int64(10) 268 ts2 := int64(20) 269 sourceType := "some-source-type" 270 sourceInstance := "some-source-instance" 271 272 var messages []*events.LogMessage 273 messages = append(messages, &events.LogMessage{ 274 Message: []byte("message-2"), 275 MessageType: &outMessage, 276 Timestamp: &ts2, 277 SourceType: &sourceType, 278 SourceInstance: &sourceInstance, 279 }) 280 messages = append(messages, &events.LogMessage{ 281 Message: []byte("message-1"), 282 MessageType: &outMessage, 283 Timestamp: &ts1, 284 SourceType: &sourceType, 285 SourceInstance: &sourceInstance, 286 }) 287 288 fakeNOAAClient.RecentLogsReturns(messages, nil) 289 }) 290 291 It("returns all the recent logs and warnings", func() { 292 messages, warnings, err := actor.GetRecentLogsForApplicationByNameAndSpace("some-app", "some-space-guid", fakeNOAAClient) 293 Expect(err).ToNot(HaveOccurred()) 294 Expect(warnings).To(ConsistOf("some-app-warnings")) 295 Expect(messages[0].Message()).To(Equal("message-1")) 296 Expect(messages[0].Type()).To(Equal("OUT")) 297 Expect(messages[0].Timestamp()).To(Equal(time.Unix(0, 10))) 298 Expect(messages[0].SourceType()).To(Equal("some-source-type")) 299 Expect(messages[0].SourceInstance()).To(Equal("some-source-instance")) 300 301 Expect(messages[1].Message()).To(Equal("message-2")) 302 Expect(messages[1].Type()).To(Equal("OUT")) 303 Expect(messages[1].Timestamp()).To(Equal(time.Unix(0, 20))) 304 Expect(messages[1].SourceType()).To(Equal("some-source-type")) 305 Expect(messages[1].SourceInstance()).To(Equal("some-source-instance")) 306 }) 307 }) 308 309 Context("when NOAA errors", func() { 310 var expectedErr error 311 312 BeforeEach(func() { 313 expectedErr = errors.New("ZOMG") 314 fakeNOAAClient.RecentLogsReturns(nil, expectedErr) 315 }) 316 317 It("returns error and warnings", func() { 318 _, warnings, err := actor.GetRecentLogsForApplicationByNameAndSpace("some-app", "some-space-guid", fakeNOAAClient) 319 Expect(err).To(MatchError(expectedErr)) 320 Expect(warnings).To(ConsistOf("some-app-warnings")) 321 }) 322 }) 323 }) 324 325 Context("when finding the application errors", func() { 326 var expectedErr error 327 328 BeforeEach(func() { 329 expectedErr = errors.New("ZOMG") 330 fakeCloudControllerClient.GetApplicationsReturns( 331 nil, 332 ccv2.Warnings{"some-app-warnings"}, 333 expectedErr, 334 ) 335 }) 336 337 It("returns error and warnings", func() { 338 _, warnings, err := actor.GetRecentLogsForApplicationByNameAndSpace("some-app", "some-space-guid", fakeNOAAClient) 339 Expect(err).To(MatchError(expectedErr)) 340 Expect(warnings).To(ConsistOf("some-app-warnings")) 341 342 Expect(fakeNOAAClient.RecentLogsCallCount()).To(Equal(0)) 343 }) 344 }) 345 }) 346 347 Describe("GetStreamingLogsForApplicationByNameAndSpace", func() { 348 Context("when the application can be found", func() { 349 var ( 350 expectedAppGUID string 351 352 eventStream chan *events.LogMessage 353 errStream chan error 354 355 messages <-chan *LogMessage 356 logErrs <-chan error 357 ) 358 359 // If tests panic due to this close, it is likely you have a failing 360 // expectation and the channels are being closed because the test has 361 // failed/short circuited and is going through teardown. 362 AfterEach(func() { 363 close(eventStream) 364 close(errStream) 365 366 Eventually(messages).Should(BeClosed()) 367 Eventually(logErrs).Should(BeClosed()) 368 }) 369 370 BeforeEach(func() { 371 expectedAppGUID = "some-app-guid" 372 373 eventStream = make(chan *events.LogMessage) 374 errStream = make(chan error) 375 fakeCloudControllerClient.GetApplicationsReturns( 376 []ccv2.Application{ 377 { 378 Name: "some-app", 379 GUID: expectedAppGUID, 380 }, 381 }, 382 ccv2.Warnings{"some-app-warnings"}, 383 nil, 384 ) 385 386 fakeNOAAClient.TailingLogsStub = func(appGUID string, authToken string) (<-chan *events.LogMessage, <-chan error) { 387 Expect(appGUID).To(Equal(expectedAppGUID)) 388 Expect(authToken).To(BeEmpty()) 389 390 go func() { 391 outMessage := events.LogMessage_OUT 392 ts1 := int64(10) 393 sourceType := "some-source-type" 394 sourceInstance := "some-source-instance" 395 396 eventStream <- &events.LogMessage{ 397 Message: []byte("message-1"), 398 MessageType: &outMessage, 399 Timestamp: &ts1, 400 SourceType: &sourceType, 401 SourceInstance: &sourceInstance, 402 } 403 404 errMessage := events.LogMessage_ERR 405 ts2 := int64(20) 406 407 eventStream <- &events.LogMessage{ 408 Message: []byte("message-2"), 409 MessageType: &errMessage, 410 Timestamp: &ts2, 411 SourceType: &sourceType, 412 SourceInstance: &sourceInstance, 413 } 414 }() 415 416 return eventStream, errStream 417 } 418 }) 419 420 It("converts them to log messages and passes them through the messages channel", func() { 421 var err error 422 var warnings Warnings 423 messages, logErrs, warnings, err = actor.GetStreamingLogsForApplicationByNameAndSpace("some-app", "some-space-guid", fakeNOAAClient) 424 425 Expect(err).ToNot(HaveOccurred()) 426 Expect(warnings).To(ConsistOf("some-app-warnings")) 427 428 message := <-messages 429 Expect(message.Message()).To(Equal("message-1")) 430 Expect(message.Type()).To(Equal("OUT")) 431 Expect(message.Timestamp()).To(Equal(time.Unix(0, 10))) 432 Expect(message.SourceType()).To(Equal("some-source-type")) 433 Expect(message.SourceInstance()).To(Equal("some-source-instance")) 434 435 message = <-messages 436 Expect(message.Message()).To(Equal("message-2")) 437 Expect(message.Type()).To(Equal("ERR")) 438 Expect(message.Timestamp()).To(Equal(time.Unix(0, 20))) 439 Expect(message.SourceType()).To(Equal("some-source-type")) 440 Expect(message.SourceInstance()).To(Equal("some-source-instance")) 441 }) 442 }) 443 444 Context("when finding the application errors", func() { 445 var expectedErr error 446 447 BeforeEach(func() { 448 expectedErr = errors.New("ZOMG") 449 fakeCloudControllerClient.GetApplicationsReturns( 450 nil, 451 ccv2.Warnings{"some-app-warnings"}, 452 expectedErr, 453 ) 454 }) 455 456 It("returns error and warnings", func() { 457 _, _, warnings, err := actor.GetStreamingLogsForApplicationByNameAndSpace("some-app", "some-space-guid", fakeNOAAClient) 458 Expect(err).To(MatchError(expectedErr)) 459 Expect(warnings).To(ConsistOf("some-app-warnings")) 460 461 Expect(fakeNOAAClient.TailingLogsCallCount()).To(Equal(0)) 462 }) 463 }) 464 }) 465 })