github.com/dcarley/cf-cli@v6.24.1-0.20170220111324-4225ff346898+incompatible/command/v2/start_command_test.go (about) 1 package v2_test 2 3 import ( 4 "errors" 5 "time" 6 7 "code.cloudfoundry.org/cli/actor/sharedaction" 8 "code.cloudfoundry.org/cli/actor/v2action" 9 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2" 10 "code.cloudfoundry.org/cli/command" 11 "code.cloudfoundry.org/cli/command/commandfakes" 12 "code.cloudfoundry.org/cli/command/v2" 13 "code.cloudfoundry.org/cli/command/v2/shared" 14 "code.cloudfoundry.org/cli/command/v2/v2fakes" 15 "code.cloudfoundry.org/cli/util/configv3" 16 "code.cloudfoundry.org/cli/util/ui" 17 "github.com/cloudfoundry/bytefmt" 18 . "github.com/onsi/ginkgo" 19 . "github.com/onsi/gomega" 20 . "github.com/onsi/gomega/gbytes" 21 ) 22 23 var _ = Describe("Start Command", func() { 24 var ( 25 cmd v2.StartCommand 26 testUI *ui.UI 27 fakeConfig *commandfakes.FakeConfig 28 fakeSharedActor *commandfakes.FakeSharedActor 29 fakeActor *v2fakes.FakeStartActor 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(v2fakes.FakeStartActor) 39 40 cmd = v2.StartCommand{ 41 UI: testUI, 42 Config: fakeConfig, 43 SharedActor: fakeSharedActor, 44 Actor: fakeActor, 45 } 46 47 cmd.RequiredArgs.AppName = "some-app" 48 49 binaryName = "faceman" 50 fakeConfig.BinaryNameReturns(binaryName) 51 52 // TODO: remove when experimental flag is removed 53 fakeConfig.ExperimentalReturns(true) 54 55 var err error 56 testUI.TimezoneLocation, err = time.LoadLocation("America/Los_Angeles") 57 Expect(err).NotTo(HaveOccurred()) 58 59 fakeActor.StartApplicationStub = func(app v2action.Application, client v2action.NOAAClient, config v2action.Config) (<-chan *v2action.LogMessage, <-chan error, <-chan string, <-chan error) { 60 messages := make(chan *v2action.LogMessage) 61 logErrs := make(chan error) 62 warnings := make(chan string) 63 errs := make(chan error) 64 65 go func() { 66 close(messages) 67 close(logErrs) 68 close(warnings) 69 close(errs) 70 }() 71 72 return messages, logErrs, warnings, errs 73 } 74 }) 75 76 JustBeforeEach(func() { 77 executeErr = cmd.Execute(nil) 78 }) 79 80 // TODO: remove when experimental flag is removed 81 It("Displays the experimental warning message", func() { 82 Expect(testUI.Out).To(Say(command.ExperimentalWarning)) 83 }) 84 85 Context("when checking target fails", func() { 86 BeforeEach(func() { 87 fakeSharedActor.CheckTargetReturns(sharedaction.NotLoggedInError{BinaryName: binaryName}) 88 }) 89 90 It("returns an error if the check fails", func() { 91 Expect(executeErr).To(MatchError(command.NotLoggedInError{BinaryName: "faceman"})) 92 93 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 94 _, checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 95 Expect(checkTargetedOrg).To(BeTrue()) 96 Expect(checkTargetedSpace).To(BeTrue()) 97 }) 98 }) 99 100 Context("when the user is logged in, and org and space are targeted", func() { 101 BeforeEach(func() { 102 fakeConfig.HasTargetedOrganizationReturns(true) 103 fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) 104 fakeConfig.HasTargetedSpaceReturns(true) 105 fakeConfig.TargetedSpaceReturns(configv3.Space{ 106 GUID: "some-space-guid", 107 Name: "some-space"}) 108 fakeConfig.CurrentUserReturns( 109 configv3.User{Name: "some-user"}, 110 nil) 111 }) 112 113 Context("when getting the current user returns an error", func() { 114 var expectedErr error 115 116 BeforeEach(func() { 117 expectedErr = errors.New("getting current user error") 118 fakeConfig.CurrentUserReturns( 119 configv3.User{}, 120 expectedErr) 121 }) 122 123 It("returns the error", func() { 124 Expect(executeErr).To(MatchError(expectedErr)) 125 }) 126 }) 127 128 It("displays flavor text", func() { 129 Expect(testUI.Out).To(Say("Starting app some-app in org some-org / space some-space as some-user...")) 130 }) 131 132 Context("when the app exists", func() { 133 Context("when the app is already started", func() { 134 BeforeEach(func() { 135 fakeActor.GetApplicationByNameAndSpaceReturns( 136 v2action.Application{State: ccv2.ApplicationStarted}, 137 v2action.Warnings{"warning-1", "warning-2"}, 138 nil, 139 ) 140 }) 141 142 It("short circuits and displays message", func() { 143 Expect(executeErr).ToNot(HaveOccurred()) 144 145 Expect(testUI.Out).To(Say("App some-app is already started")) 146 147 Expect(testUI.Err).To(Say("warning-1")) 148 Expect(testUI.Err).To(Say("warning-2")) 149 150 Expect(fakeActor.StartApplicationCallCount()).To(Equal(0)) 151 }) 152 }) 153 154 Context("when the app is not already started", func() { 155 BeforeEach(func() { 156 fakeActor.GetApplicationByNameAndSpaceReturns( 157 v2action.Application{GUID: "app-guid", State: ccv2.ApplicationStopped}, 158 v2action.Warnings{"warning-1", "warning-2"}, 159 nil, 160 ) 161 }) 162 163 It("starts the app", func() { 164 Expect(executeErr).ToNot(HaveOccurred()) 165 166 Expect(testUI.Err).To(Say("warning-1")) 167 Expect(testUI.Err).To(Say("warning-2")) 168 169 Expect(fakeActor.StartApplicationCallCount()).To(Equal(1)) 170 app, _, config := fakeActor.StartApplicationArgsForCall(0) 171 Expect(app.GUID).To(Equal("app-guid")) 172 Expect(config).To(Equal(fakeConfig)) 173 }) 174 175 Context("when passed a log message", func() { 176 BeforeEach(func() { 177 fakeActor.StartApplicationStub = func(app v2action.Application, client v2action.NOAAClient, config v2action.Config) (<-chan *v2action.LogMessage, <-chan error, <-chan string, <-chan error) { 178 messages := make(chan *v2action.LogMessage) 179 logErrs := make(chan error) 180 warnings := make(chan string) 181 errs := make(chan error) 182 183 go func() { 184 messages <- v2action.NewLogMessage("log message 1", 1, time.Unix(0, 0), "APP", "1") 185 messages <- v2action.NewLogMessage("log message 2", 1, time.Unix(0, 0), "APP", "1") 186 close(messages) 187 close(logErrs) 188 close(warnings) 189 close(errs) 190 }() 191 192 return messages, logErrs, warnings, errs 193 } 194 }) 195 196 It("displays the log", func() { 197 Expect(executeErr).ToNot(HaveOccurred()) 198 Expect(testUI.Out).To(Say("log message 1")) 199 Expect(testUI.Out).To(Say("log message 2")) 200 }) 201 }) 202 203 Context("when passed an log err", func() { 204 var expectedErr error 205 206 BeforeEach(func() { 207 expectedErr = errors.New("err log message") 208 fakeActor.StartApplicationStub = func(app v2action.Application, client v2action.NOAAClient, config v2action.Config) (<-chan *v2action.LogMessage, <-chan error, <-chan string, <-chan error) { 209 messages := make(chan *v2action.LogMessage) 210 logErrs := make(chan error) 211 warnings := make(chan string) 212 errs := make(chan error) 213 214 go func() { 215 logErrs <- expectedErr 216 close(messages) 217 close(logErrs) 218 close(warnings) 219 close(errs) 220 }() 221 222 return messages, logErrs, warnings, errs 223 } 224 }) 225 226 It("stops logging and returns the error", func() { 227 Expect(executeErr).To(MatchError(expectedErr)) 228 }) 229 }) 230 231 Context("when passed a warning", func() { 232 BeforeEach(func() { 233 fakeActor.StartApplicationStub = func(app v2action.Application, client v2action.NOAAClient, config v2action.Config) (<-chan *v2action.LogMessage, <-chan error, <-chan string, <-chan error) { 234 messages := make(chan *v2action.LogMessage) 235 logErrs := make(chan error) 236 warnings := make(chan string) 237 errs := make(chan error) 238 239 go func() { 240 warnings <- "warning 1" 241 warnings <- "warning 2" 242 close(messages) 243 close(logErrs) 244 close(warnings) 245 close(errs) 246 }() 247 248 return messages, logErrs, warnings, errs 249 } 250 }) 251 252 It("displays the warnings to STDERR", func() { 253 Expect(executeErr).ToNot(HaveOccurred()) 254 Expect(testUI.Err).To(Say("warning 1")) 255 Expect(testUI.Err).To(Say("warning 2")) 256 }) 257 }) 258 259 Context("when passed an API err", func() { 260 Describe("an unexpected error", func() { 261 var expectedErr error 262 263 BeforeEach(func() { 264 expectedErr = errors.New("err log message") 265 fakeActor.StartApplicationStub = func(app v2action.Application, client v2action.NOAAClient, config v2action.Config) (<-chan *v2action.LogMessage, <-chan error, <-chan string, <-chan error) { 266 messages := make(chan *v2action.LogMessage) 267 logErrs := make(chan error) 268 warnings := make(chan string) 269 errs := make(chan error) 270 271 go func() { 272 errs <- expectedErr 273 close(messages) 274 close(logErrs) 275 close(warnings) 276 close(errs) 277 }() 278 279 return messages, logErrs, warnings, errs 280 } 281 }) 282 283 It("stops logging and returns the error", func() { 284 Expect(executeErr).To(MatchError(expectedErr)) 285 }) 286 }) 287 288 Describe("staging error", func() { 289 BeforeEach(func() { 290 fakeActor.StartApplicationStub = func(app v2action.Application, client v2action.NOAAClient, config v2action.Config) (<-chan *v2action.LogMessage, <-chan error, <-chan string, <-chan error) { 291 messages := make(chan *v2action.LogMessage) 292 logErrs := make(chan error) 293 warnings := make(chan string) 294 errs := make(chan error) 295 296 go func() { 297 errs <- v2action.StagingFailedError{Reason: "Something, but not nothing"} 298 close(messages) 299 close(logErrs) 300 close(warnings) 301 close(errs) 302 }() 303 304 return messages, logErrs, warnings, errs 305 } 306 }) 307 308 It("stops logging and returns StagingFailedError", func() { 309 Expect(executeErr).To(MatchError(shared.StagingFailedError{BinaryName: "faceman", Message: "Something, but not nothing"})) 310 }) 311 }) 312 }) 313 314 Context("when the app finishes starting", func() { 315 var ( 316 applicationSummary v2action.ApplicationSummary 317 warnings []string 318 ) 319 320 BeforeEach(func() { 321 applicationSummary = v2action.ApplicationSummary{ 322 Application: v2action.Application{ 323 Name: "some-app", 324 GUID: "some-app-guid", 325 Instances: 3, 326 Memory: 128, 327 PackageUpdatedAt: time.Unix(0, 0), 328 DetectedBuildpack: "some-buildpack", 329 State: "STARTED", 330 DetectedStartCommand: "some start command", 331 }, 332 Stack: v2action.Stack{ 333 Name: "potatos", 334 }, 335 Routes: []v2action.Route{ 336 { 337 Host: "banana", 338 Domain: "fruit.com", 339 Path: "/hi", 340 }, 341 { 342 Domain: "foobar.com", 343 Port: 13, 344 }, 345 }, 346 } 347 warnings = []string{"app-summary-warning"} 348 349 applicationSummary.RunningInstances = []v2action.ApplicationInstanceWithStats{ 350 { 351 ID: 0, 352 State: v2action.ApplicationInstanceState(ccv2.ApplicationInstanceRunning), 353 Since: 1403140717.984577, 354 CPU: 0.73, 355 Disk: 50 * bytefmt.MEGABYTE, 356 DiskQuota: 2048 * bytefmt.MEGABYTE, 357 Memory: 100 * bytefmt.MEGABYTE, 358 MemoryQuota: 128 * bytefmt.MEGABYTE, 359 Details: "info from the backend", 360 }, 361 } 362 363 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil) 364 }) 365 366 It("displays the app summary and it's warnings", func() { 367 Expect(executeErr).ToNot(HaveOccurred()) 368 Expect(testUI.Out).To(Say("Name:\\s+some-app")) 369 Expect(testUI.Out).To(Say("Requested state:\\s+started")) 370 Expect(testUI.Out).To(Say("Instances:\\s+1\\/3")) 371 Expect(testUI.Out).To(Say("Usage:\\s+128M x 3 instances")) 372 Expect(testUI.Out).To(Say("Routes:\\s+banana.fruit.com/hi, foobar.com:13")) 373 Expect(testUI.Out).To(Say("Last uploaded:\\s+1970-01-01T00:00:00Z")) 374 Expect(testUI.Out).To(Say("Stack:\\s+potatos")) 375 Expect(testUI.Out).To(Say("Buildpack:\\s+some-buildpack")) 376 Expect(testUI.Out).To(Say("Start command:\\s+some start command")) 377 378 Expect(testUI.Err).To(Say("app-summary-warning")) 379 }) 380 381 It("should display the instance table", func() { 382 Expect(executeErr).ToNot(HaveOccurred()) 383 Expect(testUI.Out).To(Say("State\\s+Since\\s+CPU\\s+Memory\\s+Disk")) 384 Expect(testUI.Out).To(Say(`#0\s+running\s+2014-06-19T01:18:37Z\s+73.0%\s+100M of 128M\s+50M of 2G\s+info from the backend`)) 385 }) 386 }) 387 }) 388 }) 389 390 Context("when the app does *not* exists", func() { 391 BeforeEach(func() { 392 fakeActor.GetApplicationByNameAndSpaceReturns( 393 v2action.Application{}, 394 v2action.Warnings{"warning-1", "warning-2"}, 395 v2action.ApplicationNotFoundError{Name: "some-app"}, 396 ) 397 }) 398 399 It("returns back an error", func() { 400 Expect(executeErr).To(MatchError(command.ApplicationNotFoundError{Name: "some-app"})) 401 402 Expect(testUI.Err).To(Say("warning-1")) 403 Expect(testUI.Err).To(Say("warning-2")) 404 }) 405 }) 406 }) 407 })