github.com/willmadison/cli@v6.40.1-0.20181018160101-29d5937903ff+incompatible/command/v6/v3_scale_command_test.go (about)

     1  package v6_test
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"code.cloudfoundry.org/cli/actor/actionerror"
     8  	"code.cloudfoundry.org/cli/actor/v3action"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
    11  	"code.cloudfoundry.org/cli/command/commandfakes"
    12  	"code.cloudfoundry.org/cli/command/translatableerror"
    13  	. "code.cloudfoundry.org/cli/command/v6"
    14  	"code.cloudfoundry.org/cli/command/v6/shared"
    15  	"code.cloudfoundry.org/cli/command/v6/shared/sharedfakes"
    16  	"code.cloudfoundry.org/cli/command/v6/v6fakes"
    17  	"code.cloudfoundry.org/cli/integration/helpers"
    18  	"code.cloudfoundry.org/cli/types"
    19  	"code.cloudfoundry.org/cli/util/configv3"
    20  	"code.cloudfoundry.org/cli/util/ui"
    21  	. "github.com/onsi/ginkgo"
    22  	. "github.com/onsi/gomega"
    23  	. "github.com/onsi/gomega/gbytes"
    24  )
    25  
    26  var _ = Describe("v3-scale Command", func() {
    27  	var (
    28  		cmd             V3ScaleCommand
    29  		input           *Buffer
    30  		output          *Buffer
    31  		testUI          *ui.UI
    32  		fakeConfig      *commandfakes.FakeConfig
    33  		fakeSharedActor *commandfakes.FakeSharedActor
    34  		fakeActor       *v6fakes.FakeV3ScaleActor
    35  		fakeV2Actor     *sharedfakes.FakeV2AppActor
    36  		appName         string
    37  		binaryName      string
    38  		executeErr      error
    39  	)
    40  
    41  	BeforeEach(func() {
    42  		input = NewBuffer()
    43  		output = NewBuffer()
    44  		testUI = ui.NewTestUI(input, output, NewBuffer())
    45  		fakeConfig = new(commandfakes.FakeConfig)
    46  		fakeSharedActor = new(commandfakes.FakeSharedActor)
    47  		fakeActor = new(v6fakes.FakeV3ScaleActor)
    48  		fakeV2Actor = new(sharedfakes.FakeV2AppActor)
    49  		appName = "some-app"
    50  
    51  		cmd = V3ScaleCommand{
    52  			UI:          testUI,
    53  			Config:      fakeConfig,
    54  			SharedActor: fakeSharedActor,
    55  			Actor:       fakeActor,
    56  			AppSummaryDisplayer: shared.AppSummaryDisplayer{
    57  				UI:         testUI,
    58  				Config:     fakeConfig,
    59  				Actor:      fakeActor,
    60  				V2AppActor: fakeV2Actor,
    61  				AppName:    appName,
    62  			},
    63  		}
    64  
    65  		binaryName = "faceman"
    66  		fakeConfig.BinaryNameReturns(binaryName)
    67  
    68  		cmd.RequiredArgs.AppName = appName
    69  		cmd.ProcessType = constant.ProcessTypeWeb
    70  	})
    71  
    72  	JustBeforeEach(func() {
    73  		executeErr = cmd.Execute(nil)
    74  	})
    75  
    76  	When("the API version is below the minimum", func() {
    77  		BeforeEach(func() {
    78  			fakeActor.CloudControllerAPIVersionReturns(ccversion.MinV3ClientVersion)
    79  		})
    80  
    81  		It("returns a MinimumAPIVersionNotMetError", func() {
    82  			Expect(executeErr).To(MatchError(translatableerror.MinimumCFAPIVersionNotMetError{
    83  				CurrentVersion: ccversion.MinV3ClientVersion,
    84  				MinimumVersion: ccversion.MinVersionApplicationFlowV3,
    85  			}))
    86  		})
    87  
    88  		It("displays the experimental warning", func() {
    89  			Expect(testUI.Err).To(Say("This command is in EXPERIMENTAL stage and may change without notice"))
    90  		})
    91  	})
    92  
    93  	When("checking target fails", func() {
    94  		BeforeEach(func() {
    95  			fakeActor.CloudControllerAPIVersionReturns(ccversion.MinVersionApplicationFlowV3)
    96  			fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName})
    97  		})
    98  
    99  		It("returns an error", func() {
   100  			Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName}))
   101  
   102  			Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1))
   103  			checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0)
   104  			Expect(checkTargetedOrg).To(BeTrue())
   105  			Expect(checkTargetedSpace).To(BeTrue())
   106  		})
   107  	})
   108  
   109  	When("the user is logged in, and org and space are targeted", func() {
   110  		BeforeEach(func() {
   111  			fakeActor.CloudControllerAPIVersionReturns(ccversion.MinVersionApplicationFlowV3)
   112  			fakeConfig.HasTargetedOrganizationReturns(true)
   113  			fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"})
   114  			fakeConfig.HasTargetedSpaceReturns(true)
   115  			fakeConfig.TargetedSpaceReturns(configv3.Space{
   116  				GUID: "some-space-guid",
   117  				Name: "some-space"})
   118  			fakeConfig.CurrentUserReturns(
   119  				configv3.User{Name: "some-user"},
   120  				nil)
   121  		})
   122  
   123  		When("getting the current user returns an error", func() {
   124  			var expectedErr error
   125  
   126  			BeforeEach(func() {
   127  				expectedErr = errors.New("getting current user error")
   128  				fakeConfig.CurrentUserReturns(
   129  					configv3.User{},
   130  					expectedErr)
   131  			})
   132  
   133  			It("returns the error", func() {
   134  				Expect(executeErr).To(MatchError(expectedErr))
   135  			})
   136  		})
   137  
   138  		When("the application does not exist", func() {
   139  			BeforeEach(func() {
   140  				fakeActor.GetApplicationByNameAndSpaceReturns(
   141  					v3action.Application{},
   142  					v3action.Warnings{"get-app-warning"},
   143  					actionerror.ApplicationNotFoundError{Name: appName})
   144  			})
   145  
   146  			It("returns an ApplicationNotFoundError and all warnings", func() {
   147  				Expect(executeErr).To(Equal(actionerror.ApplicationNotFoundError{Name: appName}))
   148  
   149  				Expect(testUI.Out).ToNot(Say("Showing"))
   150  				Expect(testUI.Out).ToNot(Say("Scaling"))
   151  				Expect(testUI.Err).To(Say("get-app-warning"))
   152  
   153  				Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
   154  				appNameArg, spaceGUIDArg := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0)
   155  				Expect(appNameArg).To(Equal(appName))
   156  				Expect(spaceGUIDArg).To(Equal("some-space-guid"))
   157  			})
   158  		})
   159  
   160  		When("an error occurs getting the application", func() {
   161  			var expectedErr error
   162  
   163  			BeforeEach(func() {
   164  				expectedErr = errors.New("get app error")
   165  				fakeActor.GetApplicationByNameAndSpaceReturns(
   166  					v3action.Application{},
   167  					v3action.Warnings{"get-app-warning"},
   168  					expectedErr)
   169  			})
   170  
   171  			It("returns the error and displays all warnings", func() {
   172  				Expect(executeErr).To(Equal(expectedErr))
   173  				Expect(testUI.Err).To(Say("get-app-warning"))
   174  			})
   175  		})
   176  
   177  		When("the application exists", func() {
   178  			var appSummary v3action.ApplicationSummary
   179  
   180  			BeforeEach(func() {
   181  				appSummary = v3action.ApplicationSummary{
   182  					ProcessSummaries: v3action.ProcessSummaries{
   183  						{
   184  							Process: v3action.Process{
   185  								Type:       constant.ProcessTypeWeb,
   186  								MemoryInMB: types.NullUint64{Value: 32, IsSet: true},
   187  								DiskInMB:   types.NullUint64{Value: 1024, IsSet: true},
   188  							},
   189  							InstanceDetails: []v3action.ProcessInstance{
   190  								v3action.ProcessInstance{
   191  									Index:       0,
   192  									State:       constant.ProcessInstanceRunning,
   193  									MemoryUsage: 1000000,
   194  									DiskUsage:   1000000,
   195  									MemoryQuota: 33554432,
   196  									DiskQuota:   2000000,
   197  									Uptime:      int(time.Now().Sub(time.Unix(267321600, 0)).Seconds()),
   198  								},
   199  								v3action.ProcessInstance{
   200  									Index:       1,
   201  									State:       constant.ProcessInstanceRunning,
   202  									MemoryUsage: 2000000,
   203  									DiskUsage:   2000000,
   204  									MemoryQuota: 33554432,
   205  									DiskQuota:   4000000,
   206  									Uptime:      int(time.Now().Sub(time.Unix(330480000, 0)).Seconds()),
   207  								},
   208  								v3action.ProcessInstance{
   209  									Index:       2,
   210  									State:       constant.ProcessInstanceRunning,
   211  									MemoryUsage: 3000000,
   212  									DiskUsage:   3000000,
   213  									MemoryQuota: 33554432,
   214  									DiskQuota:   6000000,
   215  									Uptime:      int(time.Now().Sub(time.Unix(1277164800, 0)).Seconds()),
   216  								},
   217  							},
   218  						},
   219  						{
   220  							Process: v3action.Process{
   221  								Type:       "console",
   222  								MemoryInMB: types.NullUint64{Value: 16, IsSet: true},
   223  								DiskInMB:   types.NullUint64{Value: 512, IsSet: true},
   224  							},
   225  							InstanceDetails: []v3action.ProcessInstance{
   226  								v3action.ProcessInstance{
   227  									Index:       0,
   228  									State:       constant.ProcessInstanceRunning,
   229  									MemoryUsage: 1000000,
   230  									DiskUsage:   1000000,
   231  									MemoryQuota: 33554432,
   232  									DiskQuota:   8000000,
   233  									Uptime:      int(time.Now().Sub(time.Unix(167572800, 0)).Seconds()),
   234  								},
   235  							},
   236  						},
   237  					},
   238  				}
   239  
   240  				fakeActor.GetApplicationByNameAndSpaceReturns(
   241  					v3action.Application{GUID: "some-app-guid"},
   242  					v3action.Warnings{"get-app-warning"},
   243  					nil)
   244  			})
   245  
   246  			When("no flag options are provided", func() {
   247  				BeforeEach(func() {
   248  					fakeActor.GetApplicationSummaryByNameAndSpaceReturns(
   249  						appSummary,
   250  						v3action.Warnings{"get-app-summary-warning"},
   251  						nil)
   252  				})
   253  
   254  				It("displays current scale properties and all warnings", func() {
   255  					Expect(executeErr).ToNot(HaveOccurred())
   256  
   257  					Expect(testUI.Out).ToNot(Say("Scaling"))
   258  					Expect(testUI.Out).ToNot(Say("This will cause the app to restart"))
   259  					Expect(testUI.Out).ToNot(Say("Stopping"))
   260  					Expect(testUI.Out).ToNot(Say("Starting"))
   261  					Expect(testUI.Out).ToNot(Say("Waiting"))
   262  					Expect(testUI.Out).To(Say("Showing current scale of app some-app in org some-org / space some-space as some-user\\.\\.\\."))
   263  
   264  					firstAppTable := helpers.ParseV3AppProcessTable(output.Contents())
   265  					Expect(len(firstAppTable.Processes)).To(Equal(2))
   266  
   267  					webProcessSummary := firstAppTable.Processes[0]
   268  					Expect(webProcessSummary.Type).To(Equal("web"))
   269  					Expect(webProcessSummary.InstanceCount).To(Equal("3/3"))
   270  					Expect(webProcessSummary.MemUsage).To(Equal("32M"))
   271  
   272  					Expect(webProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M"))
   273  					Expect(webProcessSummary.Instances[0].Disk).To(Equal("976.6K of 1.9M"))
   274  					Expect(webProcessSummary.Instances[0].CPU).To(Equal("0.0%"))
   275  
   276  					Expect(webProcessSummary.Instances[1].Memory).To(Equal("1.9M of 32M"))
   277  					Expect(webProcessSummary.Instances[1].Disk).To(Equal("1.9M of 3.8M"))
   278  					Expect(webProcessSummary.Instances[1].CPU).To(Equal("0.0%"))
   279  
   280  					Expect(webProcessSummary.Instances[2].Memory).To(Equal("2.9M of 32M"))
   281  					Expect(webProcessSummary.Instances[2].Disk).To(Equal("2.9M of 5.7M"))
   282  					Expect(webProcessSummary.Instances[2].CPU).To(Equal("0.0%"))
   283  
   284  					consoleProcessSummary := firstAppTable.Processes[1]
   285  					Expect(consoleProcessSummary.Type).To(Equal("console"))
   286  					Expect(consoleProcessSummary.InstanceCount).To(Equal("1/1"))
   287  					Expect(consoleProcessSummary.MemUsage).To(Equal("16M"))
   288  
   289  					Expect(consoleProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M"))
   290  					Expect(consoleProcessSummary.Instances[0].Disk).To(Equal("976.6K of 7.6M"))
   291  					Expect(consoleProcessSummary.Instances[0].CPU).To(Equal("0.0%"))
   292  
   293  					Expect(testUI.Err).To(Say("get-app-warning"))
   294  					Expect(testUI.Err).To(Say("get-app-summary-warning"))
   295  
   296  					Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(0))
   297  				})
   298  
   299  				When("an error is encountered getting process information", func() {
   300  					var expectedErr error
   301  
   302  					BeforeEach(func() {
   303  						expectedErr = errors.New("get process error")
   304  						fakeActor.GetApplicationSummaryByNameAndSpaceReturns(
   305  							v3action.ApplicationSummary{},
   306  							v3action.Warnings{"get-process-warning"},
   307  							expectedErr,
   308  						)
   309  					})
   310  
   311  					It("returns the error and displays all warnings", func() {
   312  						Expect(executeErr).To(Equal(expectedErr))
   313  						Expect(testUI.Err).To(Say("get-process-warning"))
   314  					})
   315  				})
   316  			})
   317  
   318  			When("all flag options are provided", func() {
   319  				BeforeEach(func() {
   320  					cmd.Instances.Value = 2
   321  					cmd.Instances.IsSet = true
   322  					cmd.DiskLimit.Value = 50
   323  					cmd.DiskLimit.IsSet = true
   324  					cmd.MemoryLimit.Value = 100
   325  					cmd.MemoryLimit.IsSet = true
   326  					fakeActor.ScaleProcessByApplicationReturns(
   327  						v3action.Warnings{"scale-warning"},
   328  						nil)
   329  					fakeActor.GetApplicationSummaryByNameAndSpaceReturns(
   330  						appSummary,
   331  						v3action.Warnings{"get-instances-warning"},
   332  						nil)
   333  				})
   334  
   335  				When("force flag is not provided", func() {
   336  					When("the user chooses default", func() {
   337  						BeforeEach(func() {
   338  							_, err := input.Write([]byte("\n"))
   339  							Expect(err).ToNot(HaveOccurred())
   340  						})
   341  
   342  						It("does not scale the app", func() {
   343  							Expect(executeErr).ToNot(HaveOccurred())
   344  
   345  							Expect(testUI.Out).ToNot(Say("Showing"))
   346  							Expect(testUI.Out).To(Say("Scaling app some-app in org some-org / space some-space as some-user\\.\\.\\."))
   347  							Expect(testUI.Out).To(Say("This will cause the app to restart\\. Are you sure you want to scale some-app\\? \\[yN\\]:"))
   348  							Expect(testUI.Out).To(Say("Scaling cancelled"))
   349  							Expect(testUI.Out).ToNot(Say("Stopping"))
   350  							Expect(testUI.Out).ToNot(Say("Starting"))
   351  							Expect(testUI.Out).ToNot(Say("Waiting"))
   352  
   353  							Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(0))
   354  						})
   355  					})
   356  
   357  					When("the user chooses no", func() {
   358  						BeforeEach(func() {
   359  							_, err := input.Write([]byte("n\n"))
   360  							Expect(err).ToNot(HaveOccurred())
   361  						})
   362  
   363  						It("does not scale the app", func() {
   364  							Expect(executeErr).ToNot(HaveOccurred())
   365  
   366  							Expect(testUI.Out).ToNot(Say("Showing"))
   367  							Expect(testUI.Out).To(Say("Scaling app some-app in org some-org / space some-space as some-user\\.\\.\\."))
   368  							Expect(testUI.Out).To(Say("This will cause the app to restart\\. Are you sure you want to scale some-app\\? \\[yN\\]:"))
   369  							Expect(testUI.Out).To(Say("Scaling cancelled"))
   370  							Expect(testUI.Out).ToNot(Say("Stopping"))
   371  							Expect(testUI.Out).ToNot(Say("Starting"))
   372  							Expect(testUI.Out).ToNot(Say("Waiting"))
   373  
   374  							Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(0))
   375  						})
   376  					})
   377  
   378  					When("the user chooses yes", func() {
   379  						BeforeEach(func() {
   380  							_, err := input.Write([]byte("y\n"))
   381  							Expect(err).ToNot(HaveOccurred())
   382  						})
   383  
   384  						When("polling succeeds", func() {
   385  							BeforeEach(func() {
   386  								fakeActor.PollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error {
   387  									warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"}
   388  									return nil
   389  								}
   390  							})
   391  
   392  							It("scales, restarts, and displays scale properties", func() {
   393  								Expect(executeErr).ToNot(HaveOccurred())
   394  
   395  								Expect(testUI.Out).To(Say("Scaling app some-app in org some-org / space some-space as some-user\\.\\.\\."))
   396  								Expect(testUI.Out).To(Say("This will cause the app to restart\\. Are you sure you want to scale some-app\\? \\[yN\\]:"))
   397  								Expect(testUI.Out).To(Say("Stopping app some-app in org some-org / space some-space as some-user\\.\\.\\."))
   398  								Expect(testUI.Out).To(Say("Starting app some-app in org some-org / space some-space as some-user\\.\\.\\."))
   399  
   400  								// Note that this does test that the disk quota was scaled to 96M,
   401  								// it is tested below when we check the arguments
   402  								// passed to ScaleProcessByApplication
   403  								firstAppTable := helpers.ParseV3AppProcessTable(output.Contents())
   404  								Expect(len(firstAppTable.Processes)).To(Equal(2))
   405  
   406  								webProcessSummary := firstAppTable.Processes[0]
   407  								Expect(webProcessSummary.Type).To(Equal("web"))
   408  								Expect(webProcessSummary.InstanceCount).To(Equal("3/3"))
   409  								Expect(webProcessSummary.MemUsage).To(Equal("32M"))
   410  
   411  								Expect(webProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M"))
   412  								Expect(webProcessSummary.Instances[0].Disk).To(Equal("976.6K of 1.9M"))
   413  								Expect(webProcessSummary.Instances[0].CPU).To(Equal("0.0%"))
   414  
   415  								Expect(webProcessSummary.Instances[1].Memory).To(Equal("1.9M of 32M"))
   416  								Expect(webProcessSummary.Instances[1].Disk).To(Equal("1.9M of 3.8M"))
   417  								Expect(webProcessSummary.Instances[1].CPU).To(Equal("0.0%"))
   418  
   419  								Expect(webProcessSummary.Instances[2].Memory).To(Equal("2.9M of 32M"))
   420  								Expect(webProcessSummary.Instances[2].Disk).To(Equal("2.9M of 5.7M"))
   421  								Expect(webProcessSummary.Instances[2].CPU).To(Equal("0.0%"))
   422  
   423  								consoleProcessSummary := firstAppTable.Processes[1]
   424  								Expect(consoleProcessSummary.Type).To(Equal("console"))
   425  								Expect(consoleProcessSummary.InstanceCount).To(Equal("1/1"))
   426  								Expect(consoleProcessSummary.MemUsage).To(Equal("16M"))
   427  
   428  								Expect(consoleProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M"))
   429  								Expect(consoleProcessSummary.Instances[0].Disk).To(Equal("976.6K of 7.6M"))
   430  								Expect(consoleProcessSummary.Instances[0].CPU).To(Equal("0.0%"))
   431  
   432  								Expect(testUI.Err).To(Say("get-app-warning"))
   433  								Expect(testUI.Err).To(Say("scale-warning"))
   434  								Expect(testUI.Err).To(Say("some-poll-warning-1"))
   435  								Expect(testUI.Err).To(Say("some-poll-warning-2"))
   436  								Expect(testUI.Err).To(Say("get-instances-warning"))
   437  
   438  								Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
   439  								appNameArg, spaceGUIDArg := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0)
   440  								Expect(appNameArg).To(Equal(appName))
   441  								Expect(spaceGUIDArg).To(Equal("some-space-guid"))
   442  
   443  								Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(1))
   444  								appGUIDArg, scaleProcess := fakeActor.ScaleProcessByApplicationArgsForCall(0)
   445  								Expect(appGUIDArg).To(Equal("some-app-guid"))
   446  								Expect(scaleProcess).To(Equal(v3action.Process{
   447  									Type:       constant.ProcessTypeWeb,
   448  									Instances:  types.NullInt{Value: 2, IsSet: true},
   449  									DiskInMB:   types.NullUint64{Value: 50, IsSet: true},
   450  									MemoryInMB: types.NullUint64{Value: 100, IsSet: true},
   451  								}))
   452  
   453  								Expect(fakeActor.StopApplicationCallCount()).To(Equal(1))
   454  								Expect(fakeActor.StopApplicationArgsForCall(0)).To(Equal("some-app-guid"))
   455  
   456  								Expect(fakeActor.StartApplicationCallCount()).To(Equal(1))
   457  								Expect(fakeActor.StartApplicationArgsForCall(0)).To(Equal("some-app-guid"))
   458  							})
   459  						})
   460  
   461  						When("polling the start fails", func() {
   462  							BeforeEach(func() {
   463  								fakeActor.PollStartStub = func(appGUID string, warnings chan<- v3action.Warnings) error {
   464  									warnings <- v3action.Warnings{"some-poll-warning-1", "some-poll-warning-2"}
   465  									return errors.New("some-error")
   466  								}
   467  							})
   468  
   469  							It("displays all warnings and fails", func() {
   470  								Expect(testUI.Err).To(Say("some-poll-warning-1"))
   471  								Expect(testUI.Err).To(Say("some-poll-warning-2"))
   472  
   473  								Expect(executeErr).To(MatchError("some-error"))
   474  							})
   475  						})
   476  
   477  						When("polling times out", func() {
   478  							BeforeEach(func() {
   479  								fakeActor.PollStartReturns(actionerror.StartupTimeoutError{})
   480  							})
   481  
   482  							It("returns the StartupTimeoutError", func() {
   483  								Expect(executeErr).To(MatchError(translatableerror.StartupTimeoutError{
   484  									AppName:    "some-app",
   485  									BinaryName: binaryName,
   486  								}))
   487  							})
   488  						})
   489  					})
   490  				})
   491  
   492  				When("force flag is provided", func() {
   493  					BeforeEach(func() {
   494  						cmd.Force = true
   495  					})
   496  
   497  					It("does not prompt user to confirm app restart", func() {
   498  						Expect(executeErr).ToNot(HaveOccurred())
   499  
   500  						Expect(testUI.Out).To(Say("Scaling app some-app in org some-org / space some-space as some-user\\.\\.\\."))
   501  						Expect(testUI.Out).NotTo(Say("This will cause the app to restart\\. Are you sure you want to scale some-app\\? \\[yN\\]:"))
   502  						Expect(testUI.Out).To(Say("Stopping app some-app in org some-org / space some-space as some-user\\.\\.\\."))
   503  						Expect(testUI.Out).To(Say("Starting app some-app in org some-org / space some-space as some-user\\.\\.\\."))
   504  
   505  						Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
   506  						Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(1))
   507  						Expect(fakeActor.StopApplicationCallCount()).To(Equal(1))
   508  						Expect(fakeActor.StartApplicationCallCount()).To(Equal(1))
   509  						Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1))
   510  					})
   511  				})
   512  			})
   513  
   514  			When("only the instances flag option is provided", func() {
   515  				BeforeEach(func() {
   516  					cmd.Instances.Value = 3
   517  					cmd.Instances.IsSet = true
   518  					fakeActor.ScaleProcessByApplicationReturns(
   519  						v3action.Warnings{"scale-warning"},
   520  						nil)
   521  					fakeActor.GetApplicationSummaryByNameAndSpaceReturns(
   522  						appSummary,
   523  						v3action.Warnings{"get-instances-warning"},
   524  						nil)
   525  				})
   526  
   527  				It("scales the number of instances, displays scale properties, and does not restart the application", func() {
   528  					Expect(executeErr).ToNot(HaveOccurred())
   529  
   530  					Expect(testUI.Out).To(Say("Scaling"))
   531  					Expect(testUI.Out).NotTo(Say("This will cause the app to restart"))
   532  					Expect(testUI.Out).NotTo(Say("Stopping"))
   533  					Expect(testUI.Out).NotTo(Say("Starting"))
   534  
   535  					Expect(testUI.Err).To(Say("get-app-warning"))
   536  					Expect(testUI.Err).To(Say("scale-warning"))
   537  					Expect(testUI.Err).To(Say("get-instances-warning"))
   538  
   539  					Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
   540  					appNameArg, spaceGUIDArg := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0)
   541  					Expect(appNameArg).To(Equal(appName))
   542  					Expect(spaceGUIDArg).To(Equal("some-space-guid"))
   543  
   544  					Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(1))
   545  					appGUIDArg, scaleProcess := fakeActor.ScaleProcessByApplicationArgsForCall(0)
   546  					Expect(appGUIDArg).To(Equal("some-app-guid"))
   547  					Expect(scaleProcess).To(Equal(v3action.Process{
   548  						Type:      constant.ProcessTypeWeb,
   549  						Instances: types.NullInt{Value: 3, IsSet: true},
   550  					}))
   551  
   552  					Expect(fakeActor.StopApplicationCallCount()).To(Equal(0))
   553  					Expect(fakeActor.StartApplicationCallCount()).To(Equal(0))
   554  				})
   555  			})
   556  
   557  			When("only the memory flag option is provided", func() {
   558  				BeforeEach(func() {
   559  					cmd.MemoryLimit.Value = 256
   560  					cmd.MemoryLimit.IsSet = true
   561  					fakeActor.ScaleProcessByApplicationReturns(
   562  						v3action.Warnings{"scale-warning"},
   563  						nil)
   564  					fakeActor.GetApplicationSummaryByNameAndSpaceReturns(
   565  						appSummary,
   566  						v3action.Warnings{"get-instances-warning"},
   567  						nil)
   568  
   569  					_, err := input.Write([]byte("y\n"))
   570  					Expect(err).ToNot(HaveOccurred())
   571  				})
   572  
   573  				It("scales, restarts, and displays scale properties", func() {
   574  					Expect(executeErr).ToNot(HaveOccurred())
   575  
   576  					Expect(testUI.Out).To(Say("Scaling"))
   577  					Expect(testUI.Out).To(Say("This will cause the app to restart"))
   578  					Expect(testUI.Out).To(Say("Stopping"))
   579  					Expect(testUI.Out).To(Say("Starting"))
   580  
   581  					Expect(testUI.Err).To(Say("get-app-warning"))
   582  					Expect(testUI.Err).To(Say("scale-warning"))
   583  					Expect(testUI.Err).To(Say("get-instances-warning"))
   584  
   585  					Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
   586  					appNameArg, spaceGUIDArg := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0)
   587  					Expect(appNameArg).To(Equal(appName))
   588  					Expect(spaceGUIDArg).To(Equal("some-space-guid"))
   589  
   590  					Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(1))
   591  					appGUIDArg, scaleProcess := fakeActor.ScaleProcessByApplicationArgsForCall(0)
   592  					Expect(appGUIDArg).To(Equal("some-app-guid"))
   593  					Expect(scaleProcess).To(Equal(v3action.Process{
   594  						Type:       constant.ProcessTypeWeb,
   595  						MemoryInMB: types.NullUint64{Value: 256, IsSet: true},
   596  					}))
   597  
   598  					Expect(fakeActor.StopApplicationCallCount()).To(Equal(1))
   599  					appGUID := fakeActor.StopApplicationArgsForCall(0)
   600  					Expect(appGUID).To(Equal("some-app-guid"))
   601  
   602  					Expect(fakeActor.StartApplicationCallCount()).To(Equal(1))
   603  					appGUID = fakeActor.StartApplicationArgsForCall(0)
   604  					Expect(appGUID).To(Equal("some-app-guid"))
   605  
   606  					Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1))
   607  				})
   608  			})
   609  
   610  			When("only the disk flag option is provided", func() {
   611  				BeforeEach(func() {
   612  					cmd.DiskLimit.Value = 1025
   613  					cmd.DiskLimit.IsSet = true
   614  					fakeActor.ScaleProcessByApplicationReturns(
   615  						v3action.Warnings{"scale-warning"},
   616  						nil)
   617  					fakeActor.GetApplicationSummaryByNameAndSpaceReturns(
   618  						appSummary,
   619  						v3action.Warnings{"get-instances-warning"},
   620  						nil)
   621  					_, err := input.Write([]byte("y\n"))
   622  					Expect(err).ToNot(HaveOccurred())
   623  				})
   624  
   625  				It("scales the number of instances, displays scale properties, and restarts the application", func() {
   626  					Expect(executeErr).ToNot(HaveOccurred())
   627  
   628  					Expect(testUI.Out).To(Say("Scaling"))
   629  					Expect(testUI.Out).To(Say("This will cause the app to restart"))
   630  					Expect(testUI.Out).To(Say("Stopping"))
   631  					Expect(testUI.Out).To(Say("Starting"))
   632  
   633  					Expect(testUI.Err).To(Say("get-app-warning"))
   634  					Expect(testUI.Err).To(Say("scale-warning"))
   635  					Expect(testUI.Err).To(Say("get-instances-warning"))
   636  
   637  					Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
   638  					appNameArg, spaceGUIDArg := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0)
   639  					Expect(appNameArg).To(Equal(appName))
   640  					Expect(spaceGUIDArg).To(Equal("some-space-guid"))
   641  
   642  					Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(1))
   643  					appGUIDArg, scaleProcess := fakeActor.ScaleProcessByApplicationArgsForCall(0)
   644  					Expect(appGUIDArg).To(Equal("some-app-guid"))
   645  					Expect(scaleProcess).To(Equal(v3action.Process{
   646  						Type:     constant.ProcessTypeWeb,
   647  						DiskInMB: types.NullUint64{Value: 1025, IsSet: true},
   648  					}))
   649  
   650  					Expect(fakeActor.StopApplicationCallCount()).To(Equal(1))
   651  					appGUID := fakeActor.StopApplicationArgsForCall(0)
   652  					Expect(appGUID).To(Equal("some-app-guid"))
   653  
   654  					Expect(fakeActor.StartApplicationCallCount()).To(Equal(1))
   655  					appGUID = fakeActor.StartApplicationArgsForCall(0)
   656  					Expect(appGUID).To(Equal("some-app-guid"))
   657  				})
   658  			})
   659  
   660  			When("process flag is provided", func() {
   661  				BeforeEach(func() {
   662  					cmd.ProcessType = "some-process-type"
   663  					cmd.Instances.Value = 2
   664  					cmd.Instances.IsSet = true
   665  					fakeActor.ScaleProcessByApplicationReturns(
   666  						v3action.Warnings{"scale-warning"},
   667  						nil)
   668  					fakeActor.GetApplicationSummaryByNameAndSpaceReturns(
   669  						appSummary,
   670  						v3action.Warnings{"get-instances-warning"},
   671  						nil)
   672  					_, err := input.Write([]byte("y\n"))
   673  					Expect(err).ToNot(HaveOccurred())
   674  				})
   675  
   676  				It("scales the specified process", func() {
   677  					Expect(executeErr).ToNot(HaveOccurred())
   678  
   679  					Expect(testUI.Out).To(Say("Scaling"))
   680  
   681  					Expect(testUI.Err).To(Say("get-app-warning"))
   682  					Expect(testUI.Err).To(Say("scale-warning"))
   683  					Expect(testUI.Err).To(Say("get-instances-warning"))
   684  
   685  					Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
   686  					appNameArg, spaceGUIDArg := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0)
   687  					Expect(appNameArg).To(Equal(appName))
   688  					Expect(spaceGUIDArg).To(Equal("some-space-guid"))
   689  
   690  					Expect(fakeActor.ScaleProcessByApplicationCallCount()).To(Equal(1))
   691  					appGUIDArg, scaleProcess := fakeActor.ScaleProcessByApplicationArgsForCall(0)
   692  					Expect(appGUIDArg).To(Equal("some-app-guid"))
   693  					Expect(scaleProcess).To(Equal(v3action.Process{
   694  						Type:      "some-process-type",
   695  						Instances: types.NullInt{Value: 2, IsSet: true},
   696  					}))
   697  				})
   698  			})
   699  
   700  			When("an error is encountered scaling the application", func() {
   701  				var expectedErr error
   702  
   703  				BeforeEach(func() {
   704  					cmd.Instances.Value = 3
   705  					cmd.Instances.IsSet = true
   706  					expectedErr = errors.New("scale process error")
   707  					fakeActor.ScaleProcessByApplicationReturns(
   708  						v3action.Warnings{"scale-process-warning"},
   709  						expectedErr,
   710  					)
   711  				})
   712  
   713  				It("returns the error and displays all warnings", func() {
   714  					Expect(executeErr).To(Equal(expectedErr))
   715  					Expect(testUI.Err).To(Say("scale-process-warning"))
   716  				})
   717  			})
   718  		})
   719  	})
   720  })