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  })