github.com/randomtask1155/cli@v6.41.1-0.20181227003417-a98eed78cbde+incompatible/integration/v6/experimental/v3_scale_command_test.go (about) 1 package experimental 2 3 import ( 4 "fmt" 5 "strings" 6 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" 8 "code.cloudfoundry.org/cli/integration/helpers" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 . "github.com/onsi/gomega/gbytes" 12 . "github.com/onsi/gomega/gexec" 13 . "github.com/onsi/gomega/ghttp" 14 ) 15 16 var _ = Describe("v3-scale command", func() { 17 var ( 18 orgName string 19 spaceName string 20 appName string 21 userName string 22 ) 23 24 BeforeEach(func() { 25 orgName = helpers.NewOrgName() 26 spaceName = helpers.NewSpaceName() 27 appName = helpers.PrefixedRandomName("app") 28 userName, _ = helpers.GetCredentials() 29 }) 30 31 Describe("help", func() { 32 When("--help flag is set", func() { 33 It("displays command usage to output", func() { 34 session := helpers.CF("v3-scale", "--help") 35 36 Eventually(session).Should(Say("NAME:")) 37 Eventually(session).Should(Say("v3-scale - Change or view the instance count, disk space limit, and memory limit for an app")) 38 39 Eventually(session).Should(Say("USAGE:")) 40 Eventually(session).Should(Say(`cf v3-scale APP_NAME \[--process PROCESS\] \[-i INSTANCES\] \[-k DISK\] \[-m MEMORY\]`)) 41 42 Eventually(session).Should(Say("OPTIONS:")) 43 Eventually(session).Should(Say(`-f\s+Force restart of app without prompt`)) 44 Eventually(session).Should(Say(`-i\s+Number of instances`)) 45 Eventually(session).Should(Say(`-k\s+Disk limit \(e\.g\. 256M, 1024M, 1G\)`)) 46 Eventually(session).Should(Say(`-m\s+Memory limit \(e\.g\. 256M, 1024M, 1G\)`)) 47 Eventually(session).Should(Say(`--process\s+App process to scale \(Default: web\)`)) 48 49 Eventually(session).Should(Say("ENVIRONMENT:")) 50 Eventually(session).Should(Say(`CF_STARTUP_TIMEOUT=5\s+Max wait time for app instance startup, in minutes`)) 51 52 Eventually(session).Should(Exit(0)) 53 }) 54 }) 55 }) 56 57 It("displays the experimental warning", func() { 58 session := helpers.CF("v3-scale", appName) 59 Eventually(session.Err).Should(Say("This command is in EXPERIMENTAL stage and may change without notice")) 60 Eventually(session).Should(Exit()) 61 }) 62 63 When("the environment is not setup correctly", func() { 64 When("no API endpoint is set", func() { 65 BeforeEach(func() { 66 helpers.UnsetAPI() 67 }) 68 69 It("fails with no API endpoint set message", func() { 70 session := helpers.CF("v3-scale", appName) 71 Eventually(session).Should(Say("FAILED")) 72 Eventually(session.Err).Should(Say(`No API endpoint set\. Use 'cf login' or 'cf api' to target an endpoint\.`)) 73 Eventually(session).Should(Exit(1)) 74 }) 75 }) 76 77 When("the v3 api version is lower than the minimum version", func() { 78 var server *Server 79 80 BeforeEach(func() { 81 server = helpers.StartAndTargetServerWithAPIVersions(helpers.DefaultV2Version, ccversion.MinV3ClientVersion) 82 }) 83 84 AfterEach(func() { 85 server.Close() 86 }) 87 88 It("fails with error message that the minimum version is not met", func() { 89 session := helpers.CF("v3-scale", appName) 90 Eventually(session).Should(Say("FAILED")) 91 Eventually(session.Err).Should(Say(`This command requires CF API version 3\.27\.0 or higher\.`)) 92 Eventually(session).Should(Exit(1)) 93 }) 94 }) 95 96 When("not logged in", func() { 97 BeforeEach(func() { 98 helpers.LogoutCF() 99 }) 100 101 It("fails with not logged in message", func() { 102 session := helpers.CF("v3-scale", appName) 103 Eventually(session).Should(Say("FAILED")) 104 Eventually(session.Err).Should(Say(`Not logged in\. Use 'cf login' to log in\.`)) 105 Eventually(session).Should(Exit(1)) 106 }) 107 }) 108 109 When("there is no org set", func() { 110 BeforeEach(func() { 111 helpers.LogoutCF() 112 helpers.LoginCF() 113 }) 114 115 It("fails with no org targeted error message", func() { 116 session := helpers.CF("v3-scale", appName) 117 Eventually(session).Should(Say("FAILED")) 118 Eventually(session.Err).Should(Say(`No org targeted, use 'cf target -o ORG' to target an org\.`)) 119 Eventually(session).Should(Exit(1)) 120 }) 121 }) 122 123 When("there is no space set", func() { 124 BeforeEach(func() { 125 helpers.LogoutCF() 126 helpers.LoginCF() 127 helpers.TargetOrg(ReadOnlyOrg) 128 }) 129 130 It("fails with no space targeted error message", func() { 131 session := helpers.CF("v3-scale", appName) 132 Eventually(session).Should(Say("FAILED")) 133 Eventually(session.Err).Should(Say(`No space targeted, use 'cf target -s SPACE' to target a space\.`)) 134 Eventually(session).Should(Exit(1)) 135 }) 136 }) 137 }) 138 139 When("the environment is set up correctly", func() { 140 BeforeEach(func() { 141 helpers.SetupCF(orgName, spaceName) 142 }) 143 144 AfterEach(func() { 145 helpers.QuickDeleteOrg(orgName) 146 }) 147 148 When("the app name is not provided", func() { 149 It("tells the user that the app name is required, prints help text, and exits 1", func() { 150 session := helpers.CF("v3-scale") 151 152 Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `APP_NAME` was not provided")) 153 Eventually(session).Should(Say("NAME:")) 154 Eventually(session).Should(Exit(1)) 155 }) 156 }) 157 158 When("the app does not exist", func() { 159 It("displays app not found and exits 1", func() { 160 invalidAppName := "invalid-app-name" 161 session := helpers.CF("v3-scale", invalidAppName) 162 Eventually(session.Err).Should(Say("App %s not found", invalidAppName)) 163 Eventually(session).Should(Say("FAILED")) 164 Eventually(session).Should(Exit(1)) 165 }) 166 }) 167 168 When("the app exists", func() { 169 BeforeEach(func() { 170 helpers.WithProcfileApp(func(appDir string) { 171 Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName)).Should(Exit(0)) 172 }) 173 }) 174 175 When("scale option flags are not provided", func() { 176 It("displays the current scale properties for all processes", func() { 177 session := helpers.CF("v3-scale", appName) 178 179 Eventually(session).Should(Say(`Showing current scale of app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 180 Consistently(session).ShouldNot(Say("Scaling")) 181 Consistently(session).ShouldNot(Say("This will cause the app to restart")) 182 Consistently(session).ShouldNot(Say("Stopping")) 183 Consistently(session).ShouldNot(Say("Starting")) 184 Consistently(session).ShouldNot(Say("Waiting")) 185 Eventually(session).Should(Exit(0)) 186 187 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 188 Expect(len(appTable.Processes)).To(Equal(2)) 189 190 processSummary := appTable.Processes[0] 191 Expect(processSummary.Type).To(Equal("web")) 192 Expect(processSummary.InstanceCount).To(Equal("1/1")) 193 194 instanceSummary := processSummary.Instances[0] 195 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 196 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 197 198 Expect(appTable.Processes[1].Type).To(Equal("console")) 199 Expect(appTable.Processes[1].InstanceCount).To(Equal("0/0")) 200 }) 201 }) 202 203 When("only one scale option flag is provided", func() { 204 It("scales the app accordingly", func() { 205 By("verifying we start with a single instance") 206 session := helpers.CF("v3-scale", appName) 207 Eventually(session).Should(Exit(0)) 208 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 209 Expect(appTable.Processes).To(HaveLen(2)) 210 211 By("scaling to 3 instances") 212 session = helpers.CF("v3-scale", appName, "-i", "3") 213 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 214 Consistently(session).ShouldNot(Say("This will cause the app to restart")) 215 Consistently(session).ShouldNot(Say("Stopping")) 216 Consistently(session).ShouldNot(Say("Starting")) 217 Eventually(session).Should(Exit(0)) 218 219 updatedAppTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 220 Expect(updatedAppTable.Processes).To(HaveLen(2)) 221 222 processSummary := updatedAppTable.Processes[0] 223 instanceSummary := processSummary.Instances[0] 224 Expect(processSummary.Type).To(Equal("web")) 225 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/3`)) 226 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 227 228 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 229 By("scaling memory to 64M") 230 buffer := NewBuffer() 231 buffer.Write([]byte("y\n")) 232 session = helpers.CFWithStdin(buffer, "v3-scale", appName, "-m", "64M") 233 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 234 Eventually(session).Should(Say("This will cause the app to restart\\. Are you sure you want to scale %s\\? \\[yN\\]:", appName)) 235 Eventually(session).Should(Say("Stopping app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 236 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 237 Eventually(session).Should(Exit(0)) 238 239 updatedAppTable = helpers.ParseV3AppProcessTable(session.Out.Contents()) 240 Expect(updatedAppTable.Processes).To(HaveLen(2)) 241 242 processSummary = updatedAppTable.Processes[0] 243 instanceSummary = processSummary.Instances[0] 244 Expect(processSummary.Type).To(Equal("web")) 245 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/3`)) 246 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 64M`)) 247 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 248 249 By("scaling disk to 92M") 250 buffer = NewBuffer() 251 buffer.Write([]byte("y\n")) 252 session = helpers.CFWithStdin(buffer, "v3-scale", appName, "-k", "92M") 253 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 254 Eventually(session).Should(Say("This will cause the app to restart\\. Are you sure you want to scale %s\\? \\[yN\\]:", appName)) 255 Eventually(session).Should(Say("Stopping app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 256 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 257 Eventually(session).Should(Exit(0)) 258 259 updatedAppTable = helpers.ParseV3AppProcessTable(session.Out.Contents()) 260 Expect(updatedAppTable.Processes).To(HaveLen(2)) 261 262 processSummary = updatedAppTable.Processes[0] 263 instanceSummary = processSummary.Instances[0] 264 Expect(processSummary.Type).To(Equal("web")) 265 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/3`)) 266 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 64M`)) 267 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 92M`)) 268 269 By("scaling to 0 instances") 270 session = helpers.CF("v3-scale", appName, "-i", "0") 271 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 272 Consistently(session).ShouldNot(Say("This will cause the app to restart")) 273 Consistently(session).ShouldNot(Say("Stopping")) 274 Consistently(session).ShouldNot(Say("Starting")) 275 Eventually(session).Should(Exit(0)) 276 277 updatedAppTable = helpers.ParseV3AppProcessTable(session.Out.Contents()) 278 Expect(updatedAppTable.Processes).To(BeEmpty()) 279 }) 280 281 When("the user chooses not to restart the app", func() { 282 It("cancels the scale", func() { 283 buffer := NewBuffer() 284 buffer.Write([]byte("n\n")) 285 session := helpers.CFWithStdin(buffer, "v3-scale", appName, "-i", "2", "-k", "90M") 286 Eventually(session).Should(Say("This will cause the app to restart")) 287 Consistently(session).ShouldNot(Say("Stopping")) 288 Consistently(session).ShouldNot(Say("Starting")) 289 Eventually(session).Should(Say("Scaling cancelled")) 290 Consistently(session).ShouldNot(Say("Waiting for app to start\\.\\.\\.")) 291 Eventually(session).Should(Exit(0)) 292 293 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 294 Expect(appTable.Processes).To(BeEmpty()) 295 }) 296 }) 297 }) 298 299 When("all scale option flags are provided", func() { 300 When("the app starts successfully", func() { 301 It("scales the app accordingly", func() { 302 buffer := NewBuffer() 303 buffer.Write([]byte("y\n")) 304 session := helpers.CFWithStdin(buffer, "v3-scale", appName, "-i", "2", "-k", "120M", "-m", "60M") 305 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 306 Eventually(session).Should(Say("This will cause the app to restart\\. Are you sure you want to scale %s\\? \\[yN\\]:", appName)) 307 Eventually(session).Should(Say("Stopping app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 308 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 309 Eventually(session).Should(Exit(0)) 310 311 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 312 Expect(appTable.Processes).To(HaveLen(2)) 313 314 processSummary := appTable.Processes[0] 315 instanceSummary := processSummary.Instances[0] 316 Expect(processSummary.Type).To(Equal("web")) 317 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/2`)) 318 Expect(instanceSummary.State).To(MatchRegexp(`running|starting`)) 319 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 60M`)) 320 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 120M`)) 321 }) 322 }) 323 324 When("the app does not start successfully", func() { 325 It("scales the app and displays the app summary", func() { 326 buffer := NewBuffer() 327 buffer.Write([]byte("y\n")) 328 session := helpers.CFWithStdin(buffer, "v3-scale", appName, "-i", "2", "-k", "120M", "-m", "6M") 329 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 330 Eventually(session).Should(Say("This will cause the app to restart\\. Are you sure you want to scale %s\\? \\[yN\\]:", appName)) 331 Eventually(session).Should(Say("Stopping app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 332 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 333 Eventually(session).Should(Exit(0)) 334 335 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 336 Expect(appTable.Processes).To(HaveLen(2)) 337 338 processSummary := appTable.Processes[0] 339 instanceSummary := processSummary.Instances[0] 340 Expect(processSummary.Type).To(Equal("web")) 341 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/2`)) 342 Expect(instanceSummary.State).To(MatchRegexp(`crashed`)) 343 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 6M`)) 344 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 120M`)) 345 }) 346 }) 347 }) 348 349 PWhen("the provided scale options are the same as the existing scale properties", func() { 350 var ( 351 session *Session 352 currentInstances string 353 maxMemory string 354 maxDiskSize string 355 ) 356 357 BeforeEach(func() { 358 session = helpers.CF("v3-scale", appName) 359 Eventually(session).Should(Exit(0)) 360 361 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 362 instanceSummary := appTable.Processes[0].Instances[0] 363 currentInstances = string(len(appTable.Processes[0].Instances)) 364 maxMemory = strings.Fields(instanceSummary.Memory)[2] 365 maxDiskSize = strings.Fields(instanceSummary.Disk)[2] 366 }) 367 368 It("the action should be a no-op", func() { 369 session = helpers.CF("v3-scale", appName, "-i", currentInstances, "-m", maxMemory, "-k", maxDiskSize) 370 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 371 Consistently(session).ShouldNot(Say("This will cause the app to restart")) 372 Consistently(session).ShouldNot(Say("Stopping")) 373 Consistently(session).ShouldNot(Say("Starting")) 374 Consistently(session).ShouldNot(Say("Waiting for app to start")) 375 Eventually(session).Should(Exit(0)) 376 377 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 378 Expect(appTable.Processes).To(HaveLen(1)) 379 380 newProcessSummary := appTable.Processes[0] 381 newInstanceSummary := newProcessSummary.Instances[0] 382 Expect(newProcessSummary.Type).To(Equal("web")) 383 Expect(newProcessSummary.InstanceCount).To(MatchRegexp(fmt.Sprintf(`\d/%s`, currentInstances))) 384 Expect(newInstanceSummary.Memory).To(MatchRegexp(fmt.Sprintf(`\d+(\.\d+)?[KMG]? of %s`, maxMemory))) 385 Expect(newInstanceSummary.Disk).To(MatchRegexp(fmt.Sprintf(`\d+(\.\d+)?[KMG]? of %s`, maxDiskSize))) 386 }) 387 }) 388 389 When("the process flag is provided", func() { 390 It("scales the requested process", func() { 391 session := helpers.CF("v3-scale", appName, "-i", "2", "--process", "console") 392 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 393 Eventually(session).Should(Exit(0)) 394 395 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 396 Expect(appTable.Processes).To(HaveLen(2)) 397 398 processSummary := appTable.Processes[1] 399 instanceSummary := processSummary.Instances[0] 400 Expect(processSummary.Instances).To(HaveLen(2)) 401 Expect(processSummary.Type).To(Equal("console")) 402 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/2`)) 403 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 404 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 405 }) 406 }) 407 }) 408 }) 409 410 When("invalid scale option values are provided", func() { 411 When("a negative value is passed to a flag argument", func() { 412 It("outputs an error message to the user, provides help text, and exits 1", func() { 413 session := helpers.CF("v3-scale", "some-app", "-i=-5") 414 Eventually(session.Err).Should(Say("Incorrect Usage: invalid argument for flag '-i' \\(expected int > 0\\)")) 415 Eventually(session).Should(Say("cf v3-scale APP_NAME")) // help 416 Eventually(session).Should(Exit(1)) 417 418 session = helpers.CF("v3-scale", "some-app", "-k=-5") 419 Eventually(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB")) 420 Eventually(session).Should(Say("cf v3-scale APP_NAME")) // help 421 Eventually(session).Should(Exit(1)) 422 423 session = helpers.CF("v3-scale", "some-app", "-m=-5") 424 Eventually(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB")) 425 Eventually(session).Should(Say("cf v3-scale APP_NAME")) // help 426 Eventually(session).Should(Exit(1)) 427 }) 428 }) 429 430 When("a non-integer value is passed to a flag argument", func() { 431 It("outputs an error message to the user, provides help text, and exits 1", func() { 432 session := helpers.CF("v3-scale", "some-app", "-i", "not-an-integer") 433 Eventually(session.Err).Should(Say("Incorrect Usage: invalid argument for flag '-i' \\(expected int > 0\\)")) 434 Eventually(session).Should(Say("cf v3-scale APP_NAME")) // help 435 Eventually(session).Should(Exit(1)) 436 437 session = helpers.CF("v3-scale", "some-app", "-k", "not-an-integer") 438 Eventually(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB")) 439 Eventually(session).Should(Say("cf v3-scale APP_NAME")) // help 440 Eventually(session).Should(Exit(1)) 441 442 session = helpers.CF("v3-scale", "some-app", "-m", "not-an-integer") 443 Eventually(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB")) 444 Eventually(session).Should(Say("cf v3-scale APP_NAME")) // help 445 Eventually(session).Should(Exit(1)) 446 }) 447 }) 448 449 When("the unit of measurement is not provided", func() { 450 It("outputs an error message to the user, provides help text, and exits 1", func() { 451 session := helpers.CF("v3-scale", "some-app", "-k", "9") 452 Eventually(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB")) 453 Eventually(session).Should(Say("cf v3-scale APP_NAME")) // help 454 Eventually(session).Should(Exit(1)) 455 456 session = helpers.CF("v3-scale", "some-app", "-m", "7") 457 Eventually(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB")) 458 Eventually(session).Should(Say("cf v3-scale APP_NAME")) // help 459 Eventually(session).Should(Exit(1)) 460 }) 461 }) 462 }) 463 })