github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+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  })