github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/integration/v7/isolated/update_service_command_test.go (about) 1 package isolated 2 3 import ( 4 "os" 5 "time" 6 7 "code.cloudfoundry.org/cli/integration/helpers" 8 "code.cloudfoundry.org/cli/integration/helpers/servicebrokerstub" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/ginkgo/extensions/table" 11 . "github.com/onsi/gomega" 12 . "github.com/onsi/gomega/gbytes" 13 . "github.com/onsi/gomega/gexec" 14 ) 15 16 var _ = Describe("update-service command", func() { 17 const command = "update-service" 18 19 Describe("help", func() { 20 matchHelpMessage := SatisfyAll( 21 Say(`NAME:\n`), 22 Say(`\s+%s - Update a service instance\n`, command), 23 Say(`\n`), 24 Say(`USAGE:\n`), 25 Say(`\s+cf update-service SERVICE_INSTANCE \[-p NEW_PLAN\] \[-c PARAMETERS_AS_JSON\] \[-t TAGS\]\n`), 26 Say(`\n`), 27 Say(`\s+Optionally provide service-specific configuration parameters in a valid JSON object in-line:\n`), 28 Say(`\s+cf update-service SERVICE_INSTANCE -c '{\"name\":\"value\",\"name\":\"value\"}'\n`), 29 Say(`\s+Optionally provide a file containing service-specific configuration parameters in a valid JSON object\.\n`), 30 Say(`\s+The path to the parameters file can be an absolute or relative path to a file:\n`), 31 Say(`\s+cf update-service SERVICE_INSTANCE -c PATH_TO_FILE\n`), 32 Say(`\s+Example of valid JSON object:\n`), 33 Say(`\s+{\n`), 34 Say(`\s+\"cluster_nodes\": {\n`), 35 Say(`\s+\"count\": 5,\n`), 36 Say(`\s+\"memory_mb\": 1024\n`), 37 Say(`\s+}\n`), 38 Say(`\s+}\n`), 39 Say(`\s+ Optionally provide a list of comma-delimited tags that will be written to the VCAP_SERVICES environment variable for any bound applications.\n`), 40 Say(`EXAMPLES:\n`), 41 Say(`\s+cf update-service mydb -p gold\n`), 42 Say(`\s+cf update-service mydb -c '{\"ram_gb\":4}'\n`), 43 Say(`\s+cf update-service mydb -c ~/workspace/tmp/instance_config.json\n`), 44 Say(`\s+cf update-service mydb -t "list, of, tags"\n`), 45 Say(`OPTIONS:\n`), 46 Say(`\s+-c\s+Valid JSON object containing service-specific configuration parameters, provided either in-line or in a file\. For a list of supported configuration parameters, see documentation for the particular service offering\.\n`), 47 Say(`\s+-p\s+Change service plan for a service instance\n`), 48 Say(`\s+-t\s+User provided tags\n`), 49 Say(`\s+--wait, -w\s+Wait for the operation to complete\n`), 50 Say(`SEE ALSO:\n`), 51 Say(`\s+rename-service, services, update-user-provided-service\n`), 52 ) 53 54 When("the --help flag is specified", func() { 55 It("exits successfully and prints the help message", func() { 56 session := helpers.CF(command, "--help") 57 58 Eventually(session).Should(Exit(0)) 59 Expect(session.Out).To(matchHelpMessage) 60 Expect(session.Err.Contents()).To(BeEmpty()) 61 }) 62 }) 63 64 When("the service instance name is omitted", func() { 65 It("fails and prints the help message", func() { 66 session := helpers.CF(command) 67 68 Eventually(session).Should(Exit(1)) 69 Expect(session.Out).To(matchHelpMessage) 70 Expect(session.Err).To(Say("Incorrect Usage: the required argument `SERVICE_INSTANCE` was not provided\n")) 71 }) 72 }) 73 74 When("an extra parameter is provided", func() { 75 It("fails and prints the help message", func() { 76 session := helpers.CF(command, "service-instance-name", "invalid-extra-parameter") 77 78 Eventually(session).Should(Exit(1)) 79 Expect(session.Out).To(matchHelpMessage) 80 Expect(session.Err).To(Say(`Incorrect Usage: unexpected argument "invalid-extra-parameter"`)) 81 }) 82 }) 83 84 When("an extra flag is provided", func() { 85 It("fails and prints the help message", func() { 86 session := helpers.CF(command, "service-instance-name", "--invalid") 87 88 Eventually(session).Should(Exit(1)) 89 Expect(session.Out).To(matchHelpMessage) 90 Expect(session.Err).To(Say("Incorrect Usage: unknown flag `invalid'")) 91 }) 92 }) 93 94 When("a flag is provided without a value", func() { 95 DescribeTable( 96 "it fails and prints a help message", 97 func(flag string) { 98 session := helpers.CF(command, "service-instance-name", flag) 99 100 Eventually(session).Should(Exit(1)) 101 Expect(session.Out).To(matchHelpMessage) 102 Expect(session.Err).To(Say("Incorrect Usage: expected argument for flag `%s'", flag)) 103 }, 104 Entry("configuration", "-c"), 105 Entry("plan", "-p"), 106 Entry("tags", "-t"), 107 ) 108 }) 109 }) 110 111 When("the environment is not setup correctly", func() { 112 It("fails with the appropriate errors", func() { 113 helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, command, "service-instance-name") 114 }) 115 }) 116 117 When("logged in and targeting a space", func() { 118 const serviceCommand = "service" 119 120 var ( 121 orgName string 122 spaceName string 123 username string 124 serviceInstanceName string 125 ) 126 127 BeforeEach(func() { 128 orgName = helpers.NewOrgName() 129 spaceName = helpers.NewSpaceName() 130 helpers.SetupCF(orgName, spaceName) 131 132 username, _ = helpers.GetCredentials() 133 134 serviceInstanceName = helpers.NewServiceInstanceName() 135 }) 136 137 AfterEach(func() { 138 helpers.QuickDeleteOrg(orgName) 139 }) 140 141 When("the service instance doesn't exist", func() { 142 It("fails with an appropriate error", func() { 143 session := helpers.CF(command, serviceInstanceName, "-t", "important") 144 Eventually(session).Should(Exit(1)) 145 Expect(session.Out).To(SatisfyAll( 146 Say("Updating service instance %s in org %s / space %s as %s...", serviceInstanceName, orgName, spaceName, username), 147 Say("FAILED"), 148 )) 149 Expect(session.Err).To(Say("Service instance '%s' not found\n", serviceInstanceName)) 150 }) 151 }) 152 153 When("the service instance exists", func() { 154 const ( 155 originalTags = "foo, bar" 156 newTags = "bax, quz" 157 ) 158 var broker *servicebrokerstub.ServiceBrokerStub 159 160 BeforeEach(func() { 161 broker = servicebrokerstub.New().WithPlans(2).EnableServiceAccess() 162 helpers.CreateManagedServiceInstance( 163 broker.FirstServiceOfferingName(), 164 broker.FirstServicePlanName(), 165 serviceInstanceName, 166 "-t", originalTags, 167 ) 168 session := helpers.CF("m") 169 Eventually(session).Should(Exit(0)) 170 171 }) 172 173 AfterEach(func() { 174 broker.Forget() 175 }) 176 177 It("can update tags, parameters and plan", func() { 178 By("performing the update") 179 newPlanName := broker.Services[0].Plans[1].Name 180 session := helpers.CF(command, serviceInstanceName, "-t", newTags, "-p", newPlanName, "-c", `{"foo":"bar"}`) 181 Eventually(session).Should(Exit(0)) 182 183 Expect(session.Out).To(SatisfyAll( 184 Say(`Updating service instance %s in org %s / space %s as %s\.\.\.\n`, serviceInstanceName, orgName, spaceName, username), 185 Say(`\n`), 186 Say(`Update of service instance %s complete\.\n`, serviceInstanceName), 187 Say(`OK\n`), 188 )) 189 190 Expect(string(session.Err.Contents())).To(BeEmpty()) 191 192 By("checking that the update changed things") 193 session = helpers.CF(serviceCommand, serviceInstanceName) 194 Eventually(session).Should(Exit(0)) 195 196 Expect(session.Out).To(SatisfyAll( 197 Say(`plan:\s+%s`, newPlanName), 198 Say(`tags:\s+%s`, newTags), 199 )) 200 }) 201 202 Describe("updating tags", func() { 203 It("can update tags alone", func() { 204 session := helpers.CF(command, serviceInstanceName, "-t", newTags) 205 Eventually(session).Should(Exit(0)) 206 207 Expect(session.Out).To(SatisfyAll( 208 Say(`Updating service instance %s in org %s / space %s as %s\.\.\.\n`, serviceInstanceName, orgName, spaceName, username), 209 Say(`\n`), 210 Say(`Update of service instance %s complete\.\n`, serviceInstanceName), 211 Say(`OK\n`), 212 )) 213 214 Expect(string(session.Err.Contents())).To(BeEmpty()) 215 216 session = helpers.CF(serviceCommand, serviceInstanceName) 217 Eventually(session).Should(Exit(0)) 218 Expect(session.Out).To(Say(`tags:\s+%s`, newTags)) 219 }) 220 }) 221 222 Describe("updating parameters", func() { 223 const ( 224 validParams = `{"funky":"chicken"}` 225 invalidParams = `{"funky":chicken"}` 226 ) 227 228 checkParams := func() { 229 session := helpers.CF(serviceCommand, serviceInstanceName, "--params") 230 Eventually(session).Should(Exit(0)) 231 Expect(session.Out).To(SatisfyAll( 232 Say(`\{\n`), 233 Say(` "funky": "chicken"\n`), 234 Say(`\}\n`), 235 )) 236 } 237 238 It("accepts JSON on the command line", func() { 239 session := helpers.CF(command, serviceInstanceName, "-c", validParams) 240 Eventually(session).Should(Exit(0)) 241 242 checkParams() 243 }) 244 245 It("rejects invalid JSON on the command line", func() { 246 session := helpers.CF(command, serviceInstanceName, "-c", invalidParams) 247 Eventually(session).Should(Exit(1)) 248 249 Expect(session.Err).To(Say("Incorrect Usage: Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object.\n")) 250 }) 251 252 It("accepts JSON from a file", func() { 253 path := helpers.TempFileWithContent(validParams) 254 defer os.Remove(path) 255 256 session := helpers.CF(command, serviceInstanceName, "-c", path, "-v") 257 Eventually(session).Should(Exit(0)) 258 259 checkParams() 260 }) 261 262 It("rejects invalid JSON from a file", func() { 263 path := helpers.TempFileWithContent(invalidParams) 264 defer os.Remove(path) 265 266 session := helpers.CF(command, serviceInstanceName, "-c", path) 267 Eventually(session).Should(Exit(1)) 268 269 Expect(session.Err).To(Say("Incorrect Usage: Invalid configuration provided for -c flag. Please provide a valid JSON object or path to a file containing a valid JSON object.\n")) 270 }) 271 }) 272 273 Describe("updating plan", func() { 274 It("updates the plan", func() { 275 newPlanName := broker.Services[0].Plans[1].Name 276 session := helpers.CF(command, serviceInstanceName, "-p", newPlanName) 277 Eventually(session).Should(Exit(0)) 278 279 Eventually(helpers.CF("service", serviceInstanceName)).Should( 280 SatisfyAll( 281 Say(`plan:\s+%s`, newPlanName), 282 Say(`status:\s+update succeeded`), 283 ), 284 ) 285 }) 286 287 When("plan does not exist", func() { 288 const invalidPlan = "invalid-plan" 289 290 It("displays an error and exits 1", func() { 291 session := helpers.CF(command, serviceInstanceName, "-p", invalidPlan) 292 Eventually(session).Should(Exit(1)) 293 Expect(session.Err).To(Say("The plan '%s' could not be found for service offering '%s' and broker '%s'.", invalidPlan, broker.Services[0].Name, broker.Name)) 294 }) 295 }) 296 297 When("plan is the same as current", func() { 298 It("displays a message and exits 0", func() { 299 session := helpers.CF(command, serviceInstanceName, "-p", broker.Services[0].Plans[0].Name) 300 Eventually(session).Should(Exit(0)) 301 Expect(session.Out).To(SatisfyAll( 302 Say(`No changes were made\.\n`), 303 Say(`OK\n`), 304 )) 305 }) 306 }) 307 }) 308 309 When("the broker responds asynchronously", func() { 310 BeforeEach(func() { 311 broker.WithAsyncDelay(time.Second).Configure() 312 }) 313 314 It("says that the operation is in progress", func() { 315 newPlanName := broker.Services[0].Plans[1].Name 316 session := helpers.CF(command, serviceInstanceName, "-p", newPlanName) 317 Eventually(session).Should(Exit(0)) 318 319 Expect(session.Out).To(SatisfyAll( 320 Say(`Updating service instance %s in org %s / space %s as %s\.\.\.\n`, serviceInstanceName, orgName, spaceName, username), 321 Say(`\n`), 322 Say(`Update in progress. Use 'cf services' or 'cf service %s' to check operation status\.\n`, serviceInstanceName), 323 Say(`OK\n`), 324 )) 325 }) 326 327 It("accepts the --wait flag to wait for completion", func() { 328 session := helpers.CF(command, serviceInstanceName, "-c", `{"funky":"chicken"}`, "--wait") 329 Eventually(session).Should(Exit(0)) 330 331 Expect(session.Out).To(SatisfyAll( 332 Say(`Updating service instance %s in org %s / space %s as %s\.\.\.\n`, serviceInstanceName, orgName, spaceName, username), 333 Say(`\n`), 334 Say(`Waiting for the operation to complete\.+\n`), 335 Say(`\n`), 336 Say(`Update of service instance %s complete\.\n`, serviceInstanceName), 337 Say(`OK\n`), 338 )) 339 340 Expect(string(session.Err.Contents())).To(BeEmpty()) 341 session = helpers.CF(serviceCommand, serviceInstanceName) 342 Eventually(session).Should(Exit(0)) 343 Expect(session.Out).To(Say(`status:\s+update succeeded`)) 344 }) 345 }) 346 }) 347 }) 348 })