Allow backing service instances to be unbound and rebound to backing apps on service instance update.

This commit is contained in:
Scott Frederick
2018-12-20 16:44:24 -06:00
parent 97f3a9d2e0
commit 0a2987f22d
20 changed files with 533 additions and 188 deletions

View File

@@ -45,6 +45,7 @@ class UpdateInstanceWithServicesAcceptanceTest extends CloudFoundryAcceptanceTes
"spring.cloud.appbroker.services[0].services[0].name=" + BACKING_SERVICE_NAME,
"spring.cloud.appbroker.services[0].services[0].plan=" + PLAN_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].rebind-on-update=true"
})
void shouldPushAppWithServicesBind() {
// when a service instance is created

View File

@@ -31,6 +31,7 @@ public class BackingService {
private Map<String, Object> parameters;
private Map<String, String> properties;
private List<ParametersTransformerSpec> parametersTransformers;
private boolean rebindOnUpdate;
private BackingService() {
}
@@ -40,13 +41,15 @@ public class BackingService {
String plan,
Map<String, Object> parameters,
Map<String, String> properties,
List<ParametersTransformerSpec> parametersTransformers) {
List<ParametersTransformerSpec> parametersTransformers,
boolean rebindOnUpdate) {
this.serviceInstanceName = serviceInstanceName;
this.name = name;
this.plan = plan;
this.parameters = parameters;
this.properties = properties;
this.parametersTransformers = parametersTransformers;
this.rebindOnUpdate = rebindOnUpdate;
}
BackingService(BackingService backingServiceToCopy) {
@@ -62,6 +65,7 @@ public class BackingService {
this.parametersTransformers = backingServiceToCopy.parametersTransformers == null
? new ArrayList<>()
: new ArrayList<>(backingServiceToCopy.parametersTransformers);
this.rebindOnUpdate = backingServiceToCopy.rebindOnUpdate;
}
public String getServiceInstanceName() {
@@ -96,6 +100,10 @@ public class BackingService {
this.parameters = parameters;
}
public void addParameter(String key, Object value) {
parameters.put(key, value);
}
public Map<String, String> getProperties() {
return properties;
}
@@ -112,8 +120,12 @@ public class BackingService {
this.parametersTransformers = parametersTransformers;
}
public void addParameter(String key, Object value) {
parameters.put(key, value);
public boolean isRebindOnUpdate() {
return rebindOnUpdate;
}
public void setRebindOnUpdate(boolean rebindOnUpdate) {
this.rebindOnUpdate = rebindOnUpdate;
}
@Override
@@ -162,14 +174,11 @@ public class BackingService {
private Map<String, Object> parameters = new HashMap<>();
private Map<String, String> properties = new HashMap<>();
private final List<ParametersTransformerSpec> parameterTransformers = new ArrayList<>();
private boolean rebindOnUpdate;
BackingServiceBuilder() {
}
public BackingService build() {
return new BackingService(serviceInstanceName, name, plan, parameters, properties, parameterTransformers);
}
public BackingServiceBuilder serviceInstanceName(String serviceInstanceName) {
this.serviceInstanceName = serviceInstanceName;
return this;
@@ -200,6 +209,14 @@ public class BackingService {
return this;
}
public BackingServiceBuilder rebindOnUpdate(boolean rebindOnUpdate) {
this.rebindOnUpdate = rebindOnUpdate;
return this;
}
public BackingService build() {
return new BackingService(serviceInstanceName, name, plan, parameters, properties, parameterTransformers, rebindOnUpdate);
}
}
}

View File

@@ -49,9 +49,6 @@ public class BackingServicesProvisionService {
return Flux.fromIterable(backingServices)
.parallel()
.runOn(Schedulers.parallel())
// service instances can be updated with a change to the plan or to parameters
// if the service instance has no parameters, don't update it
.filter(backingService -> !backingService.getParameters().isEmpty())
.flatMap(deployerClient::updateServiceInstance)
.doOnRequest(l -> log.info("Updating backing services {}", backingServices))
.doOnEach(d -> log.info("Finished updating backing service {}", d))

View File

@@ -75,6 +75,7 @@ public class DeployerClient {
.serviceInstanceName(backingService.getServiceInstanceName())
.parameters(backingService.getParameters())
.properties(backingService.getProperties())
.rebindOnUpdate(backingService.isRebindOnUpdate())
.build())
.doOnRequest(l -> log.debug("Creating backing service {}", backingService.getName()))
.doOnSuccess(d -> log.debug("Finished creating backing service {}", backingService.getName()))

View File

@@ -12,7 +12,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -56,22 +55,29 @@ class BackingServicesProvisionServiceTest {
expectedValues.add("si2");
StepVerifier.create(backingServicesProvisionService.createServiceInstance(backingServices))
// deployments are run in parallel, so the order of completion is not predictable
// ensure that both expected signals are sent in any order
.expectNextMatches(expectedValues::remove)
.expectNextMatches(expectedValues::remove)
.verifyComplete();
// deployments are run in parallel, so the order of completion is not predictable
// ensure that both expected signals are sent in any order
.expectNextMatches(expectedValues::remove)
.expectNextMatches(expectedValues::remove)
.verifyComplete();
}
@Test
@SuppressWarnings("UnassignedFluxMonoInstance")
void updateServiceInstance() {
doReturn(Mono.just("si1"))
doReturn(Mono.just("updated1"))
.when(deployerClient).updateServiceInstance(backingServices.get(0));
doReturn(Mono.just("updated2"))
.when(deployerClient).updateServiceInstance(backingServices.get(1));
List<String> expectedValues = new ArrayList<>();
expectedValues.add("updated1");
expectedValues.add("updated2");
StepVerifier.create(backingServicesProvisionService.updateServiceInstance(backingServices))
.assertNext(value -> assertThat(value).isEqualTo("si1"))
.verifyComplete();
.expectNextMatches(expectedValues::remove)
.expectNextMatches(expectedValues::remove)
.verifyComplete();
verifyNoMoreInteractions(deployerClient);
}
@@ -89,11 +95,11 @@ class BackingServicesProvisionServiceTest {
expectedValues.add("deleted2");
StepVerifier.create(backingServicesProvisionService.deleteServiceInstance(backingServices))
// deployments are run in parallel, so the order of completion is not predictable
// ensure that both expected signals are sent in any order
.expectNextMatches(expectedValues::remove)
.expectNextMatches(expectedValues::remove)
.verifyComplete();
// deployments are run in parallel, so the order of completion is not predictable
// ensure that both expected signals are sent in any order
.expectNextMatches(expectedValues::remove)
.expectNextMatches(expectedValues::remove)
.verifyComplete();
}
}

View File

@@ -21,12 +21,10 @@ import java.nio.file.Path;
import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -492,21 +490,6 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
}
}
/**
* Return a function usable in {@literal doOnError} constructs that will unwrap unrecognized Cloud Foundry Exceptions
* and log the text payload.
*/
private Consumer<Throwable> logError(String msg) {
return e -> {
if (e instanceof UnknownCloudFoundryException) {
logger.error(msg + "\nUnknownCloudFoundryException encountered, whose payload follows:\n"
+ ((UnknownCloudFoundryException)e).getPayload(), e);
} else {
logger.error(msg, e);
}
};
}
@Override
public Mono<CreateServiceInstanceResponse> createServiceInstance(CreateServiceInstanceRequest request) {
org.cloudfoundry.operations.services.CreateServiceInstanceRequest createServiceInstanceRequest =
@@ -540,56 +523,75 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
@Override
public Mono<UpdateServiceInstanceResponse> updateServiceInstance(UpdateServiceInstanceRequest request) {
org.cloudfoundry.operations.services.UpdateServiceInstanceRequest updateServiceInstanceRequest =
org.cloudfoundry.operations.services.UpdateServiceInstanceRequest
.builder()
.serviceInstanceName(request.getServiceInstanceName())
.parameters(request.getParameters())
.build();
Mono<UpdateServiceInstanceResponse> updateServiceInstanceResponseMono =
Mono.just(UpdateServiceInstanceResponse.builder()
.name(request.getServiceInstanceName())
.build());
CloudFoundryOperations operations = getOperations(request.getProperties());
return operations.services()
.updateInstance(updateServiceInstanceRequest)
.then(updateServiceInstanceResponseMono);
CloudFoundryOperations cloudFoundryOperations = getOperations(request.getProperties());
return unbindServiceInstanceIfNecessary(request, cloudFoundryOperations)
.then(updateServiceInstanceIfNecessary(request, cloudFoundryOperations));
}
@Override
public Mono<DeleteServiceInstanceResponse> deleteServiceInstance(DeleteServiceInstanceRequest request) {
final String serviceInstanceName = request.getServiceInstanceName();
return getOperations(request.getProperties())
.services()
.getInstance(GetServiceInstanceRequest.builder()
CloudFoundryOperations cloudFoundryOperations = getOperations(request.getProperties());
return unbindServiceInstance(serviceInstanceName, cloudFoundryOperations)
.then(deleteServiceInstance(serviceInstanceName, cloudFoundryOperations)
.then(Mono.just(DeleteServiceInstanceResponse.builder()
.name(serviceInstanceName)
.build())));
}
private Mono<Void> deleteServiceInstance(String serviceInstanceName, CloudFoundryOperations cloudFoundryOperations) {
return cloudFoundryOperations.services().deleteInstance(
org.cloudfoundry.operations.services.DeleteServiceInstanceRequest
.builder()
.name(serviceInstanceName)
.build())
.build());
}
private Mono<Void> unbindServiceInstance(String serviceInstanceName,
CloudFoundryOperations cloudFoundryOperations) {
return cloudFoundryOperations.services().getInstance(GetServiceInstanceRequest.builder()
.name(serviceInstanceName)
.build())
.map(ServiceInstance::getApplications)
.flatMap((Function<List<String>, Mono<?>>) applications ->
Flux.fromIterable(applications)
.flatMap(
application ->
getOperations(request.getProperties())
.services()
.unbind(
UnbindServiceInstanceRequest
.builder()
.applicationName(application)
.serviceInstanceName(serviceInstanceName)
.build())
).collectList())
.then(
getOperations(request.getProperties())
.services()
.deleteInstance(
org.cloudfoundry.operations.services.DeleteServiceInstanceRequest
.builder()
.name(serviceInstanceName)
.build())
.then(Mono.just(DeleteServiceInstanceResponse.builder().name(serviceInstanceName).build())));
.flatMap(applications -> Flux.fromIterable(applications)
.flatMap(application -> cloudFoundryOperations.services().unbind(
UnbindServiceInstanceRequest.builder()
.applicationName(application)
.serviceInstanceName(serviceInstanceName)
.build())
)
.then(Mono.empty()));
}
private Mono<Void> unbindServiceInstanceIfNecessary(UpdateServiceInstanceRequest request,
CloudFoundryOperations cloudFoundryOperations) {
if (request.isRebindOnUpdate()) {
return unbindServiceInstance(request.getServiceInstanceName(), cloudFoundryOperations);
}
return Mono.empty();
}
private Mono<UpdateServiceInstanceResponse> updateServiceInstanceIfNecessary(UpdateServiceInstanceRequest request,
CloudFoundryOperations cloudFoundryOperations) {
// service instances can be updated with a change to the plan, name, or parameters;
// of these only parameter changes are supported, so don't update if the
// backing service instance has no parameters
if (request.getParameters() == null || request.getParameters().isEmpty()) {
return Mono.empty();
}
final String serviceInstanceName = request.getServiceInstanceName();
return cloudFoundryOperations.services().updateInstance(
org.cloudfoundry.operations.services.UpdateServiceInstanceRequest.builder()
.serviceInstanceName(serviceInstanceName)
.parameters(request.getParameters())
.build())
.then(Mono.just(UpdateServiceInstanceResponse.builder()
.name(serviceInstanceName)
.build()));
}
private CloudFoundryOperations getOperations(Map<String, String> properties) {
@@ -599,4 +601,19 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
return this.operations;
}
}
/**
* Return a function usable in {@literal doOnError} constructs that will unwrap unrecognized Cloud Foundry Exceptions
* and log the text payload.
*/
private Consumer<Throwable> logError(String msg) {
return e -> {
if (e instanceof UnknownCloudFoundryException) {
logger.error(msg + "\nUnknownCloudFoundryException encountered, whose payload follows:\n"
+ ((UnknownCloudFoundryException)e).getPayload(), e);
} else {
logger.error(msg, e);
}
};
}
}

View File

@@ -18,11 +18,10 @@ package org.springframework.cloud.appbroker.deployer.cloudfoundry;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import org.cloudfoundry.client.CloudFoundryClient;
import org.cloudfoundry.client.v2.serviceinstances.GetServiceInstanceResponse;
import org.cloudfoundry.client.v2.serviceinstances.LastOperation;
import org.cloudfoundry.client.v2.serviceinstances.ServiceInstanceEntity;
import org.cloudfoundry.client.v2.serviceinstances.ServiceInstances;
import org.cloudfoundry.operations.CloudFoundryOperations;
import org.cloudfoundry.operations.applications.ApplicationHealthCheck;
@@ -370,7 +369,30 @@ class CloudFoundryAppDeployerTest {
}
@Test
void updateServiceInstance() {
void updateServiceInstanceUpdatesWithParameters() {
Map<String, Object> parameters = Collections.singletonMap("param1", "value");
when(operationsServices.updateInstance(
org.cloudfoundry.operations.services.UpdateServiceInstanceRequest.builder()
.serviceInstanceName("service-instance-name")
.parameters(parameters)
.build()))
.thenReturn(Mono.empty());
UpdateServiceInstanceRequest request =
UpdateServiceInstanceRequest.builder()
.serviceInstanceName("service-instance-name")
.parameters(parameters)
.build();
StepVerifier.create(
appDeployer.updateServiceInstance(request))
.assertNext(response -> assertThat(response.getName()).isEqualTo("service-instance-name"))
.verifyComplete();
}
@Test
void updateServiceInstanceUnbindsWhenRequired() {
when(operationsServices.updateInstance(
org.cloudfoundry.operations.services.UpdateServiceInstanceRequest.builder()
.serviceInstanceName("service-instance-name")
@@ -379,25 +401,47 @@ class CloudFoundryAppDeployerTest {
.thenReturn(Mono.empty());
when(operationsServices.getInstance(GetServiceInstanceRequest.builder()
.name("service-instance-name")
.build()))
.name("service-instance-name")
.build()))
.thenReturn(Mono.just(ServiceInstance.builder()
.name("service-instance-name")
.id("service-instance-guid")
.type(ServiceInstanceType.MANAGED)
.applications("app1", "app2")
.build()));
when(clientServiceInstances.get(
org.cloudfoundry.client.v2.serviceinstances.GetServiceInstanceRequest.builder()
.serviceInstanceId("service-instance-guid")
when(operationsServices.unbind(UnbindServiceInstanceRequest.builder()
.applicationName("app1")
.serviceInstanceName("service-instance-name")
.build()))
.thenReturn(Mono.empty());
when(operationsServices.unbind(UnbindServiceInstanceRequest.builder()
.applicationName("app2")
.serviceInstanceName("service-instance-name")
.build()))
.thenReturn(Mono.empty());
UpdateServiceInstanceRequest request =
UpdateServiceInstanceRequest.builder()
.serviceInstanceName("service-instance-name")
.parameters(emptyMap())
.rebindOnUpdate(true)
.build();
StepVerifier.create(
appDeployer.updateServiceInstance(request))
.verifyComplete();
}
@Test
void updateServiceInstanceDoesNothingWithoutParameters() {
when(operationsServices.updateInstance(
org.cloudfoundry.operations.services.UpdateServiceInstanceRequest.builder()
.serviceInstanceName("service-instance-name")
.parameters(emptyMap())
.build()))
.thenReturn(Mono.just(GetServiceInstanceResponse.builder()
.entity(ServiceInstanceEntity.builder()
.lastOperation(LastOperation.builder()
.state("succeeded")
.build())
.build())
.build()));
.thenReturn(Mono.empty());
UpdateServiceInstanceRequest request =
UpdateServiceInstanceRequest.builder()
@@ -407,7 +451,6 @@ class CloudFoundryAppDeployerTest {
StepVerifier.create(
appDeployer.updateServiceInstance(request))
.assertNext(response -> assertThat(response.getName()).isEqualTo("service-instance-name"))
.verifyComplete();
}

View File

@@ -24,13 +24,16 @@ public class UpdateServiceInstanceRequest {
private final String serviceInstanceName;
private final Map<String, Object> parameters;
private final Map<String, String> properties;
private final boolean rebindOnUpdate;
UpdateServiceInstanceRequest(String serviceInstanceName,
Map<String, Object> parameters,
Map<String, String> properties) {
Map<String, String> properties,
boolean rebindOnUpdate) {
this.serviceInstanceName = serviceInstanceName;
this.parameters = parameters;
this.properties = properties;
this.rebindOnUpdate = rebindOnUpdate;
}
public static UpdateServiceInstanceRequestBuilder builder() {
@@ -49,11 +52,16 @@ public class UpdateServiceInstanceRequest {
return properties;
}
public boolean isRebindOnUpdate() {
return rebindOnUpdate;
}
public static class UpdateServiceInstanceRequestBuilder {
private String serviceInstanceName;
private final Map<String, Object> parameters = new HashMap<>();
private final Map<String, String> properties = new HashMap<>();
private boolean rebindOnUpdate;
UpdateServiceInstanceRequestBuilder() {
}
@@ -84,8 +92,13 @@ public class UpdateServiceInstanceRequest {
return this;
}
public UpdateServiceInstanceRequestBuilder rebindOnUpdate(boolean rebindOnUpdate) {
this.rebindOnUpdate = rebindOnUpdate;
return this;
}
public UpdateServiceInstanceRequest build() {
return new UpdateServiceInstanceRequest(serviceInstanceName, parameters, properties);
return new UpdateServiceInstanceRequest(serviceInstanceName, parameters, properties, rebindOnUpdate);
}
}

View File

@@ -30,23 +30,23 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithExistingServicesComponentTest.APP_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithExistingServicesComponentTest.SERVICE_INSTANCE_1_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithExistingServicesComponentTest.SERVICE_INSTANCE_2_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithExistingServicesComponentTest.BACKING_SI_1_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithExistingServicesComponentTest.BACKING_SI_2_NAME;
@TestPropertySource(properties = {
"spring.cloud.appbroker.services[0].service-name=example",
"spring.cloud.appbroker.services[0].plan-name=standard",
"spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar",
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + SERVICE_INSTANCE_1_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[1].service-instance-name=" + SERVICE_INSTANCE_2_NAME
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + BACKING_SI_1_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[1].service-instance-name=" + BACKING_SI_2_NAME
})
class CreateInstanceWithExistingServicesComponentTest extends WiremockComponentTest {
static final String APP_NAME = "app-with-services";
static final String SERVICE_INSTANCE_1_NAME = "my-db-service";
static final String SERVICE_INSTANCE_2_NAME = "my-rabbit-service";
static final String BACKING_SI_1_NAME = "my-db-service";
static final String BACKING_SI_2_NAME = "my-rabbit-service";
@Autowired
private OpenServiceBrokerApiFixture brokerFixture;
@@ -60,11 +60,11 @@ class CreateInstanceWithExistingServicesComponentTest extends WiremockComponentT
cloudControllerFixture.stubPushApp(APP_NAME);
// given that service instances exist
cloudControllerFixture.stubServiceInstanceExists(SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubServiceInstanceExists(SERVICE_INSTANCE_2_NAME);
cloudControllerFixture.stubServiceInstanceExists(BACKING_SI_1_NAME);
cloudControllerFixture.stubServiceInstanceExists(BACKING_SI_2_NAME);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, SERVICE_INSTANCE_2_NAME);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, BACKING_SI_1_NAME);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, BACKING_SI_2_NAME);
// when a service instance is created
given(brokerFixture.serviceInstanceRequest())

View File

@@ -30,17 +30,17 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesAndTargetComponentTest.APP_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesAndTargetComponentTest.SERVICE_1_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesAndTargetComponentTest.SERVICE_INSTANCE_1_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesAndTargetComponentTest.BACKING_SERVICE_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesAndTargetComponentTest.BACKING_SI_NAME;
@TestPropertySource(properties = {
"spring.cloud.appbroker.services[0].service-name=example",
"spring.cloud.appbroker.services[0].plan-name=standard",
"spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar",
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + SERVICE_INSTANCE_1_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + SERVICE_INSTANCE_1_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + SERVICE_1_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + BACKING_SERVICE_NAME,
"spring.cloud.appbroker.services[0].services[0].plan=standard",
"spring.cloud.appbroker.services[0].target.name=SpacePerServiceInstance"
})
@@ -48,8 +48,8 @@ class CreateInstanceWithServicesAndTargetComponentTest extends WiremockComponent
static final String APP_NAME = "app-new-services-target";
static final String SERVICE_INSTANCE_1_NAME = "my-db-service";
static final String SERVICE_1_NAME = "db-service";
static final String BACKING_SI_NAME = "my-db-service";
static final String BACKING_SERVICE_NAME = "db-service";
@Autowired
private OpenServiceBrokerApiFixture brokerFixture;
@@ -65,15 +65,15 @@ class CreateInstanceWithServicesAndTargetComponentTest extends WiremockComponent
cloudControllerFixture.stubPushAppWithHost(APP_NAME, host);
// given that service instances does not exist
cloudControllerFixture.stubServiceInstanceDoesNotExists(SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubServiceInstanceDoesNotExists(BACKING_SI_NAME);
// and the services are available in the marketplace
cloudControllerFixture.stubServiceExists(SERVICE_1_NAME);
cloudControllerFixture.stubServiceExists(BACKING_SERVICE_NAME);
// will create and bind the service instance
cloudControllerFixture.stubCreateServiceInstance(SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubServiceInstanceExists(SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubCreateServiceInstance(BACKING_SI_NAME);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubServiceInstanceExists(BACKING_SI_NAME);
// when a service instance is created
given(brokerFixture.serviceInstanceRequest())

View File

@@ -30,25 +30,25 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesComponentTest.APP_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesComponentTest.SERVICE_1_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesComponentTest.SERVICE_INSTANCE_1_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesComponentTest.BACKING_SERVICE_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesComponentTest.BACKING_SI_NAME;
@TestPropertySource(properties = {
"spring.cloud.appbroker.services[0].service-name=example",
"spring.cloud.appbroker.services[0].plan-name=standard",
"spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar",
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + SERVICE_INSTANCE_1_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + SERVICE_INSTANCE_1_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + SERVICE_1_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + BACKING_SERVICE_NAME,
"spring.cloud.appbroker.services[0].services[0].plan=standard"
})
class CreateInstanceWithServicesComponentTest extends WiremockComponentTest {
static final String APP_NAME = "app-with-new-services";
static final String SERVICE_INSTANCE_1_NAME = "my-db-service";
static final String SERVICE_1_NAME = "db-service";
static final String BACKING_SI_NAME = "my-db-service";
static final String BACKING_SERVICE_NAME = "db-service";
@Autowired
private OpenServiceBrokerApiFixture brokerFixture;
@@ -62,15 +62,15 @@ class CreateInstanceWithServicesComponentTest extends WiremockComponentTest {
cloudControllerFixture.stubPushApp(APP_NAME);
// given that service instances does not exist
cloudControllerFixture.stubServiceInstanceDoesNotExists(SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubServiceInstanceDoesNotExists(BACKING_SI_NAME);
// and the services are available in the marketplace
cloudControllerFixture.stubServiceExists(SERVICE_1_NAME);
cloudControllerFixture.stubServiceExists(BACKING_SERVICE_NAME);
// will create and bind the service instance
cloudControllerFixture.stubCreateServiceInstance(SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubServiceInstanceExists(SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubCreateServiceInstance(BACKING_SI_NAME);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubServiceInstanceExists(BACKING_SI_NAME);
// when a service instance is created
given(brokerFixture.serviceInstanceRequest())

View File

@@ -33,17 +33,17 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesParametersComponentTest.APP_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesParametersComponentTest.SERVICE_1_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesParametersComponentTest.SERVICE_INSTANCE_1_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesParametersComponentTest.BACKING_SERVICE_NAME;
import static org.springframework.cloud.appbroker.integration.CreateInstanceWithServicesParametersComponentTest.BACKING_SI_NAME;
@TestPropertySource(properties = {
"spring.cloud.appbroker.services[0].service-name=example",
"spring.cloud.appbroker.services[0].plan-name=standard",
"spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar",
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + SERVICE_INSTANCE_1_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + SERVICE_INSTANCE_1_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + SERVICE_1_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + BACKING_SERVICE_NAME,
"spring.cloud.appbroker.services[0].services[0].plan=standard",
"spring.cloud.appbroker.services[0].services[0].parameters-transformers[0].name=ParameterMapping",
"spring.cloud.appbroker.services[0].services[0].parameters-transformers[0].args.include=paramA,paramC"
@@ -52,8 +52,8 @@ class CreateInstanceWithServicesParametersComponentTest extends WiremockComponen
static final String APP_NAME = "app-services-param";
static final String SERVICE_INSTANCE_1_NAME = "my-db-service";
static final String SERVICE_1_NAME = "db-service";
static final String BACKING_SI_NAME = "my-db-service";
static final String BACKING_SERVICE_NAME = "db-service";
@Autowired
private OpenServiceBrokerApiFixture brokerFixture;
@@ -67,19 +67,19 @@ class CreateInstanceWithServicesParametersComponentTest extends WiremockComponen
cloudControllerFixture.stubPushApp(APP_NAME);
// given that service instances does not exist
cloudControllerFixture.stubServiceInstanceDoesNotExists(SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubServiceInstanceDoesNotExists(BACKING_SI_NAME);
// and the services are available in the marketplace
cloudControllerFixture.stubServiceExists(SERVICE_1_NAME);
cloudControllerFixture.stubServiceExists(BACKING_SERVICE_NAME);
// will create with filtered parameters and bind the service instance
HashMap<String, Object> expectedCreationParameters = new HashMap<>();
expectedCreationParameters.put("paramA", "valueA");
expectedCreationParameters.put("paramC", Collections.singletonMap("paramC1", "valueC1"));
cloudControllerFixture.stubCreateServiceInstanceWithParameters(SERVICE_INSTANCE_1_NAME, expectedCreationParameters);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubServiceInstanceExists(SERVICE_INSTANCE_1_NAME);
cloudControllerFixture.stubCreateServiceInstanceWithParameters(BACKING_SI_NAME, expectedCreationParameters);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubServiceInstanceExists(BACKING_SI_NAME);
// when a service instance is created with parameters
HashMap<String, Object> creationParameters = new HashMap<>();

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2016-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.appbroker.integration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.appbroker.integration.fixtures.CloudControllerStubFixture;
import org.springframework.cloud.appbroker.integration.fixtures.OpenServiceBrokerApiFixture;
import org.springframework.cloud.servicebroker.model.instance.OperationState;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.TestPropertySource;
import static io.restassured.RestAssured.given;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.springframework.cloud.appbroker.integration.DeleteInstanceWithServicesComponentTest.APP_NAME;
import static org.springframework.cloud.appbroker.integration.DeleteInstanceWithServicesComponentTest.BACKING_SERVICE_NAME;
import static org.springframework.cloud.appbroker.integration.DeleteInstanceWithServicesComponentTest.BACKING_SI_NAME;
@TestPropertySource(properties = {
"spring.cloud.appbroker.services[0].service-name=example",
"spring.cloud.appbroker.services[0].plan-name=standard",
"spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar",
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + BACKING_SERVICE_NAME,
"spring.cloud.appbroker.services[0].services[0].plan=standard"
})
class DeleteInstanceWithServicesComponentTest extends WiremockComponentTest {
static final String APP_NAME = "app-delete-with-services";
static final String BACKING_SI_NAME = "my-db-service";
static final String BACKING_SERVICE_NAME = "db-service";
@Autowired
private OpenServiceBrokerApiFixture brokerFixture;
@Autowired
private CloudControllerStubFixture cloudControllerFixture;
@Test
void deleteAppsAndServicesWhenTheyExist() {
cloudControllerFixture.stubAppExists(APP_NAME);
cloudControllerFixture.stubServiceBindingDoesNotExist(APP_NAME);
cloudControllerFixture.stubDeleteApp(APP_NAME);
cloudControllerFixture.stubServiceInstanceExists(BACKING_SI_NAME);
cloudControllerFixture.stubListServiceBindings(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubServiceBindingExists(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubDeleteServiceBinding(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubDeleteServiceInstance(BACKING_SI_NAME);
// when the service instance is deleted
given(brokerFixture.serviceInstanceRequest())
.when()
.delete(brokerFixture.deleteServiceInstanceUrl(), "instance-id")
.then()
.statusCode(HttpStatus.ACCEPTED.value());
// when the "last_operation" API is polled
given(brokerFixture.serviceInstanceRequest())
.when()
.get(brokerFixture.getLastInstanceOperationUrl(), "instance-id")
.then()
.statusCode(HttpStatus.OK.value())
.body("state", is(equalTo(OperationState.IN_PROGRESS.toString())));
String state = brokerFixture.waitForAsyncOperationComplete("instance-id");
assertThat(state).isEqualTo(OperationState.SUCCEEDED.toString());
}
}

View File

@@ -56,7 +56,7 @@ class UpdateInstanceWithServicesComponentTest extends WiremockComponentTest {
private CloudControllerStubFixture cloudControllerFixture;
@Test
void updateAppWithServicesWhenServicesExist() {
void updateAppWithServices() {
cloudControllerFixture.stubAppExists(APP_NAME);
cloudControllerFixture.stubUpdateApp(APP_NAME);

View File

@@ -32,17 +32,17 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.springframework.cloud.appbroker.integration.UpdateInstanceWithServicesParametersComponentTest.APP_NAME;
import static org.springframework.cloud.appbroker.integration.UpdateInstanceWithServicesParametersComponentTest.SERVICE_NAME;
import static org.springframework.cloud.appbroker.integration.UpdateInstanceWithServicesParametersComponentTest.SERVICE_INSTANCE_NAME;
import static org.springframework.cloud.appbroker.integration.UpdateInstanceWithServicesParametersComponentTest.BACKING_SERVICE_NAME;
import static org.springframework.cloud.appbroker.integration.UpdateInstanceWithServicesParametersComponentTest.BACKING_SI_NAME;
@TestPropertySource(properties = {
"spring.cloud.appbroker.services[0].service-name=example",
"spring.cloud.appbroker.services[0].plan-name=standard",
"spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar",
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + SERVICE_INSTANCE_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + SERVICE_INSTANCE_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + SERVICE_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + BACKING_SERVICE_NAME,
"spring.cloud.appbroker.services[0].services[0].plan=standard",
"spring.cloud.appbroker.services[0].services[0].parameters-transformers[0].name=ParameterMapping",
"spring.cloud.appbroker.services[0].services[0].parameters-transformers[0].args.include=paramA,paramC"
@@ -51,8 +51,8 @@ class UpdateInstanceWithServicesParametersComponentTest extends WiremockComponen
static final String APP_NAME = "app-update-services-param";
static final String SERVICE_INSTANCE_NAME = "my-db-service";
static final String SERVICE_NAME = "db-service";
static final String BACKING_SI_NAME = "my-db-service";
static final String BACKING_SERVICE_NAME = "db-service";
@Autowired
private OpenServiceBrokerApiFixture brokerFixture;
@@ -65,17 +65,17 @@ class UpdateInstanceWithServicesParametersComponentTest extends WiremockComponen
cloudControllerFixture.stubAppExists(APP_NAME);
cloudControllerFixture.stubUpdateApp(APP_NAME);
cloudControllerFixture.stubServiceInstanceExists(SERVICE_INSTANCE_NAME);
cloudControllerFixture.stubListServiceBindings(APP_NAME, SERVICE_INSTANCE_NAME);
cloudControllerFixture.stubServiceBindingExists(APP_NAME, SERVICE_INSTANCE_NAME);
cloudControllerFixture.stubServiceInstanceExists(BACKING_SI_NAME);
cloudControllerFixture.stubListServiceBindings(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubServiceBindingExists(APP_NAME, BACKING_SI_NAME);
// will update with filtered parameters and bind the service instance
HashMap<String, Object> expectedCreationParameters = new HashMap<>();
expectedCreationParameters.put("paramA", "valueA");
expectedCreationParameters.put("paramC", Collections.singletonMap("paramC1", "valueC1"));
cloudControllerFixture.stubUpdateServiceInstanceWithParameters(SERVICE_INSTANCE_NAME, expectedCreationParameters);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, SERVICE_INSTANCE_NAME);
cloudControllerFixture.stubUpdateServiceInstanceWithParameters(BACKING_SI_NAME, expectedCreationParameters);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, BACKING_SI_NAME);
// when a service instance is created with parameters
HashMap<String, Object> creationParameters = new HashMap<>();

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2016-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.appbroker.integration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.appbroker.integration.fixtures.CloudControllerStubFixture;
import org.springframework.cloud.appbroker.integration.fixtures.OpenServiceBrokerApiFixture;
import org.springframework.cloud.servicebroker.model.instance.OperationState;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.TestPropertySource;
import static io.restassured.RestAssured.given;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.springframework.cloud.appbroker.integration.UpdateInstanceWithServicesRebindComponentTest.APP_NAME;
import static org.springframework.cloud.appbroker.integration.UpdateInstanceWithServicesRebindComponentTest.BACKING_SI_NAME;
import static org.springframework.cloud.appbroker.integration.UpdateInstanceWithServicesRebindComponentTest.BACKING_SERVICE_NAME;
@TestPropertySource(properties = {
"spring.cloud.appbroker.services[0].service-name=example",
"spring.cloud.appbroker.services[0].plan-name=standard",
"spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar",
"spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME,
"spring.cloud.appbroker.services[0].apps[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].service-instance-name=" + BACKING_SI_NAME,
"spring.cloud.appbroker.services[0].services[0].name=" + BACKING_SERVICE_NAME,
"spring.cloud.appbroker.services[0].services[0].plan=standard",
"spring.cloud.appbroker.services[0].services[0].rebind-on-update=true"
})
class UpdateInstanceWithServicesRebindComponentTest extends WiremockComponentTest {
static final String APP_NAME = "app-update-rebind-with-services";
static final String BACKING_SI_NAME = "my-db-service";
static final String BACKING_SERVICE_NAME = "db-service";
@Autowired
private OpenServiceBrokerApiFixture brokerFixture;
@Autowired
private CloudControllerStubFixture cloudControllerFixture;
@Test
void updateAppWithServices() {
cloudControllerFixture.stubAppExists(APP_NAME);
cloudControllerFixture.stubUpdateApp(APP_NAME);
cloudControllerFixture.stubServiceInstanceExists(BACKING_SI_NAME);
cloudControllerFixture.stubListServiceBindings(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubServiceBindingExists(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubDeleteServiceBinding(APP_NAME, BACKING_SI_NAME);
cloudControllerFixture.stubCreateServiceBinding(APP_NAME, BACKING_SI_NAME);
// when a service instance is updated
given(brokerFixture.serviceInstanceRequest())
.when()
.patch(brokerFixture.createServiceInstanceUrl(), "instance-id")
.then()
.statusCode(HttpStatus.ACCEPTED.value());
// when the "last_operation" API is polled
given(brokerFixture.serviceInstanceRequest())
.when()
.get(brokerFixture.getLastInstanceOperationUrl(), "instance-id")
.then()
.statusCode(HttpStatus.OK.value())
.body("state", is(equalTo(OperationState.IN_PROGRESS.toString())));
String state = brokerFixture.waitForAsyncOperationComplete("instance-id");
assertThat(state).isEqualTo(OperationState.SUCCEEDED.toString());
}
}

View File

@@ -138,11 +138,17 @@ public class CloudControllerStubFixture extends WiremockStubFixture {
}
public void stubAppExists(final String appName) {
stubFor(get(urlPathEqualTo("/v2/apps/" + appGuid(appName)))
.willReturn(ok()
.withBody(cc("get-app-STAGED",
replace("@name", appName)))));
stubFor(get(urlPathEqualTo("/v2/spaces/" + TEST_SPACE_GUID + "/apps"))
.withQueryParam("q", equalTo("name:" + appName))
.withQueryParam("page", equalTo("1"))
.willReturn(ok()
.withBody(cc("list-space-apps",
replace("@name", appName),
replace("@guid", appGuid(appName)),
replace("@space-guid", TEST_SPACE_GUID),
replace("@stack-guid", stackGuid(appName))))));
@@ -276,7 +282,8 @@ public class CloudControllerStubFixture extends WiremockStubFixture {
private void stubCheckAppState(String appName) {
stubFor(get(urlPathEqualTo("/v2/apps/" + appGuid(appName)))
.willReturn(ok()
.withBody(cc("get-app-STAGED"))));
.withBody(cc("get-app-STAGED",
replace("@name", appName)))));
stubFor(get(urlPathEqualTo("/v2/apps/" + appGuid(appName) + "/instances"))
.willReturn(ok()
@@ -357,6 +364,13 @@ public class CloudControllerStubFixture extends WiremockStubFixture {
.willReturn(ok()));
}
public void stubDeleteServiceInstance(String serviceInstanceName) {
String serviceInstanceGuid = serviceInstanceGuid(serviceInstanceName);
stubFor(delete(urlPathEqualTo("/v2/service_instances/" + serviceInstanceGuid))
.willReturn(ok()));
}
public void stubCreateServiceBinding(String appName, String serviceInstanceName) {
String serviceInstanceGuid = serviceInstanceGuid(serviceInstanceName);
String serviceBindingGuid = serviceBindingGuid(appName, serviceInstanceName);
@@ -365,12 +379,24 @@ public class CloudControllerStubFixture extends WiremockStubFixture {
.withRequestBody(matchingJsonPath("$.[?(@.app_guid == '" + appGuid(appName) + "')]"))
.withRequestBody(matchingJsonPath("$.[?(@.service_instance_guid == '" + serviceInstanceGuid + "')]"))
.willReturn(created()
.withBody(cc("get-service_bindings",
.withBody(cc("get-service_binding",
replace("@guid", serviceBindingGuid),
replace("@app-guid", appGuid(appName)),
replace("@service-instance-guid", serviceInstanceGuid)))));
}
public void stubDeleteServiceBinding(String appName, String serviceInstanceName) {
String appGuid = appGuid(appName);
String serviceBindingGuid = serviceBindingGuid(appName, serviceInstanceName);
stubFor(delete(urlPathEqualTo("/v2/service_bindings/" + serviceBindingGuid))
.withQueryParam("async", equalTo("true"))
.willReturn(noContent()));
stubFor(delete(urlPathEqualTo("/v2/apps/" + appGuid + "/service_bindings/" + serviceBindingGuid))
.willReturn(noContent()));
}
public void stubListServiceBindings(String appName, String serviceInstanceName) {
String serviceInstanceGuid = serviceInstanceGuid(serviceInstanceName);
String serviceBindingGuid = serviceBindingGuid(appName, serviceInstanceName);
@@ -392,7 +418,16 @@ public class CloudControllerStubFixture extends WiremockStubFixture {
stubFor(get(urlPathEqualTo("/v2/apps/" + appGuid(appName) + "/service_bindings"))
.willReturn(ok()
.withBody(cc("get-service_bindings",
replace("@guid", serviceBindingGuid),
replace("@service-binding-guid", serviceBindingGuid),
replace("@app-guid", appGuid(appName)),
replace("@service-instance-guid", serviceInstanceGuid)))));
stubFor(get(urlPathEqualTo("/v2/apps/" + appGuid(appName) + "/service_bindings"))
.withQueryParam("q", equalTo("service_instance_guid:" + serviceInstanceGuid))
.withQueryParam("page", equalTo("1"))
.willReturn(ok()
.withBody(cc("get-service_bindings",
replace("@service-binding-guid", serviceBindingGuid),
replace("@app-guid", appGuid(appName)),
replace("@service-instance-guid", serviceInstanceGuid)))));
}

View File

@@ -0,0 +1,21 @@
{
"entity": {
"app_guid": "@app-guid",
"app_url": "/v2/apps/@app-guid",
"binding_options": {},
"credentials": {},
"gateway_data": null,
"gateway_name": "",
"name": null,
"service_instance_guid": "@service-instance-guid",
"service_instance_url": "/v2/service_instances/@service-instance-guid",
"syslog_drain_url": "",
"volume_mounts": null
},
"metadata": {
"created_at": "2018-08-17T22:01:54Z",
"guid": "@guid",
"updated_at": "2018-08-17T22:01:54Z",
"url": "/v2/service_bindings/@guid"
}
}

View File

@@ -1,21 +1,37 @@
{
"entity": {
"app_guid": "@app-guid",
"app_url": "/v2/apps/@app-guid",
"binding_options": {},
"credentials": {},
"gateway_data": null,
"gateway_name": "",
"name": null,
"service_instance_guid": "@service-instance-guid",
"service_instance_url": "/v2/service_instances/@service-instance-guid",
"syslog_drain_url": "",
"volume_mounts": null
},
"metadata": {
"created_at": "2018-08-17T22:01:54Z",
"guid": "@guid",
"updated_at": "2018-08-17T22:01:54Z",
"url": "/v2/service_bindings/@guid"
}
"total_results": 1,
"total_pages": 1,
"prev_url": null,
"next_url": null,
"resources": [
{
"metadata": {
"guid": "@service-binding-guid",
"url": "/v2/service_bindings/@service-binding-guid",
"created_at": "2016-06-08T16:41:43Z",
"updated_at": "2016-06-08T16:41:26Z"
},
"entity": {
"app_guid": "@app-guid",
"service_instance_guid": "@service-instance-guid",
"credentials": {},
"binding_options": {},
"gateway_data": null,
"gateway_name": "",
"syslog_drain_url": null,
"volume_mounts": [],
"name": "",
"last_operation": {
"type": "create",
"state": "succeeded",
"description": "",
"updated_at": "2018-02-28T16:25:19Z",
"created_at": "2018-02-28T16:25:19Z"
},
"app_url": "/v2/apps/@app-guid",
"service_instance_url": "/v2/service_instances/@service-instance-guid",
"service_binding_parameters_url": "/v2/service_bindings/@service-binding-guid/parameters"
}
}
]
}

View File

@@ -7,7 +7,7 @@
{
"metadata": {
"guid": "@guid",
"url": "/v2/user_provided_service_instances/@guid",
"url": "/v2/service_instances/@guid",
"created_at": "2018-07-19T22:29:41Z",
"updated_at": "2018-07-19T22:29:41Z"
},
@@ -15,13 +15,13 @@
"name": "@name",
"credentials": {},
"space_guid": "@space-guid",
"type": "user_provided_service_instance",
"type": "managed_service_instance",
"syslog_drain_url": "",
"route_service_url": "",
"space_url": "/v2/spaces/@space-guid",
"service_bindings_url": "/v2/user_provided_service_instances/@guid/service_bindings",
"service_keys_url": "/v2/user_provided_service_instances/@guid/service_keys",
"routes_url": "/v2/user_provided_service_instances/@guid/routes"
"service_bindings_url": "/v2/service_instances/@guid/service_bindings",
"service_keys_url": "/v2/service_instances/@guid/service_keys",
"routes_url": "/v2/service_instances/@guid/routes"
}
}
]