From a73c600181f5c2fd0e4cbc2ec89dd41148ad5d9f Mon Sep 17 00:00:00 2001 From: Alberto Rios Date: Wed, 22 Aug 2018 15:26:31 +0200 Subject: [PATCH] Adding environment variable from create-service params Finishes #20 --- .../CloudFoundryAcceptanceTest.java | 8 +- .../CreateInstanceAcceptanceTest.java | 1 - ...eInstanceWithParametersAcceptanceTest.java | 51 ++++++ .../fixtures/cf/CloudFoundryService.java | 19 ++- .../WorkflowServiceInstanceService.java | 11 +- .../CreateServiceInstanceWorkflow.java | 19 ++- .../WorkflowServiceInstanceServiceTest.java | 47 +++++- .../CreateServiceInstanceWorkflowTest.java | 151 ++++++++++++++++-- ...ceWithCreationParametersComponentTest.java | 81 ++++++++++ .../fixtures/OpenServiceBrokerApiFixture.java | 16 +- 10 files changed, 367 insertions(+), 37 deletions(-) create mode 100644 spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceWithParametersAcceptanceTest.java create mode 100644 spring-cloud-app-broker-sample/src/test/java/org.springframework.cloud.appbroker/sample/CreateInstanceWithCreationParametersComponentTest.java diff --git a/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CloudFoundryAcceptanceTest.java b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CloudFoundryAcceptanceTest.java index 943e61c..6b2ff01 100644 --- a/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CloudFoundryAcceptanceTest.java +++ b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CloudFoundryAcceptanceTest.java @@ -18,6 +18,8 @@ package org.springframework.cloud.appbroker.acceptance; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CountDownLatch; @@ -82,7 +84,11 @@ class CloudFoundryAcceptanceTest { } void createServiceInstance() { - blockingSubscribe(cloudFoundryService.createServiceInstance(PLAN_NAME, SERVICE_NAME, SERVICE_INSTANCE_NAME)); + createServiceInstanceWithParameters(Collections.emptyMap()); + } + + void createServiceInstanceWithParameters(Map parameters) { + blockingSubscribe(cloudFoundryService.createServiceInstance(PLAN_NAME, SERVICE_NAME, SERVICE_INSTANCE_NAME, parameters)); } void deleteServiceInstance() { diff --git a/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceAcceptanceTest.java b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceAcceptanceTest.java index 3341b63..18134e7 100644 --- a/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceAcceptanceTest.java +++ b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceAcceptanceTest.java @@ -32,7 +32,6 @@ class CreateInstanceAcceptanceTest extends CloudFoundryAcceptanceTest { @AppBrokerTestProperties({ "spring.cloud.appbroker.apps[0].name=" + BROKER_SAMPLE_APP_CREATE, "spring.cloud.appbroker.apps[0].path=classpath:demo.jar", - "spring.cloud.appbroker.apps[0].path=classpath:demo.jar", "spring.cloud.appbroker.apps[0].environment.ENV_VAR_1=value1", "spring.cloud.appbroker.apps[0].environment.ENV_VAR_2=value2", "spring.cloud.appbroker.apps[0].properties.spring.cloud.deployer.memory=2G", diff --git a/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceWithParametersAcceptanceTest.java b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceWithParametersAcceptanceTest.java new file mode 100644 index 0000000..8a90396 --- /dev/null +++ b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceWithParametersAcceptanceTest.java @@ -0,0 +1,51 @@ +/* + * 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.acceptance; + +import java.util.Collections; +import java.util.Optional; +import org.cloudfoundry.operations.applications.ApplicationEnvironments; +import org.cloudfoundry.operations.applications.ApplicationSummary; +import org.junit.jupiter.api.Test; + + +import static org.assertj.core.api.Assertions.assertThat; + +class CreateInstanceWithParametersAcceptanceTest extends CloudFoundryAcceptanceTest { + + private static final String BROKER_SAMPLE_APP_CREATE = "broker-sample-app-create-with-parameters"; + + @Test + @AppBrokerTestProperties({ + "spring.cloud.appbroker.apps[0].name=" + BROKER_SAMPLE_APP_CREATE, + "spring.cloud.appbroker.apps[0].path=classpath:demo.jar", + }) + void shouldPushAppWhenCreateServiceCalled() { + // when a service instance is created + createServiceInstanceWithParameters(Collections.singletonMap("ENV_VAR_1", "value1")); + + // then a backing application is deployed + Optional backingApplication = getApplicationSummaryByName(BROKER_SAMPLE_APP_CREATE); + assertThat(backingApplication).isNotEmpty(); + + // and has the environment variables + ApplicationEnvironments applicationEnvironments = getApplicationEnvironmentByName(BROKER_SAMPLE_APP_CREATE); + assertThat(applicationEnvironments.getUserProvided().get("SPRING_APPLICATION_JSON")).asString() + .contains("\"ENV_VAR_1\":\"value1\""); + } + +} \ No newline at end of file diff --git a/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/fixtures/cf/CloudFoundryService.java b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/fixtures/cf/CloudFoundryService.java index 910ea8b..0fd431e 100644 --- a/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/fixtures/cf/CloudFoundryService.java +++ b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/fixtures/cf/CloudFoundryService.java @@ -21,7 +21,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; - import org.cloudfoundry.client.CloudFoundryClient; import org.cloudfoundry.operations.CloudFoundryOperations; import org.cloudfoundry.operations.applications.ApplicationDetail; @@ -45,12 +44,12 @@ import org.cloudfoundry.operations.spaces.DefaultSpaces; import org.cloudfoundry.operations.spaces.SpaceSummary; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.appbroker.acceptance.AcceptanceTestProperties; import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + import static java.lang.String.format; @@ -65,8 +64,10 @@ public class CloudFoundryService { private AcceptanceTestProperties acceptanceTestProperties; @Autowired - public CloudFoundryService(CloudFoundryOperations cloudFoundryOperations, CloudFoundryProperties cloudFoundryProperties, - CloudFoundryClient cloudFoundryClient, AcceptanceTestProperties acceptanceTestProperties) { + public CloudFoundryService(CloudFoundryOperations cloudFoundryOperations, + CloudFoundryProperties cloudFoundryProperties, + CloudFoundryClient cloudFoundryClient, + AcceptanceTestProperties acceptanceTestProperties) { this.cloudFoundryOperations = cloudFoundryOperations; this.cloudFoundryProperties = cloudFoundryProperties; this.cloudFoundryClient = cloudFoundryClient; @@ -150,7 +151,10 @@ public class CloudFoundryService { .deleteInstance(DeleteServiceInstanceRequest.builder().name(si.getName()).build()))); } - public Mono createServiceInstance(String planName, String serviceName, String serviceInstanceName) { + public Mono createServiceInstance(String planName, + String serviceName, + String serviceInstanceName, + Map parameters) { return loggingMono( cloudFoundryOperations .services() @@ -159,6 +163,7 @@ public class CloudFoundryService { .planName(planName) .serviceName(serviceName) .serviceInstanceName(serviceInstanceName) + .parameters(parameters) .build())); } diff --git a/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/service/WorkflowServiceInstanceService.java b/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/service/WorkflowServiceInstanceService.java index 4dd1ea9..258d4b3 100644 --- a/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/service/WorkflowServiceInstanceService.java +++ b/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/service/WorkflowServiceInstanceService.java @@ -18,11 +18,6 @@ package org.springframework.cloud.appbroker.service; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; -import reactor.util.Logger; -import reactor.util.Loggers; - import org.springframework.cloud.appbroker.state.ServiceInstanceStateRepository; import org.springframework.cloud.appbroker.workflow.instance.CreateServiceInstanceWorkflow; import org.springframework.cloud.appbroker.workflow.instance.DeleteServiceInstanceWorkflow; @@ -39,6 +34,10 @@ import org.springframework.cloud.servicebroker.model.instance.OperationState; import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest; import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse; import org.springframework.cloud.servicebroker.service.ServiceInstanceService; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; +import reactor.util.Logger; +import reactor.util.Loggers; /** * A {@code ServiceInstanceService} that delegates to a set of discrete Workflow objects for each service broker @@ -75,7 +74,7 @@ public class WorkflowServiceInstanceService implements ServiceInstanceService { return stateRepository.saveState(request.getServiceInstanceId(), OperationState.IN_PROGRESS, "create service instance started") - .then(createServiceInstanceWorkflow.create() + .then(createServiceInstanceWorkflow.create(request.getParameters()) .doOnRequest(l -> log.info("Creating service instance {}", request)) .doOnSuccess(d -> log.info("Finished creating service instance {}", request)) .doOnError(e -> log.info("Error creating service instance {} with error {}", request, e))) diff --git a/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/workflow/instance/CreateServiceInstanceWorkflow.java b/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/workflow/instance/CreateServiceInstanceWorkflow.java index 6cf350d..91da7eb 100644 --- a/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/workflow/instance/CreateServiceInstanceWorkflow.java +++ b/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/workflow/instance/CreateServiceInstanceWorkflow.java @@ -16,10 +16,11 @@ package org.springframework.cloud.appbroker.workflow.instance; -import reactor.core.publisher.Mono; - +import java.util.HashMap; +import java.util.Map; import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService; import org.springframework.cloud.appbroker.deployer.BackingApplications; +import reactor.core.publisher.Mono; import reactor.util.Logger; import reactor.util.Loggers; @@ -35,7 +36,19 @@ public class CreateServiceInstanceWorkflow { this.deploymentService = deploymentService; } - public Mono create() { + public Mono create(Map parameters) { + backingApps.forEach(backingApplication -> { + final Map environment = new HashMap<>(); + final Map backingAppEnvironment = backingApplication.getEnvironment(); + if (backingAppEnvironment != null) { + environment.putAll(backingAppEnvironment); + } + if (parameters != null) { + parameters.forEach((key, value) -> environment.put(key, value.toString())); + } + backingApplication.setEnvironment(environment); + }); + return deploymentService.deploy(backingApps) .doOnRequest(l -> log.info("Deploying applications {}", backingApps)) .doOnSuccess(d -> log.info("Finished deploying applications {}", backingApps)) diff --git a/spring-cloud-app-broker-core/src/test/java/org/springframework/cloud/appbroker/service/WorkflowServiceInstanceServiceTest.java b/spring-cloud-app-broker-core/src/test/java/org/springframework/cloud/appbroker/service/WorkflowServiceInstanceServiceTest.java index c218ed7..f6b3cd6 100644 --- a/spring-cloud-app-broker-core/src/test/java/org/springframework/cloud/appbroker/service/WorkflowServiceInstanceServiceTest.java +++ b/spring-cloud-app-broker-core/src/test/java/org/springframework/cloud/appbroker/service/WorkflowServiceInstanceServiceTest.java @@ -16,14 +16,14 @@ package org.springframework.cloud.appbroker.service; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - import org.springframework.cloud.appbroker.state.ServiceInstanceState; import org.springframework.cloud.appbroker.state.ServiceInstanceStateRepository; import org.springframework.cloud.appbroker.workflow.instance.CreateServiceInstanceWorkflow; @@ -31,6 +31,9 @@ import org.springframework.cloud.appbroker.workflow.instance.DeleteServiceInstan import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest; import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest; import org.springframework.cloud.servicebroker.model.instance.OperationState; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -67,7 +70,7 @@ class WorkflowServiceInstanceServiceTest { .thenReturn(Mono.just(new ServiceInstanceState(OperationState.IN_PROGRESS, "create service instance started"))) .thenReturn(Mono.just(new ServiceInstanceState(OperationState.SUCCEEDED, "create service instance completed"))); - given(createServiceInstanceWorkflow.create()) + given(createServiceInstanceWorkflow.create(Collections.emptyMap())) .willReturn(Mono.empty()); StepVerifier.create(workflowServiceInstanceService.createServiceInstance(CreateServiceInstanceRequest.builder() @@ -76,7 +79,37 @@ class WorkflowServiceInstanceServiceTest { .assertNext(createServiceInstanceResponse -> { verify(serviceInstanceStateRepository) .saveState(eq("foo"), eq(OperationState.IN_PROGRESS), eq("create service instance started")); - verify(createServiceInstanceWorkflow).create(); + verify(createServiceInstanceWorkflow).create(Collections.emptyMap()); + verify(serviceInstanceStateRepository) + .saveState(eq("foo"), eq(OperationState.SUCCEEDED), eq("create service instance completed")); + verifyNoMoreInteractions(serviceInstanceStateRepository, createServiceInstanceWorkflow); + assertThat(createServiceInstanceResponse).isNotNull(); + assertThat(createServiceInstanceResponse.isAsync()).isTrue(); + }) + .verifyComplete(); + } + + @Test + void createServiceInstanceWithParameters() { + when(serviceInstanceStateRepository.saveState(anyString(), any(OperationState.class), anyString())) + .thenReturn(Mono.just(new ServiceInstanceState(OperationState.IN_PROGRESS, "create service instance started"))) + .thenReturn(Mono.just(new ServiceInstanceState(OperationState.SUCCEEDED, "create service instance completed"))); + + Map params = new HashMap<>(); + params.put("ENV_VAR_1", "value1"); + params.put("ENV_VAR_2", true); + + given(createServiceInstanceWorkflow.create(params)) + .willReturn(Mono.empty()); + + StepVerifier.create(workflowServiceInstanceService.createServiceInstance(CreateServiceInstanceRequest.builder() + .serviceInstanceId("foo") + .parameters(params) + .build())) + .assertNext(createServiceInstanceResponse -> { + verify(serviceInstanceStateRepository) + .saveState(eq("foo"), eq(OperationState.IN_PROGRESS), eq("create service instance started")); + verify(createServiceInstanceWorkflow).create(params); verify(serviceInstanceStateRepository) .saveState(eq("foo"), eq(OperationState.SUCCEEDED), eq("create service instance completed")); verifyNoMoreInteractions(serviceInstanceStateRepository, createServiceInstanceWorkflow); @@ -92,7 +125,7 @@ class WorkflowServiceInstanceServiceTest { .thenReturn(Mono.just(new ServiceInstanceState(OperationState.IN_PROGRESS, "create service instance started"))) .thenReturn(Mono.just(new ServiceInstanceState(OperationState.FAILED, "create service instance failed"))); - given(createServiceInstanceWorkflow.create()) + given(createServiceInstanceWorkflow.create(Collections.emptyMap())) .willReturn(Mono.error(new RuntimeException("create foo error"))); StepVerifier.create(workflowServiceInstanceService.createServiceInstance(CreateServiceInstanceRequest.builder() @@ -101,7 +134,7 @@ class WorkflowServiceInstanceServiceTest { .assertNext(error -> { verify(serviceInstanceStateRepository) .saveState(eq("foo"), eq(OperationState.IN_PROGRESS), eq("create service instance started")); - verify(createServiceInstanceWorkflow).create(); + verify(createServiceInstanceWorkflow).create(Collections.emptyMap()); verify(serviceInstanceStateRepository) .saveState(eq("foo"), eq(OperationState.FAILED), eq("create foo error")); verifyNoMoreInteractions(serviceInstanceStateRepository, createServiceInstanceWorkflow); diff --git a/spring-cloud-app-broker-core/src/test/java/org/springframework/cloud/appbroker/workflow/instance/CreateServiceInstanceWorkflowTest.java b/spring-cloud-app-broker-core/src/test/java/org/springframework/cloud/appbroker/workflow/instance/CreateServiceInstanceWorkflowTest.java index 2e4fce8..5af6d5d 100644 --- a/spring-cloud-app-broker-core/src/test/java/org/springframework/cloud/appbroker/workflow/instance/CreateServiceInstanceWorkflowTest.java +++ b/spring-cloud-app-broker-core/src/test/java/org/springframework/cloud/appbroker/workflow/instance/CreateServiceInstanceWorkflowTest.java @@ -16,16 +16,21 @@ package org.springframework.cloud.appbroker.workflow.instance; +import java.util.Collections; +import java.util.Map; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import reactor.core.publisher.Mono; - import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService; import org.springframework.cloud.appbroker.deployer.BackingApplication; import org.springframework.cloud.appbroker.deployer.BackingApplications; +import reactor.core.publisher.Mono; + +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verify; @@ -39,23 +44,147 @@ class CreateServiceInstanceWorkflowTest { @Test void shouldCreateServiceInstance() { given(this.backingAppDeploymentService.deploy(any(BackingApplications.class))) - .willReturn(Mono.just("hello")); + .willReturn(Mono.just("deployment-id-app1")); // given that properties contains app details - BackingApplications backingApps = BackingApplications.builder() + CreateServiceInstanceWorkflow createServiceInstanceWorkflow = + new CreateServiceInstanceWorkflow(createBackingApplications(), backingAppDeploymentService); + + // when + createServiceInstanceWorkflow.create(Collections.emptyMap()); + + // then deployer should be called with the application details + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BackingApplications.class); + verify(backingAppDeploymentService).deploy(argumentCaptor.capture()); + + BackingApplication backingApplication = argumentCaptor.getValue().get(0); + assertThat(backingApplication.getName()).isEqualTo("helloworldapp"); + assertThat(backingApplication.getPath()).isEqualTo("http://myfiles/app.jar"); + assertThat(backingApplication.getEnvironment()).isEqualTo(Collections.emptyMap()); + } + + @Test + void shouldCreateServiceInstanceWithEnvironment() { + given(this.backingAppDeploymentService.deploy(any(BackingApplications.class))) + .willReturn(Mono.just("deployment-id-app1")); + + // given that properties contains app details and environment variables + Map environment = singletonMap("ENV_VAR_1", "value from environment"); + CreateServiceInstanceWorkflow createServiceInstanceWorkflow = + new CreateServiceInstanceWorkflow(createBackingApplicationWithEnvironment(environment), backingAppDeploymentService); + + // when + createServiceInstanceWorkflow.create(Collections.emptyMap()); + + // then deployer should be called with the application details and the environment variables + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BackingApplications.class); + verify(backingAppDeploymentService).deploy(argumentCaptor.capture()); + + BackingApplication backingApplication = argumentCaptor.getValue().get(0); + assertThat(backingApplication.getName()).isEqualTo("helloworldapp"); + assertThat(backingApplication.getPath()).isEqualTo("http://myfiles/app.jar"); + assertThat(backingApplication.getEnvironment()).isEqualTo(singletonMap("ENV_VAR_1", "value from environment")); + } + + @Test + void shouldCreateServiceInstanceWithParameters() { + given(this.backingAppDeploymentService.deploy(any(BackingApplications.class))) + .willReturn(Mono.just("deployment-id-app1")); + + // given that properties contains app details + CreateServiceInstanceWorkflow createServiceInstanceWorkflow = + new CreateServiceInstanceWorkflow(createBackingApplications(), backingAppDeploymentService); + + // when create is called with parameters + Map parameters = singletonMap("ENV_VAR_1", "value from parameters"); + createServiceInstanceWorkflow.create(parameters); + + // then deployer should be called with the application details and environment variables + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BackingApplications.class); + verify(backingAppDeploymentService).deploy(argumentCaptor.capture()); + + BackingApplication backingApplication = argumentCaptor.getValue().get(0); + assertThat(backingApplication.getName()).isEqualTo("helloworldapp"); + assertThat(backingApplication.getPath()).isEqualTo("http://myfiles/app.jar"); + assertThat(backingApplication.getEnvironment()).isEqualTo(singletonMap("ENV_VAR_1", "value from parameters")); + } + + @Test + void shouldCreateServiceInstanceOverwritingEnvironmentPropertiesWithParameters() { + given(this.backingAppDeploymentService.deploy(any(BackingApplications.class))) + .willReturn(Mono.just("deployment-id-app1")); + + // given that properties contains app details and environment variables + Map environment = singletonMap("ENV_VAR_1", "value from environment"); + CreateServiceInstanceWorkflow createServiceInstanceWorkflow = + new CreateServiceInstanceWorkflow(createBackingApplicationWithEnvironment(environment), backingAppDeploymentService); + + // when create is called with parameters + Map parameters = singletonMap("ENV_VAR_1", "value from parameters"); + createServiceInstanceWorkflow.create(parameters); + + // then deployer should contain the environment with the value from the parameters + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BackingApplications.class); + verify(backingAppDeploymentService).deploy(argumentCaptor.capture()); + + BackingApplication backingApplication = argumentCaptor.getValue().get(0); + assertThat(backingApplication.getName()).isEqualTo("helloworldapp"); + assertThat(backingApplication.getPath()).isEqualTo("http://myfiles/app.jar"); + assertThat(backingApplication.getEnvironment()).isEqualTo(singletonMap("ENV_VAR_1", "value from parameters")); + } + + @Test + void shouldCreateServiceInstanceWithMultipleApplicationsAndProperties() { + given(this.backingAppDeploymentService.deploy(any(BackingApplications.class))) + .willReturn(Mono.just("deployment-id-app1")); + + // given that properties contains two apps + BackingApplications backingApplications = BackingApplications.builder() .backingApplication(BackingApplication.builder() - .name("helloworldapp") + .name("helloworldapp1") + .path("http://myfiles/app.jar") + .build()) + .backingApplication(BackingApplication.builder() + .name("helloworldapp2") .path("http://myfiles/app.jar") .build()) .build(); + CreateServiceInstanceWorkflow createServiceInstanceWorkflow = - new CreateServiceInstanceWorkflow(backingApps, backingAppDeploymentService); + new CreateServiceInstanceWorkflow(backingApplications, backingAppDeploymentService); - // when - createServiceInstanceWorkflow.create(); + // when create is called with parameters + Map parameters = singletonMap("ENV_VAR_1", "value from parameters"); + createServiceInstanceWorkflow.create(parameters); - // then deployer should be called with the application details - verify(backingAppDeploymentService) - .deploy(backingApps); + // then deployer should contain the environment with the value from the parameters + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(BackingApplications.class); + verify(backingAppDeploymentService).deploy(argumentCaptor.capture()); + + BackingApplication backingApplication1 = argumentCaptor.getValue().get(0); + assertThat(backingApplication1.getName()).isEqualTo("helloworldapp1"); + assertThat(backingApplication1.getPath()).isEqualTo("http://myfiles/app.jar"); + assertThat(backingApplication1.getEnvironment()).isEqualTo(singletonMap("ENV_VAR_1", "value from parameters")); + + BackingApplication backingApplication2 = argumentCaptor.getValue().get(1); + assertThat(backingApplication2.getName()).isEqualTo("helloworldapp2"); + assertThat(backingApplication2.getPath()).isEqualTo("http://myfiles/app.jar"); + assertThat(backingApplication2.getEnvironment()).isEqualTo(singletonMap("ENV_VAR_1", "value from parameters")); + } + + private BackingApplications createBackingApplications() { + return createBackingApplicationWithEnvironment(null); + } + + private BackingApplications createBackingApplicationWithEnvironment(Map parameters) { + BackingApplication.BackingApplicationBuilder backingApplicationBuilder = BackingApplication.builder() + .name("helloworldapp") + .path("http://myfiles/app.jar"); + if (parameters != null) { + backingApplicationBuilder.environment(parameters); + } + return BackingApplications.builder() + .backingApplication(backingApplicationBuilder.build()) + .build(); } } \ No newline at end of file diff --git a/spring-cloud-app-broker-sample/src/test/java/org.springframework.cloud.appbroker/sample/CreateInstanceWithCreationParametersComponentTest.java b/spring-cloud-app-broker-sample/src/test/java/org.springframework.cloud.appbroker/sample/CreateInstanceWithCreationParametersComponentTest.java new file mode 100644 index 0000000..9076001 --- /dev/null +++ b/spring-cloud-app-broker-sample/src/test/java/org.springframework.cloud.appbroker/sample/CreateInstanceWithCreationParametersComponentTest.java @@ -0,0 +1,81 @@ +/* + * 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.sample; + +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.appbroker.sample.fixtures.CloudControllerStubFixture; +import org.springframework.cloud.appbroker.sample.fixtures.OpenServiceBrokerApiFixture; +import org.springframework.cloud.servicebroker.model.instance.OperationState; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.TestPropertySource; + + +import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath; +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.sample.CreateInstanceWithCreationParametersComponentTest.APP_NAME; + +@TestPropertySource(properties = { + "spring.cloud.appbroker.apps[0].path=classpath:demo.jar", + "spring.cloud.appbroker.apps[0].name=" + APP_NAME +}) +class CreateInstanceWithCreationParametersComponentTest extends WiremockComponentTest { + static final String APP_NAME = "app-with-env-create-params"; + + @Autowired + private OpenServiceBrokerApiFixture brokerFixture; + + @Autowired + private CloudControllerStubFixture cloudControllerFixture; + + @Test + void shouldPushAppWithEnvironmentWhenCreateServiceEndpointCalledWithCreationParameters() { + cloudControllerFixture.stubAppDoesNotExist(APP_NAME); + cloudControllerFixture.stubPushApp(APP_NAME, + matchingJsonPath("$.environment_json[?(@.SPRING_APPLICATION_JSON =~ /.*ENV_VAR_1.*:.*value1.*/)]"), + matchingJsonPath("$.environment_json[?(@.SPRING_APPLICATION_JSON =~ /.*ENV_VAR_2.*:.*true.*/)]")); + + // given a set of parameters + Map params = new HashMap<>(); + params.put("ENV_VAR_1", "value1"); + params.put("ENV_VAR_2", true); + + // when a service instance is created + given(brokerFixture.serviceInstanceRequest(params)) + .when() + .put(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()); + } + +} diff --git a/spring-cloud-app-broker-sample/src/test/java/org.springframework.cloud.appbroker/sample/fixtures/OpenServiceBrokerApiFixture.java b/spring-cloud-app-broker-sample/src/test/java/org.springframework.cloud.appbroker/sample/fixtures/OpenServiceBrokerApiFixture.java index d426697..867cdc1 100644 --- a/spring-cloud-app-broker-sample/src/test/java/org.springframework.cloud.appbroker/sample/fixtures/OpenServiceBrokerApiFixture.java +++ b/spring-cloud-app-broker-sample/src/test/java/org.springframework.cloud.appbroker/sample/fixtures/OpenServiceBrokerApiFixture.java @@ -18,6 +18,9 @@ package org.springframework.cloud.appbroker.sample.fixtures; import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.json.JSONObject; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.test.context.TestComponent; @@ -25,7 +28,6 @@ import org.springframework.cloud.servicebroker.model.instance.OperationState; import org.springframework.context.ApplicationListener; import org.springframework.http.HttpStatus; -import java.util.concurrent.TimeUnit; import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.with; @@ -62,6 +64,18 @@ public class OpenServiceBrokerApiFixture implements ApplicationListener params) { + String stringParams = new JSONObject(params).toString(); + return serviceBrokerSpecification() + .body("{" + + " \"service_id\": \"" + serviceDefinitionId + "\"," + + " \"plan_id\": \"" + planId + "\"," + + " \"organization_guid\": \"" + ORG_ID + "\"," + + " \"space_guid\": \"" + SPACE_ID + "\"," + + " \"parameters\": " + stringParams + + "}"); + } + private RequestSpecification serviceBrokerSpecification() { return with() .baseUri("http://localhost:" + port + "/v2")