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