github.com/sleungcy/cli@v7.1.0+incompatible/command/v7/logs_command_test.go (about)

     1  package v7_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"time"
     7  
     8  	"code.cloudfoundry.org/cli/actor/actionerror"
     9  	"code.cloudfoundry.org/cli/actor/sharedaction"
    10  	"code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes"
    11  	"code.cloudfoundry.org/cli/actor/v7action"
    12  	"code.cloudfoundry.org/cli/command/commandfakes"
    13  	. "code.cloudfoundry.org/cli/command/v7"
    14  	"code.cloudfoundry.org/cli/command/v7/v7fakes"
    15  	"code.cloudfoundry.org/cli/util/configv3"
    16  	"code.cloudfoundry.org/cli/util/ui"
    17  	. "github.com/onsi/ginkgo"
    18  	. "github.com/onsi/gomega"
    19  	. "github.com/onsi/gomega/gbytes"
    20  )
    21  
    22  var _ = Describe("logs command", func() {
    23  	var (
    24  		cmd             LogsCommand
    25  		testUI          *ui.UI
    26  		fakeConfig      *commandfakes.FakeConfig
    27  		fakeSharedActor *commandfakes.FakeSharedActor
    28  		fakeActor       *v7fakes.FakeActor
    29  		logCacheClient  *sharedactionfakes.FakeLogCacheClient
    30  		binaryName      string
    31  		executeErr      error
    32  	)
    33  
    34  	BeforeEach(func() {
    35  		testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer())
    36  		fakeConfig = new(commandfakes.FakeConfig)
    37  		fakeSharedActor = new(commandfakes.FakeSharedActor)
    38  		fakeActor = new(v7fakes.FakeActor)
    39  		logCacheClient = new(sharedactionfakes.FakeLogCacheClient)
    40  
    41  		cmd = LogsCommand{
    42  			BaseCommand: BaseCommand{
    43  				UI:          testUI,
    44  				Config:      fakeConfig,
    45  				SharedActor: fakeSharedActor,
    46  				Actor:       fakeActor,
    47  			},
    48  			LogCacheClient: logCacheClient,
    49  		}
    50  
    51  		binaryName = "faceman"
    52  		fakeConfig.BinaryNameReturns(binaryName)
    53  		cmd.RequiredArgs.AppName = "some-app"
    54  		fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil)
    55  	})
    56  
    57  	JustBeforeEach(func() {
    58  		executeErr = cmd.Execute(nil)
    59  	})
    60  
    61  	When("the checkTarget fails", func() {
    62  		BeforeEach(func() {
    63  			fakeSharedActor.CheckTargetReturns(
    64  				actionerror.NotLoggedInError{BinaryName: binaryName})
    65  		})
    66  		It("returns an error", func() {
    67  			orgRequired, spaceRequired := fakeSharedActor.CheckTargetArgsForCall(0)
    68  			Expect(orgRequired).To(BeTrue())
    69  			Expect(spaceRequired).To(BeTrue())
    70  
    71  			Expect(executeErr).To(MatchError(
    72  				actionerror.NotLoggedInError{BinaryName: binaryName}))
    73  		})
    74  	})
    75  
    76  	When("checkTarget succeeds", func() {
    77  		BeforeEach(func() {
    78  			fakeConfig.TargetedSpaceReturns(configv3.Space{
    79  				Name: "some-space-name",
    80  				GUID: "some-space-guid",
    81  			})
    82  			fakeConfig.TargetedOrganizationReturns(configv3.Organization{
    83  				Name: "some-org-name",
    84  			})
    85  		})
    86  
    87  		When("the --recent flag is provided", func() {
    88  			BeforeEach(func() {
    89  				cmd.Recent = true
    90  			})
    91  
    92  			It("displays flavor text", func() {
    93  				Expect(testUI.Out).To(Say("Retrieving logs for app some-app in org some-org-name / space some-space-name as some-user..."))
    94  			})
    95  
    96  			When("the logs actor returns an error", func() {
    97  				var expectedErr error
    98  				BeforeEach(func() {
    99  					expectedErr = errors.New("some-error")
   100  					fakeActor.GetRecentLogsForApplicationByNameAndSpaceReturns(
   101  						[]sharedaction.LogMessage{
   102  							*sharedaction.NewLogMessage(
   103  								"all your base are belong to us",
   104  								"1",
   105  								time.Unix(0, 0),
   106  								"app",
   107  								"1",
   108  							),
   109  						},
   110  						v7action.Warnings{"some-warning-1", "some-warning-2"},
   111  						expectedErr)
   112  				})
   113  
   114  				It("displays the errors along with the logs and warnings", func() {
   115  					Expect(executeErr).To(MatchError(expectedErr))
   116  					Expect(testUI.Out).To(Say("all your base are belong to us"))
   117  					Expect(testUI.Err).To(Say("some-warning-1"))
   118  					Expect(testUI.Err).To(Say("some-warning-2"))
   119  				})
   120  			})
   121  
   122  			When("the logs actor returns logs", func() {
   123  				BeforeEach(func() {
   124  					fakeActor.GetRecentLogsForApplicationByNameAndSpaceReturns(
   125  						[]sharedaction.LogMessage{
   126  							*sharedaction.NewLogMessage(
   127  								"i am message 1",
   128  								"1",
   129  								time.Unix(0, 0),
   130  								"app",
   131  								"1",
   132  							),
   133  							*sharedaction.NewLogMessage(
   134  								"i am message 2",
   135  								"1",
   136  								time.Unix(1, 0),
   137  								"another-app",
   138  								"2",
   139  							),
   140  						},
   141  						v7action.Warnings{"some-warning-1", "some-warning-2"},
   142  						nil)
   143  				})
   144  
   145  				It("displays the recent log messages and warnings", func() {
   146  					Expect(executeErr).NotTo(HaveOccurred())
   147  					Expect(testUI.Err).To(Say("some-warning-1"))
   148  					Expect(testUI.Err).To(Say("some-warning-2"))
   149  
   150  					Expect(testUI.Out).To(Say("i am message 1"))
   151  					Expect(testUI.Out).To(Say("i am message 2"))
   152  
   153  					Expect(fakeActor.GetRecentLogsForApplicationByNameAndSpaceCallCount()).To(Equal(1))
   154  					appName, spaceGUID, client := fakeActor.GetRecentLogsForApplicationByNameAndSpaceArgsForCall(0)
   155  
   156  					Expect(appName).To(Equal("some-app"))
   157  					Expect(spaceGUID).To(Equal("some-space-guid"))
   158  					Expect(client).To(Equal(logCacheClient))
   159  				})
   160  			})
   161  		})
   162  
   163  		When("the --recent flag is not provided", func() {
   164  			BeforeEach(func() {
   165  				cmd.Recent = false
   166  				fakeActor.ScheduleTokenRefreshStub = func(
   167  					after func(time.Duration) <-chan time.Time,
   168  					stop chan struct{}, stoppedRefreshing chan struct{}) (<-chan error, error) {
   169  					errCh := make(chan error, 1)
   170  					go func() {
   171  						<-stop
   172  						close(stoppedRefreshing)
   173  					}()
   174  					return errCh, nil
   175  				}
   176  			})
   177  
   178  			When("the logs setup returns an error", func() {
   179  				var expectedErr error
   180  
   181  				BeforeEach(func() {
   182  					expectedErr = errors.New("some-error")
   183  					fakeActor.GetStreamingLogsForApplicationByNameAndSpaceReturns(nil,
   184  						nil,
   185  						nil,
   186  						v7action.Warnings{"some-warning-1",
   187  							"some-warning-2"},
   188  						expectedErr)
   189  				})
   190  
   191  				It("displays the error and all warnings", func() {
   192  					Expect(executeErr).To(MatchError(expectedErr))
   193  					Expect(testUI.Err).To(Say("some-warning-1"))
   194  					Expect(testUI.Err).To(Say("some-warning-2"))
   195  				})
   196  			})
   197  
   198  			When("the logs stream returns an error", func() {
   199  				var (
   200  					expectedErr                 error
   201  					cancelFunctionHasBeenCalled bool
   202  				)
   203  
   204  				BeforeEach(func() {
   205  					expectedErr = errors.New("banana")
   206  
   207  					fakeActor.GetStreamingLogsForApplicationByNameAndSpaceStub =
   208  						func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (
   209  							<-chan sharedaction.LogMessage,
   210  							<-chan error,
   211  							context.CancelFunc,
   212  							v7action.Warnings, error) {
   213  							logStream := make(chan sharedaction.LogMessage)
   214  							errorStream := make(chan error)
   215  							cancelFunctionHasBeenCalled = false
   216  							streamsWereClosed := false
   217  
   218  							cancelFunc := func() {
   219  								if cancelFunctionHasBeenCalled {
   220  									return
   221  								}
   222  								cancelFunctionHasBeenCalled = true
   223  								if !streamsWereClosed {
   224  									close(logStream)
   225  									close(errorStream)
   226  									streamsWereClosed = true
   227  								}
   228  							}
   229  							go func() {
   230  								errorStream <- expectedErr
   231  								close(logStream)
   232  								close(errorStream)
   233  								streamsWereClosed = true
   234  							}()
   235  
   236  							return logStream, errorStream, cancelFunc, v7action.Warnings{"steve for all I care"}, nil
   237  						}
   238  				})
   239  
   240  				When("the token refresher returns an error", func() {
   241  					BeforeEach(func() {
   242  						cmd.Recent = false
   243  						fakeActor.ScheduleTokenRefreshReturns(nil, errors.New("firs swimming"))
   244  					})
   245  					It("displays the errors", func() {
   246  						Expect(executeErr).To(MatchError("firs swimming"))
   247  						Expect(fakeActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(0))
   248  					})
   249  				})
   250  
   251  				It("displays the error and all warnings", func() {
   252  					Expect(executeErr).NotTo(HaveOccurred())
   253  					Expect(testUI.Err).To(Say("steve for all I care"))
   254  					Expect(cancelFunctionHasBeenCalled).To(BeTrue())
   255  				})
   256  			})
   257  
   258  			When("the logs actor returns logs", func() {
   259  				BeforeEach(func() {
   260  					fakeActor.GetStreamingLogsForApplicationByNameAndSpaceStub =
   261  						func(_ string, _ string, _ sharedaction.LogCacheClient) (
   262  							<-chan sharedaction.LogMessage,
   263  							<-chan error, context.CancelFunc,
   264  							v7action.Warnings,
   265  							error) {
   266  
   267  							logStream := make(chan sharedaction.LogMessage)
   268  							errorStream := make(chan error)
   269  
   270  							go func() {
   271  								logStream <- *sharedaction.NewLogMessage("Here are some staging logs!", "OUT", time.Now(), sharedaction.StagingLog, "sourceInstance") //TODO: is it ok to leave staging logs here?
   272  								logStream <- *sharedaction.NewLogMessage("Here are some other staging logs!", "OUT", time.Now(), sharedaction.StagingLog, "sourceInstance")
   273  								close(logStream)
   274  								close(errorStream)
   275  							}()
   276  
   277  							return logStream, errorStream, func() {}, v7action.Warnings{"some-warning-1", "some-warning-2"}, nil
   278  						}
   279  				})
   280  
   281  				It("displays flavor text", func() {
   282  					Expect(testUI.Out).To(Say("Retrieving logs for app some-app in org some-org-name / space some-space-name as some-user..."))
   283  				})
   284  
   285  				It("displays all streaming log messages and warnings", func() {
   286  					Expect(executeErr).NotTo(HaveOccurred())
   287  					Expect(testUI.Err).To(Say("some-warning-1"))
   288  					Expect(testUI.Err).To(Say("some-warning-2"))
   289  
   290  					Expect(testUI.Out).To(Say("Here are some staging logs!"))
   291  					Expect(testUI.Out).To(Say("Here are some other staging logs!"))
   292  
   293  					Expect(fakeActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(1))
   294  					appName, spaceGUID, client := fakeActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(0)
   295  
   296  					Expect(appName).To(Equal("some-app"))
   297  					Expect(spaceGUID).To(Equal("some-space-guid"))
   298  					Expect(client).To(Equal(logCacheClient))
   299  				})
   300  
   301  				When("scheduling a token refresh errors immediately", func() {
   302  					BeforeEach(func() {
   303  						cmd.Recent = false
   304  						fakeActor.ScheduleTokenRefreshReturns(nil, errors.New("fjords pining"))
   305  					})
   306  					It("displays the errors", func() {
   307  						Expect(executeErr).To(MatchError("fjords pining"))
   308  						Expect(fakeActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(0))
   309  					})
   310  				})
   311  
   312  				When("there is an error refreshing a token sometime later", func() {
   313  					BeforeEach(func() {
   314  						cmd.Recent = false
   315  						fakeActor.ScheduleTokenRefreshStub = func(
   316  							after func(time.Duration) <-chan time.Time,
   317  							stop chan struct{}, stoppedRefreshing chan struct{}) (<-chan error, error) {
   318  							errCh := make(chan error, 1)
   319  							go func() {
   320  								errCh <- errors.New("fjords pining")
   321  								<-stop
   322  								close(stoppedRefreshing)
   323  							}()
   324  							return errCh, nil
   325  						}
   326  					})
   327  					It("displays the errors", func() {
   328  						Expect(executeErr).NotTo(HaveOccurred())
   329  						Expect(fakeActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(1))
   330  						Expect(testUI.Err).To(Say("fjords pining"))
   331  					})
   332  				})
   333  			})
   334  		})
   335  	})
   336  })