Skip to content

Commit fbcace6

Browse files
committed
Add API version check for bind-service "--strategy" parameter
* and complete "help" docu integration tests
1 parent b9b9ba2 commit fbcace6

File tree

6 files changed

+51
-1
lines changed

6 files changed

+51
-1
lines changed

command/flag/service_binding_strategy.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
type ServiceBindingStrategy struct {
1111
Strategy resources.BindingStrategyType
12+
IsSet bool
1213
}
1314

1415
func (ServiceBindingStrategy) Complete(prefix string) []flags.Completion {
@@ -20,6 +21,7 @@ func (h *ServiceBindingStrategy) UnmarshalFlag(val string) error {
2021
switch valLower {
2122
case "single", "multiple":
2223
h.Strategy = resources.BindingStrategyType(valLower)
24+
h.IsSet = true
2325
default:
2426
return &flags.Error{
2527
Type: flags.ErrRequired,

command/flag/service_binding_strategy_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,18 @@ var _ = Describe("ServiceBindingStrategy", func() {
3535
sbs = ServiceBindingStrategy{}
3636
})
3737

38+
When("unmarshal has not been called", func() {
39+
It("is marked as not set", func() {
40+
Expect(sbs.IsSet).To(BeFalse())
41+
})
42+
})
43+
3844
DescribeTable("downcases and sets strategy",
3945
func(input string, expected resources.BindingStrategyType) {
4046
err := sbs.UnmarshalFlag(input)
4147
Expect(err).ToNot(HaveOccurred())
4248
Expect(sbs.Strategy).To(Equal(expected))
49+
Expect(sbs.IsSet).To(BeTrue())
4350
},
4451
Entry("sets 'single' when passed 'single'", "single", resources.SingleBindingStrategy),
4552
Entry("sets 'single' when passed 'sInGlE'", "sInGlE", resources.SingleBindingStrategy),

command/v7/bind_service_command.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package v7
33
import (
44
"code.cloudfoundry.org/cli/v8/actor/actionerror"
55
"code.cloudfoundry.org/cli/v8/actor/v7action"
6+
"code.cloudfoundry.org/cli/v8/api/cloudcontroller/ccversion"
7+
"code.cloudfoundry.org/cli/v8/command"
68
"code.cloudfoundry.org/cli/v8/command/flag"
79
"code.cloudfoundry.org/cli/v8/command/v7/shared"
810
"code.cloudfoundry.org/cli/v8/types"
@@ -24,6 +26,13 @@ func (cmd BindServiceCommand) Execute(args []string) error {
2426
return err
2527
}
2628

29+
if cmd.ServiceBindingStrategy.IsSet {
30+
err := command.MinimumCCAPIVersionCheck(cmd.Config.APIVersion(), ccversion.MinVersionServiceBindingStrategy, "--strategy")
31+
if err != nil {
32+
return err
33+
}
34+
}
35+
2736
if err := cmd.displayIntro(); err != nil {
2837
return err
2938
}

command/v7/bind_service_command_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import (
66
"code.cloudfoundry.org/cli/v8/actor/actionerror"
77
"code.cloudfoundry.org/cli/v8/actor/v7action"
88
"code.cloudfoundry.org/cli/v8/command/commandfakes"
9+
"code.cloudfoundry.org/cli/v8/command/translatableerror"
910
v7 "code.cloudfoundry.org/cli/v8/command/v7"
1011
"code.cloudfoundry.org/cli/v8/command/v7/v7fakes"
12+
"code.cloudfoundry.org/cli/v8/resources"
1113
"code.cloudfoundry.org/cli/v8/types"
1214
"code.cloudfoundry.org/cli/v8/util/configv3"
1315
"code.cloudfoundry.org/cli/v8/util/ui"
@@ -39,6 +41,7 @@ var _ = Describe("bind-service Command", func() {
3941
BeforeEach(func() {
4042
testUI = ui.NewTestUI(NewBuffer(), NewBuffer(), NewBuffer())
4143
fakeConfig = new(commandfakes.FakeConfig)
44+
fakeConfig.APIVersionReturns("3.205.0")
4245
fakeSharedActor = new(commandfakes.FakeSharedActor)
4346
fakeActor = new(v7fakes.FakeActor)
4447

@@ -110,6 +113,30 @@ var _ = Describe("bind-service Command", func() {
110113
})
111114
})
112115

116+
When("strategy flag is set", func() {
117+
BeforeEach(func() {
118+
setFlag(&cmd, "--strategy", "multiple")
119+
})
120+
121+
It("passes the strategy to the actor", func() {
122+
Expect(executeErr).NotTo(HaveOccurred())
123+
Expect(fakeActor.CreateServiceAppBindingCallCount()).To(Equal(1))
124+
Expect(fakeActor.CreateServiceAppBindingArgsForCall(0).Strategy).
125+
To(Equal(resources.MultipleBindingStrategy))
126+
})
127+
128+
It("fails when the cc version is below the minimum", func() {
129+
fakeConfig.APIVersionReturns("3.204.0")
130+
executeErr = cmd.Execute(nil)
131+
132+
Expect(executeErr).To(MatchError(translatableerror.MinimumCFAPIVersionNotMetError{
133+
Command: "--strategy",
134+
CurrentVersion: "3.204.0",
135+
MinimumVersion: "3.205.0",
136+
}))
137+
})
138+
})
139+
113140
When("binding already exists", func() {
114141
BeforeEach(func() {
115142
fakeActor.CreateServiceAppBindingReturns(

integration/v7/isolated/bind_service_command_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ var _ = Describe("bind-service command", func() {
4141
Say(`\n`),
4242
Say(`\s+cf bind-service APP_NAME SERVICE_INSTANCE --binding-name BINDING_NAME\n`),
4343
Say(`\n`),
44+
Say(`\s+Optionally provide the binding strategy type. Valid options are 'single' \(default\) and 'multiple'. The 'multiple' strategy allows multiple bindings between the same app and service instance.\n`),
45+
Say(`\s+This is useful for credential rotation scenarios.\n`),
46+
Say(`\n`),
47+
Say(`\s+cf bind-service APP_NAME SERVICE_INSTANCE --strategy multiple\n`),
4448
Say(`EXAMPLES:\n`),
4549
Say(`\s+Linux/Mac:\n`),
4650
Say(`\s+cf bind-service myapp mydb -c '\{"permissions":"read-only"\}'\n`),
@@ -59,6 +63,7 @@ var _ = Describe("bind-service command", func() {
5963
Say(`OPTIONS:\n`),
6064
Say(`\s+--binding-name\s+Name to expose service instance to app process with \(Default: service instance name\)\n`),
6165
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`),
66+
Say(`\s+--strategy\s+Service binding strategy. Valid values are 'single' \(default\) and 'multiple'.\n`),
6267
Say(`\s+--wait, -w\s+Wait for the operation to complete\n`),
6368
Say(`\n`),
6469
Say(`SEE ALSO:\n`),

resources/service_credential_binding_resource.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type ServiceCredentialBinding struct {
3838
LastOperation LastOperation `jsonry:"last_operation"`
3939
// Parameters can be specified when creating a binding
4040
Parameters types.OptionalObject `jsonry:"parameters"`
41-
// Strategy can be "single" (default) or "multiple"
41+
// Strategy can be "single" or "multiple" (if empty, "single" is set as default by backend)
4242
Strategy BindingStrategyType `jsonry:"strategy,omitempty"`
4343
}
4444

0 commit comments

Comments
 (0)