Allow backing service instances to be unbound and rebound to backing apps on service instance update.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ class UpdateInstanceWithServicesComponentTest extends WiremockComponentTest {
|
||||
private CloudControllerStubFixture cloudControllerFixture;
|
||||
|
||||
@Test
|
||||
void updateAppWithServicesWhenServicesExist() {
|
||||
void updateAppWithServices() {
|
||||
cloudControllerFixture.stubAppExists(APP_NAME);
|
||||
cloudControllerFixture.stubUpdateApp(APP_NAME);
|
||||
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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)))));
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user