github.com/sleungcy/cli@v7.1.0+incompatible/command/v7/stage_package_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/api/cloudcontroller/ccv3/constant"
    13  	"code.cloudfoundry.org/cli/command/commandfakes"
    14  	"code.cloudfoundry.org/cli/command/flag"
    15  	v7 "code.cloudfoundry.org/cli/command/v7"
    16  	"code.cloudfoundry.org/cli/command/v7/v7fakes"
    17  	"code.cloudfoundry.org/cli/resources"
    18  	"code.cloudfoundry.org/cli/util/configv3"
    19  	"code.cloudfoundry.org/cli/util/ui"
    20  	. "github.com/onsi/ginkgo"
    21  	. "github.com/onsi/gomega"
    22  	. "github.com/onsi/gomega/gbytes"
    23  )
    24  
    25  var _ = Describe("stage-package Command", func() {
    26  	const dropletCreateTime = "2017-08-14T21:16:42Z"
    27  
    28  	var (
    29  		cmd                v7.StagePackageCommand
    30  		testUI             *ui.UI
    31  		fakeConfig         *commandfakes.FakeConfig
    32  		fakeSharedActor    *commandfakes.FakeSharedActor
    33  		fakeActor          *v7fakes.FakeActor
    34  		fakeLogCacheClient *sharedactionfakes.FakeLogCacheClient
    35  
    36  		binaryName  string
    37  		executeErr  error
    38  		appName     string
    39  		packageGUID string
    40  		spaceGUID   string
    41  		app         resources.Application
    42  
    43  		allLogsWritten   chan bool
    44  		closedTheStreams bool
    45  	)
    46  
    47  	BeforeEach(func() {
    48  		testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer())
    49  		fakeConfig = new(commandfakes.FakeConfig)
    50  		fakeSharedActor = new(commandfakes.FakeSharedActor)
    51  		fakeActor = new(v7fakes.FakeActor)
    52  		fakeLogCacheClient = new(sharedactionfakes.FakeLogCacheClient)
    53  
    54  		fakeConfig.StagingTimeoutReturns(10 * time.Minute)
    55  
    56  		binaryName = "faceman"
    57  		fakeConfig.BinaryNameReturns(binaryName)
    58  		appName = "some-app"
    59  		packageGUID = "some-package-guid"
    60  		spaceGUID = "some-space-guid"
    61  
    62  		cmd = v7.StagePackageCommand{
    63  			RequiredArgs: flag.AppName{AppName: appName},
    64  			PackageGUID:  packageGUID,
    65  			BaseCommand: v7.BaseCommand{
    66  				UI:          testUI,
    67  				Config:      fakeConfig,
    68  				SharedActor: fakeSharedActor,
    69  				Actor:       fakeActor,
    70  			},
    71  			LogCacheClient: fakeLogCacheClient,
    72  		}
    73  
    74  		fakeConfig.HasTargetedOrganizationReturns(true)
    75  		fakeConfig.TargetedOrganizationReturns(configv3.Organization{
    76  			GUID: "some-org-guid",
    77  			Name: "some-org",
    78  		})
    79  		fakeConfig.HasTargetedSpaceReturns(true)
    80  		fakeConfig.TargetedSpaceReturns(configv3.Space{
    81  			GUID: spaceGUID,
    82  			Name: "some-space",
    83  		})
    84  		fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil)
    85  
    86  		allLogsWritten = make(chan bool)
    87  		fakeActor.GetStreamingLogsForApplicationByNameAndSpaceStub = func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) {
    88  			logStream := make(chan sharedaction.LogMessage)
    89  			errorStream := make(chan error)
    90  			closedTheStreams = false
    91  
    92  			cancelFunc := func() {
    93  				if closedTheStreams {
    94  					return
    95  				}
    96  				closedTheStreams = true
    97  				close(logStream)
    98  				close(errorStream)
    99  			}
   100  
   101  			go func() {
   102  				logStream <- *sharedaction.NewLogMessage("Here are some staging logs!", "OUT", time.Now(), sharedaction.StagingLog, "sourceInstance")
   103  				logStream <- *sharedaction.NewLogMessage("Here are some other staging logs!", "OUT", time.Now(), sharedaction.StagingLog, "sourceInstance")
   104  				errorStream <- errors.New("problem getting more staging logs")
   105  				allLogsWritten <- true
   106  			}()
   107  
   108  			return logStream, errorStream, cancelFunc, v7action.Warnings{"steve for all I care"}, nil
   109  		}
   110  
   111  		fakeActor.StagePackageStub = func(packageGUID, appName, spaceGUID string) (<-chan resources.Droplet, <-chan v7action.Warnings, <-chan error) {
   112  			dropletStream := make(chan resources.Droplet)
   113  			warningsStream := make(chan v7action.Warnings)
   114  			errorStream := make(chan error)
   115  
   116  			go func() {
   117  				<-allLogsWritten
   118  				defer close(dropletStream)
   119  				defer close(warningsStream)
   120  				defer close(errorStream)
   121  				warningsStream <- v7action.Warnings{"some-warning", "some-other-warning"}
   122  				dropletStream <- resources.Droplet{
   123  					GUID:      "some-droplet-guid",
   124  					CreatedAt: dropletCreateTime,
   125  					State:     constant.DropletStaged,
   126  				}
   127  			}()
   128  
   129  			return dropletStream, warningsStream, errorStream
   130  		}
   131  	})
   132  
   133  	JustBeforeEach(func() {
   134  		executeErr = cmd.Execute(nil)
   135  	})
   136  
   137  	When("checking target fails", func() {
   138  		BeforeEach(func() {
   139  			fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName})
   140  		})
   141  
   142  		It("displays the experimental warning", func() {
   143  			Expect(testUI.Err).NotTo(Say("This command is in EXPERIMENTAL stage and may change without notice"))
   144  		})
   145  
   146  		It("returns an error", func() {
   147  			Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName}))
   148  
   149  			Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1))
   150  			checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0)
   151  			Expect(checkTargetedOrg).To(BeTrue())
   152  			Expect(checkTargetedSpace).To(BeTrue())
   153  		})
   154  	})
   155  
   156  	When("the package's GUID is not passed in", func() {
   157  		var (
   158  			newestPackageGUID string
   159  		)
   160  
   161  		BeforeEach(func() {
   162  			cmd.PackageGUID = ""
   163  			app = resources.Application{GUID: "some-app-guid", Name: "some-name"}
   164  			newestPackageGUID = "newest-package-guid"
   165  
   166  			fakeActor.GetApplicationByNameAndSpaceReturns(
   167  				app,
   168  				v7action.Warnings{"app-by-name-warning"},
   169  				nil)
   170  
   171  			fakeActor.GetNewestReadyPackageForApplicationReturns(
   172  				v7action.Package{GUID: newestPackageGUID},
   173  				v7action.Warnings{"newest-pkg-warning"},
   174  				nil)
   175  		})
   176  
   177  		It("grabs the most recent version", func() {
   178  			Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
   179  			appNameArg, spaceGUIDArg := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0)
   180  			Expect(appNameArg).To(Equal(cmd.RequiredArgs.AppName))
   181  			Expect(spaceGUIDArg).To(Equal(spaceGUID))
   182  			Expect(testUI.Err).To(Say("app-by-name-warning"))
   183  
   184  			Expect(fakeActor.GetNewestReadyPackageForApplicationCallCount()).To(Equal(1))
   185  			appArg := fakeActor.GetNewestReadyPackageForApplicationArgsForCall(0)
   186  			Expect(appArg).To(Equal(app))
   187  			Expect(testUI.Err).To(Say("newest-pkg-warning"))
   188  
   189  			Expect(fakeActor.StagePackageCallCount()).To(Equal(1))
   190  			guidArg, appNameArg, spaceGUIDArg := fakeActor.StagePackageArgsForCall(0)
   191  			Expect(guidArg).To(Equal(newestPackageGUID))
   192  			Expect(appNameArg).To(Equal(appName))
   193  			Expect(spaceGUIDArg).To(Equal(spaceGUID))
   194  		})
   195  		When("It can't get the application's information", func() {
   196  			BeforeEach(func() {
   197  				fakeActor.GetApplicationByNameAndSpaceReturns(
   198  					resources.Application{},
   199  					v7action.Warnings{"app-warning"},
   200  					errors.New("cant-get-app-error"))
   201  			})
   202  
   203  			It("returns an error", func() {
   204  				Expect(executeErr).To(HaveOccurred())
   205  				Expect(testUI.Err).To(Say("app-warning"))
   206  				Expect(executeErr).To(MatchError("cant-get-app-error"))
   207  			})
   208  		})
   209  	})
   210  
   211  	When("the logging stream has errors", func() {
   212  		var (
   213  			expectedErr      error
   214  			allLogsWritten   chan bool
   215  			closedTheStreams bool
   216  		)
   217  
   218  		BeforeEach(func() {
   219  			allLogsWritten = make(chan bool)
   220  			expectedErr = errors.New("banana")
   221  
   222  			fakeActor.GetStreamingLogsForApplicationByNameAndSpaceStub = func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) {
   223  				logStream := make(chan sharedaction.LogMessage)
   224  				errorStream := make(chan error)
   225  				closedTheStreams = false
   226  
   227  				cancelFunc := func() {
   228  					if closedTheStreams {
   229  						return
   230  					}
   231  					closedTheStreams = true
   232  					close(logStream)
   233  					close(errorStream)
   234  				}
   235  				go func() {
   236  					logStream <- *sharedaction.NewLogMessage("Here are some staging logs!", "err", time.Now(), sharedaction.StagingLog, "sourceInstance")
   237  					errorStream <- expectedErr
   238  					allLogsWritten <- true
   239  				}()
   240  
   241  				return logStream, errorStream, cancelFunc, v7action.Warnings{"steve for all I care"}, nil
   242  			}
   243  
   244  			fakeActor.StagePackageStub = func(packageGUID, _, _ string) (<-chan resources.Droplet, <-chan v7action.Warnings, <-chan error) {
   245  				dropletStream := make(chan resources.Droplet)
   246  				warningsStream := make(chan v7action.Warnings)
   247  				errorStream := make(chan error)
   248  
   249  				go func() {
   250  					<-allLogsWritten
   251  					defer close(dropletStream)
   252  					defer close(warningsStream)
   253  					defer close(errorStream)
   254  					warningsStream <- v7action.Warnings{"some-warning", "some-other-warning"}
   255  					dropletStream <- resources.Droplet{
   256  						GUID:      "some-droplet-guid",
   257  						CreatedAt: "2017-08-14T21:16:42Z",
   258  						State:     constant.DropletStaged,
   259  					}
   260  				}()
   261  
   262  				return dropletStream, warningsStream, errorStream
   263  			}
   264  		})
   265  
   266  		JustAfterEach(func() {
   267  			Expect(closedTheStreams).To(BeTrue())
   268  		})
   269  
   270  		It("displays the errors and continues staging", func() {
   271  			Expect(executeErr).ToNot(HaveOccurred())
   272  
   273  			Expect(testUI.Err).To(Say("banana"))
   274  			Expect(testUI.Err).To(Say("some-warning"))
   275  			Expect(testUI.Err).To(Say("some-other-warning"))
   276  		})
   277  	})
   278  
   279  	When("the logging returns an error due to an API error", func() {
   280  		var expectedErr error
   281  
   282  		BeforeEach(func() {
   283  			expectedErr = errors.New("something is wrong!")
   284  			logStream := make(chan sharedaction.LogMessage)
   285  			errorStream := make(chan error)
   286  			cancelFunc := func() {
   287  				close(logStream)
   288  				close(errorStream)
   289  			}
   290  			fakeActor.GetStreamingLogsForApplicationByNameAndSpaceReturns(logStream, errorStream, cancelFunc, v7action.Warnings{"some-warning", "some-other-warning"}, expectedErr)
   291  		})
   292  
   293  		It("returns the error and displays warnings", func() {
   294  			Expect(executeErr).To(Equal(expectedErr))
   295  
   296  			Expect(testUI.Err).To(Say("some-warning"))
   297  			Expect(testUI.Err).To(Say("some-other-warning"))
   298  		})
   299  	})
   300  
   301  	When("the staging returns an error", func() {
   302  		var expectedErr error
   303  
   304  		BeforeEach(func() {
   305  			expectedErr = errors.New("any gibberish")
   306  			fakeActor.StagePackageStub = func(packageGUID, _, _ string) (<-chan resources.Droplet, <-chan v7action.Warnings, <-chan error) {
   307  				dropletStream := make(chan resources.Droplet)
   308  				warningsStream := make(chan v7action.Warnings)
   309  				errorStream := make(chan error)
   310  
   311  				go func() {
   312  					<-allLogsWritten
   313  					defer close(dropletStream)
   314  					defer close(warningsStream)
   315  					defer close(errorStream)
   316  					warningsStream <- v7action.Warnings{"some-warning", "some-other-warning"}
   317  					errorStream <- expectedErr
   318  				}()
   319  
   320  				return dropletStream, warningsStream, errorStream
   321  			}
   322  		})
   323  
   324  		It("returns the error and displays warnings", func() {
   325  			Expect(executeErr).To(Equal(expectedErr))
   326  
   327  			Expect(testUI.Err).To(Say("some-warning"))
   328  			Expect(testUI.Err).To(Say("some-other-warning"))
   329  			Expect(closedTheStreams).To(BeTrue())
   330  		})
   331  	})
   332  
   333  	It("outputs the droplet GUID", func() {
   334  		Expect(executeErr).ToNot(HaveOccurred())
   335  
   336  		createdAtTimeParsed, err := time.Parse(time.RFC3339, dropletCreateTime)
   337  		Expect(err).ToNot(HaveOccurred())
   338  
   339  		Expect(testUI.Out).To(Say("Staging package for %s in org some-org / space some-space as steve...", appName))
   340  		Expect(testUI.Out).To(Say("\n\n"))
   341  		Expect(testUI.Out).To(Say("Package staged"))
   342  		Expect(testUI.Out).To(Say(`droplet guid:\s+some-droplet-guid`))
   343  		Expect(testUI.Out).To(Say(`state:\s+staged`))
   344  		Expect(testUI.Out).To(Say(`created:\s+%s`, testUI.UserFriendlyDate(createdAtTimeParsed)))
   345  
   346  		Expect(testUI.Err).To(Say("some-warning"))
   347  		Expect(testUI.Err).To(Say("some-other-warning"))
   348  	})
   349  
   350  	It("stages the package", func() {
   351  		Expect(executeErr).ToNot(HaveOccurred())
   352  		Expect(fakeActor.StagePackageCallCount()).To(Equal(1))
   353  		guidArg, appNameArg, spaceGUIDArg := fakeActor.StagePackageArgsForCall(0)
   354  		Expect(guidArg).To(Equal(packageGUID))
   355  		Expect(appNameArg).To(Equal(appName))
   356  		Expect(spaceGUIDArg).To(Equal("some-space-guid"))
   357  	})
   358  
   359  	It("displays staging logs and their warnings", func() {
   360  		Expect(testUI.Out).To(Say("Here are some staging logs!"))
   361  		Expect(testUI.Out).To(Say("Here are some other staging logs!"))
   362  
   363  		Expect(testUI.Err).To(Say("steve for all I care"))
   364  		Eventually(testUI.Err).Should(Say("Failed to retrieve logs from Log Cache: problem getting more staging logs"))
   365  
   366  		Expect(fakeActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(1))
   367  		appNameArg, spaceGUID, logCacheClient := fakeActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(0)
   368  		Expect(appNameArg).To(Equal(appName))
   369  		Expect(spaceGUID).To(Equal("some-space-guid"))
   370  		Expect(logCacheClient).To(Equal(fakeLogCacheClient))
   371  
   372  		Expect(fakeActor.StagePackageCallCount()).To(Equal(1))
   373  		guidArg, appNameArg, spaceGUIDArg := fakeActor.StagePackageArgsForCall(0)
   374  		Expect(guidArg).To(Equal(packageGUID))
   375  		Expect(appNameArg).To(Equal(appName))
   376  		Expect(spaceGUIDArg).To(Equal(spaceGUID))
   377  
   378  		Expect(closedTheStreams).To(BeTrue())
   379  	})
   380  })