code.cloudfoundry.org/cli@v7.1.0+incompatible/command/v7/scale_command_test.go (about)

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