github.com/randomtask1155/cli@v6.41.1-0.20181227003417-a98eed78cbde+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 buffer.Write([]byte("y\n")) 165 session := helpers.CFWithStdin(buffer, "scale", appName, "-m", "64M") 166 Eventually(session).Should(Say(`Scaling app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 167 Eventually(session).Should(Say(`This will cause the app to restart\. Are you sure you want to scale %s\? \[yN\]:`, appName)) 168 Eventually(session).Should(Say(`Stopping app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 169 Eventually(session).Should(Say(`Starting app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 170 Eventually(session).Should(Exit(0)) 171 172 updatedAppTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 173 Expect(updatedAppTable.Processes).To(HaveLen(2)) 174 175 processSummary := updatedAppTable.Processes[0] 176 instanceSummary := processSummary.Instances[0] 177 Expect(processSummary.Type).To(Equal("web")) 178 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/1`)) 179 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 64M`)) 180 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 181 }) 182 183 When("-f flag provided", func() { 184 It("scales without prompt", func() { 185 session := helpers.CF("scale", appName, "-m", "64M", "-f") 186 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName)) 187 Eventually(session).Should(Exit(0)) 188 189 updatedAppTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 190 Expect(updatedAppTable.Processes).To(HaveLen(2)) 191 192 processSummary := updatedAppTable.Processes[0] 193 instanceSummary := processSummary.Instances[0] 194 Expect(processSummary.Type).To(Equal("web")) 195 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/1`)) 196 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 64M`)) 197 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 198 }) 199 }) 200 }) 201 202 When("Scaling the disk space", func() { 203 It("scales disk to 92M", func() { 204 buffer := NewBuffer() 205 buffer.Write([]byte("y\n")) 206 session := helpers.CFWithStdin(buffer, "scale", appName, "-k", "92M") 207 Eventually(session).Should(Say(`Scaling app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 208 Eventually(session).Should(Say(`This will cause the app to restart\. Are you sure you want to scale %s\? \[yN\]:`, appName)) 209 Eventually(session).Should(Say(`Stopping app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 210 Eventually(session).Should(Say(`Starting app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 211 Eventually(session).Should(Exit(0)) 212 213 updatedAppTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 214 Expect(updatedAppTable.Processes).To(HaveLen(2)) 215 216 processSummary := updatedAppTable.Processes[0] 217 instanceSummary := processSummary.Instances[0] 218 Expect(processSummary.Type).To(Equal("web")) 219 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/1`)) 220 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 221 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 92M`)) 222 }) 223 224 When("-f flag provided", func() { 225 It("scales without prompt", func() { 226 session := helpers.CF("scale", appName, "-k", "92M", "-f") 227 Eventually(session).Should(Say("Scaling app %s in org %s / space %s as %s...", appName, orgName, spaceName, userName)) 228 Eventually(session).Should(Exit(0)) 229 230 updatedAppTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 231 Expect(updatedAppTable.Processes).To(HaveLen(2)) 232 233 processSummary := updatedAppTable.Processes[0] 234 instanceSummary := processSummary.Instances[0] 235 Expect(processSummary.Type).To(Equal("web")) 236 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/1`)) 237 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 238 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 92M`)) 239 }) 240 }) 241 }) 242 243 When("Scaling to 0 instances", func() { 244 It("scales to 0 instances", func() { 245 session := helpers.CF("scale", appName, "-i", "0") 246 Eventually(session).Should(Say(`Scaling app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 247 Consistently(session).ShouldNot(Say(`This will cause the app to restart|Stopping|Starting`)) 248 Eventually(session).Should(Exit(0)) 249 updatedAppTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 250 Expect(updatedAppTable.Processes[0].InstanceCount).To(Equal("0/0")) 251 Expect(updatedAppTable.Processes[0].Instances).To(BeEmpty()) 252 }) 253 }) 254 255 When("the user chooses not to restart the app", func() { 256 It("cancels the scale", func() { 257 buffer := NewBuffer() 258 buffer.Write([]byte("n\n")) 259 session := helpers.CFWithStdin(buffer, "scale", appName, "-i", "2", "-k", "90M") 260 Eventually(session).Should(Say("This will cause the app to restart")) 261 Consistently(session).ShouldNot(Say("Stopping")) 262 Consistently(session).ShouldNot(Say("Starting")) 263 Eventually(session).Should(Say("Scaling cancelled")) 264 Consistently(session).ShouldNot(Say(`Waiting for app to start\.\.\.`)) 265 Eventually(session).Should(Exit(0)) 266 267 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 268 Expect(appTable.Processes).To(BeEmpty()) 269 }) 270 }) 271 }) 272 273 When("all scale option flags are provided", func() { 274 When("the app starts successfully", func() { 275 It("scales the app accordingly", func() { 276 buffer := NewBuffer() 277 buffer.Write([]byte("y\n")) 278 session := helpers.CFWithStdin(buffer, "scale", appName, "-i", "2", "-k", "120M", "-m", "60M") 279 Eventually(session).Should(Say(`Scaling app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 280 Eventually(session).Should(Say(`This will cause the app to restart\. Are you sure you want to scale %s\? \[yN\]:`, appName)) 281 Eventually(session).Should(Say(`Stopping app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 282 Eventually(session).Should(Say(`Starting app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 283 Eventually(session).Should(Exit(0)) 284 285 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 286 Expect(appTable.Processes).To(HaveLen(2)) 287 288 processSummary := appTable.Processes[0] 289 instanceSummary := processSummary.Instances[0] 290 Expect(processSummary.Type).To(Equal("web")) 291 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/2`)) 292 Expect(instanceSummary.State).To(MatchRegexp(`running|starting`)) 293 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 60M`)) 294 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 120M`)) 295 }) 296 }) 297 298 When("the app does not start successfully", func() { 299 It("scales the app and displays the app summary", func() { 300 buffer := NewBuffer() 301 buffer.Write([]byte("y\n")) 302 session := helpers.CFWithStdin(buffer, "scale", appName, "-i", "2", "-k", "120M", "-m", "6M") 303 Eventually(session).Should(Say(`Scaling app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 304 Eventually(session).Should(Say(`This will cause the app to restart\. Are you sure you want to scale %s\? \[yN\]:`, appName)) 305 Eventually(session).Should(Say(`Stopping app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 306 Eventually(session).Should(Say(`Starting app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 307 Eventually(session).Should(Exit(1)) 308 309 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 310 Expect(appTable.Processes).To(HaveLen(2)) 311 312 processSummary := appTable.Processes[0] 313 instanceSummary := processSummary.Instances[0] 314 Expect(processSummary.Type).To(Equal("web")) 315 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/2`)) 316 Expect(instanceSummary.State).To(MatchRegexp(`crashed`)) 317 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 6M`)) 318 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of 120M`)) 319 }) 320 }) 321 }) 322 323 PWhen("the provided scale options are the same as the existing scale properties", func() { 324 var ( 325 session *Session 326 currentInstances string 327 maxMemory string 328 maxDiskSize string 329 ) 330 331 BeforeEach(func() { 332 session = helpers.CF("scale", appName) 333 Eventually(session).Should(Exit(0)) 334 335 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 336 instanceSummary := appTable.Processes[0].Instances[0] 337 currentInstances = string(len(appTable.Processes[0].Instances)) 338 maxMemory = strings.Fields(instanceSummary.Memory)[2] 339 maxDiskSize = strings.Fields(instanceSummary.Disk)[2] 340 }) 341 342 It("the action should be a no-op", func() { 343 session = helpers.CF("scale", appName, "-i", currentInstances, "-m", maxMemory, "-k", maxDiskSize) 344 Eventually(session).Should(Say(`Scaling app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 345 Consistently(session).ShouldNot(Say("This will cause the app to restart")) 346 Consistently(session).ShouldNot(Say("Stopping")) 347 Consistently(session).ShouldNot(Say("Starting")) 348 Consistently(session).ShouldNot(Say("Waiting for app to start")) 349 Eventually(session).Should(Exit(0)) 350 351 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 352 Expect(appTable.Processes).To(HaveLen(1)) 353 354 newProcessSummary := appTable.Processes[0] 355 newInstanceSummary := newProcessSummary.Instances[0] 356 Expect(newProcessSummary.Type).To(Equal("web")) 357 Expect(newProcessSummary.InstanceCount).To(MatchRegexp(fmt.Sprintf(`\d/%s`, currentInstances))) 358 Expect(newInstanceSummary.Memory).To(MatchRegexp(fmt.Sprintf(`\d+(\.\d+)?[KMG]? of %s`, maxMemory))) 359 Expect(newInstanceSummary.Disk).To(MatchRegexp(fmt.Sprintf(`\d+(\.\d+)?[KMG]? of %s`, maxDiskSize))) 360 }) 361 }) 362 363 When("the process flag is provided", func() { 364 It("scales the requested process", func() { 365 session := helpers.CF("scale", appName, "-i", "2", "--process", "console") 366 Eventually(session).Should(Say(`Scaling app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName)) 367 Eventually(session).Should(Exit(0)) 368 369 appTable := helpers.ParseV3AppProcessTable(session.Out.Contents()) 370 Expect(appTable.Processes).To(HaveLen(2)) 371 372 processSummary := appTable.Processes[1] 373 instanceSummary := processSummary.Instances[0] 374 Expect(processSummary.Instances).To(HaveLen(2)) 375 Expect(processSummary.Type).To(Equal("console")) 376 Expect(processSummary.InstanceCount).To(MatchRegexp(`\d/2`)) 377 Expect(instanceSummary.Memory).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 378 Expect(instanceSummary.Disk).To(MatchRegexp(`\d+(\.\d+)?[KMG]? of \d+[KMG]`)) 379 }) 380 }) 381 }) 382 }) 383 384 When("invalid scale option values are provided", func() { 385 When("a negative value is passed to a flag argument", func() { 386 It("outputs an error message to the user, provides help text, and exits 1", func() { 387 session := helpers.CF("scale", "some-app", "-i=-5") 388 Eventually(session.Err).Should(Say(`Incorrect Usage: invalid argument for flag '-i' \(expected int > 0\)`)) 389 Eventually(session).Should(Say("cf scale APP_NAME")) // help 390 Eventually(session).Should(Exit(1)) 391 392 session = helpers.CF("scale", "some-app", "-k=-5") 393 Eventually(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB")) 394 Eventually(session).Should(Say("cf scale APP_NAME")) // help 395 Eventually(session).Should(Exit(1)) 396 397 session = helpers.CF("scale", "some-app", "-m=-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 }) 403 404 When("a non-integer value is passed to a flag argument", func() { 405 It("outputs an error message to the user, provides help text, and exits 1", func() { 406 session := helpers.CF("scale", "some-app", "-i", "not-an-integer") 407 Eventually(session.Err).Should(Say(`Incorrect Usage: invalid argument for flag '-i' \(expected int > 0\)`)) 408 Eventually(session).Should(Say("cf scale APP_NAME")) // help 409 Eventually(session).Should(Exit(1)) 410 411 session = helpers.CF("scale", "some-app", "-k", "not-an-integer") 412 Eventually(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB")) 413 Eventually(session).Should(Say("cf scale APP_NAME")) // help 414 Eventually(session).Should(Exit(1)) 415 416 session = helpers.CF("scale", "some-app", "-m", "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 }) 422 423 When("the unit of measurement is not provided", func() { 424 It("outputs an error message to the user, provides help text, and exits 1", func() { 425 session := helpers.CF("scale", "some-app", "-k", "9") 426 Eventually(session.Err).Should(Say("Byte quantity must be an integer with a unit of measurement like M, MB, G, or GB")) 427 Eventually(session).Should(Say("cf scale APP_NAME")) // help 428 Eventually(session).Should(Exit(1)) 429 430 session = helpers.CF("scale", "some-app", "-m", "7") 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 }) 436 }) 437 })