diff --git a/build.gradle b/build.gradle index ed82c0a..2e6955f 100644 --- a/build.gradle +++ b/build.gradle @@ -156,6 +156,20 @@ configure(allprojects) { "${result.skippedTestCount} skipped" } } + + // print failed tests after the execution + def failedTests = [] + + afterTest { test, result -> + if (result.resultType == TestResult.ResultType.FAILURE) { + failedTests << test + } + } + + afterSuite { + failedTests.each { test -> println "FAILED test: ${test.className} > ${test.name}" } + } + } pmd { 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 94dc896..d80a31f 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 @@ -19,6 +19,7 @@ package org.springframework.cloud.appbroker.acceptance; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.CountDownLatch; @@ -117,10 +118,18 @@ class CloudFoundryAcceptanceTest { .blockOptional(); } + Optional getApplicationSummaryByNameAndSpace(String appName, String space) { + return cloudFoundryService.getApplicationSummaryByName(appName, space).blockOptional(); + } + ApplicationEnvironments getApplicationEnvironmentByName(String appName) { return cloudFoundryService.getApplicationEnvironmentByAppName(appName).block(); } + List getSpaces() { + return cloudFoundryService.getSpaces().block(); + } + private Path getSampleBrokerAppPath() { return Paths.get(acceptanceTestProperties.getSampleBrokerAppPath(), ""); } diff --git a/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceWithTargetAcceptanceTest.java b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceWithTargetAcceptanceTest.java new file mode 100644 index 0000000..ad82f40 --- /dev/null +++ b/spring-cloud-app-broker-acceptance-tests/src/test/java/org.springframework.cloud.appbroker.acceptance/CreateInstanceWithTargetAcceptanceTest.java @@ -0,0 +1,66 @@ +/* + * 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.List; +import java.util.Optional; + +import org.cloudfoundry.operations.applications.ApplicationSummary; +import org.cloudfoundry.operations.services.ServiceInstanceSummary; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class CreateInstanceWithTargetAcceptanceTest extends CloudFoundryAcceptanceTest { + + private static final String BROKER_SAMPLE_APP_CREATE_WITH_TARGET = "app-with-target"; + + @Test + @AppBrokerTestProperties({ + "spring.cloud.appbroker.services[0].service-name=example", + "spring.cloud.appbroker.services[0].plan-name=standard", + "spring.cloud.appbroker.services[0].apps[0].name=" + BROKER_SAMPLE_APP_CREATE_WITH_TARGET, + "spring.cloud.appbroker.services[0].apps[0].path=classpath:demo.jar", + "spring.cloud.appbroker.services[0].apps[0].target.name=SpacePerServiceInstance" + }) + void shouldPushAppWithTargetWhenCreateServiceCalled() { + // when a service instance is created + createServiceInstance(); + Optional serviceInstance = getServiceInstance(); + assertThat(serviceInstance).isNotEmpty(); + + // then a backing application is deployed in a space named as the service instance id + String serviceInstanceId = serviceInstance.orElseThrow(RuntimeException::new).getId(); + String spaceName = serviceInstanceId; + Optional backingApplication = + getApplicationSummaryByNameAndSpace(BROKER_SAMPLE_APP_CREATE_WITH_TARGET, spaceName); + assertThat(backingApplication).isNotEmpty(); + + // and has its route with the service instance id appended to it + ApplicationSummary applicationSummary = backingApplication.orElseThrow(RuntimeException::new); + assertThat(applicationSummary.getUrls()).isNotEmpty(); + assertThat(applicationSummary.getUrls().get(0)).startsWith(BROKER_SAMPLE_APP_CREATE_WITH_TARGET + "-" + spaceName); + + // when the service instance is deleted + deleteServiceInstance(); + + // then the space is deleted + List spaces = getSpaces(); + assertThat(spaces).doesNotContain(spaceName); + } + +} \ 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 cacf860..1a2bce0 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 @@ -24,6 +24,7 @@ import java.util.Map; import org.cloudfoundry.client.CloudFoundryClient; import org.cloudfoundry.operations.CloudFoundryOperations; +import org.cloudfoundry.operations.DefaultCloudFoundryOperations; import org.cloudfoundry.operations.applications.ApplicationDetail; import org.cloudfoundry.operations.applications.ApplicationEnvironments; import org.cloudfoundry.operations.applications.ApplicationManifest; @@ -175,10 +176,10 @@ public class CloudFoundryService { cloudFoundryOperations .services() .updateInstance(UpdateServiceInstanceRequest - .builder() - .serviceInstanceName(serviceInstanceName) - .parameters(parameters) - .build())); + .builder() + .serviceInstanceName(serviceInstanceName) + .parameters(parameters) + .build())); } public Mono getServiceInstance(String serviceInstanceName) { @@ -191,6 +192,23 @@ public class CloudFoundryService { cloudFoundryOperations.applications().list().collectList()); } + public Mono> getSpaces() { + return this.cloudFoundryOperations.spaces().list().map(SpaceSummary::getName).collectList(); + } + + public Mono getApplicationSummaryByName(String appName, String space) { + final String defaultOrg = cloudFoundryProperties.getDefaultOrg(); + return loggingFlux(DefaultCloudFoundryOperations.builder() + .cloudFoundryClient(cloudFoundryClient) + .organization(defaultOrg) + .space(space) + .build() + .applications() + .list() + .filter(applicationSummary -> applicationSummary.getName().equals(appName)) + ).next(); + } + public Mono getApplicationEnvironmentByAppName(String appName) { return loggingMono( cloudFoundryOperations @@ -303,4 +321,11 @@ public class CloudFoundryService { } } + private Flux loggingFlux(Flux publisher) { + if (LOGGER.isDebugEnabled()) { + return publisher.log(); + } else { + return publisher; + } + } } diff --git a/spring-cloud-app-broker-autoconfigure/src/main/java/org/springframework/cloud/appbroker/autoconfigure/AppBrokerAutoConfiguration.java b/spring-cloud-app-broker-autoconfigure/src/main/java/org/springframework/cloud/appbroker/autoconfigure/AppBrokerAutoConfiguration.java index bf96fd6..3a893b1 100644 --- a/spring-cloud-app-broker-autoconfigure/src/main/java/org/springframework/cloud/appbroker/autoconfigure/AppBrokerAutoConfiguration.java +++ b/spring-cloud-app-broker-autoconfigure/src/main/java/org/springframework/cloud/appbroker/autoconfigure/AppBrokerAutoConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.cloud.appbroker.autoconfigure; +import java.util.List; + import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -25,28 +27,29 @@ import org.springframework.cloud.appbroker.deployer.BackingAppDeploymentService; import org.springframework.cloud.appbroker.deployer.BrokeredServices; import org.springframework.cloud.appbroker.deployer.DeployerClient; import org.springframework.cloud.appbroker.extensions.credentials.CredentialGenerator; -import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService; import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderFactory; +import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService; import org.springframework.cloud.appbroker.extensions.credentials.SimpleCredentialGenerator; import org.springframework.cloud.appbroker.extensions.credentials.SpringSecurityBasicAuthCredentialProviderFactory; import org.springframework.cloud.appbroker.extensions.parameters.EnvironmentMappingParametersTransformerFactory; import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService; import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformerFactory; import org.springframework.cloud.appbroker.extensions.parameters.PropertyMappingParametersTransformerFactory; +import org.springframework.cloud.appbroker.extensions.targets.SpacePerServiceInstance; +import org.springframework.cloud.appbroker.extensions.targets.TargetFactory; +import org.springframework.cloud.appbroker.extensions.targets.TargetService; +import org.springframework.cloud.appbroker.service.CreateServiceInstanceWorkflow; +import org.springframework.cloud.appbroker.service.DeleteServiceInstanceWorkflow; import org.springframework.cloud.appbroker.service.UpdateServiceInstanceWorkflow; import org.springframework.cloud.appbroker.service.WorkflowServiceInstanceService; import org.springframework.cloud.appbroker.state.InMemoryServiceInstanceStateRepository; import org.springframework.cloud.appbroker.state.ServiceInstanceStateRepository; import org.springframework.cloud.appbroker.workflow.instance.AppDeploymentCreateServiceInstanceWorkflow; -import org.springframework.cloud.appbroker.service.CreateServiceInstanceWorkflow; import org.springframework.cloud.appbroker.workflow.instance.AppDeploymentDeleteServiceInstanceWorkflow; -import org.springframework.cloud.appbroker.service.DeleteServiceInstanceWorkflow; import org.springframework.cloud.appbroker.workflow.instance.AppDeploymentUpdateServiceInstanceWorkflow; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.List; - @Configuration @AutoConfigureAfter(AppDeployerAutoConfiguration.class) @ConditionalOnBean(AppDeployer.class) @@ -100,35 +103,45 @@ public class AppBrokerAutoConfiguration { public SpringSecurityBasicAuthCredentialProviderFactory springSecurityBasicAuthCredentialProvider(CredentialGenerator credentialGenerator) { return new SpringSecurityBasicAuthCredentialProviderFactory(credentialGenerator); } - + @Bean public CredentialProviderService credentialProviderService(List> providers) { return new CredentialProviderService(providers); } + @Bean + public SpacePerServiceInstance targetFactory() { + return new SpacePerServiceInstance(); + } + + @Bean + public TargetService targetService(List> targets) { + return new TargetService(targets); + } + @Bean public CreateServiceInstanceWorkflow appDeploymentCreateServiceInstanceWorkflow(BrokeredServices brokeredServices, BackingAppDeploymentService backingAppDeploymentService, ParametersTransformationService parametersTransformationService, - CredentialProviderService credentialProviderService) { - return new AppDeploymentCreateServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService, - parametersTransformationService, credentialProviderService); + CredentialProviderService credentialProviderService, + TargetService targetService) { + return new AppDeploymentCreateServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService, parametersTransformationService, credentialProviderService, targetService); } @Bean public DeleteServiceInstanceWorkflow appDeploymentDeleteServiceInstanceWorkflow(BrokeredServices brokeredServices, BackingAppDeploymentService backingAppDeploymentService, - CredentialProviderService credentialProviderService) { - return new AppDeploymentDeleteServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService, - credentialProviderService); + CredentialProviderService credentialProviderService, + TargetService targetService) { + return new AppDeploymentDeleteServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService, credentialProviderService, targetService); } @Bean - public UpdateServiceInstanceWorkflow appDeploymentUpdateServiceInstanceWorkflow(BrokeredServices brokeredServices, - BackingAppDeploymentService backingAppDeploymentService, - ParametersTransformationService parametersTransformationService) { - return new AppDeploymentUpdateServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService, - parametersTransformationService); + public UpdateServiceInstanceWorkflow updateServiceInstanceWorkflow(BrokeredServices brokeredServices, + BackingAppDeploymentService backingAppDeploymentService, + ParametersTransformationService parametersTransformationService, + TargetService targetService) { + return new AppDeploymentUpdateServiceInstanceWorkflow(brokeredServices, backingAppDeploymentService, parametersTransformationService, targetService); } @Bean diff --git a/spring-cloud-app-broker-autoconfigure/src/main/java/org/springframework/cloud/appbroker/autoconfigure/AppDeployerAutoConfiguration.java b/spring-cloud-app-broker-autoconfigure/src/main/java/org/springframework/cloud/appbroker/autoconfigure/AppDeployerAutoConfiguration.java index 1680efa..c5a5c51 100644 --- a/spring-cloud-app-broker-autoconfigure/src/main/java/org/springframework/cloud/appbroker/autoconfigure/AppDeployerAutoConfiguration.java +++ b/spring-cloud-app-broker-autoconfigure/src/main/java/org/springframework/cloud/appbroker/autoconfigure/AppDeployerAutoConfiguration.java @@ -34,9 +34,12 @@ public class AppDeployerAutoConfiguration { @Bean @ConditionalOnBean(CloudFoundryOperations.class) public AppDeployer cloudFoundryAppDeployer(CloudFoundryOperations cloudFoundryOperations, + CloudFoundryProperties cloudFoundryProperties, ResourceLoader resourceLoader) { CloudFoundryDeploymentProperties cloudFoundryDeploymentProperties = new CloudFoundryDeploymentProperties(); - return new CloudFoundryAppDeployer(cloudFoundryDeploymentProperties, - cloudFoundryOperations, resourceLoader); + + cloudFoundryDeploymentProperties.setDefaultOrg(cloudFoundryProperties.getDefaultOrg()); + cloudFoundryDeploymentProperties.setUsername(cloudFoundryProperties.getUsername()); + return new CloudFoundryAppDeployer(cloudFoundryDeploymentProperties, cloudFoundryOperations, resourceLoader); } } diff --git a/spring-cloud-app-broker-autoconfigure/src/test/java/org/springframework/cloud/appbroker/autoconfigure/AppBrokerAutoConfigurationTest.java b/spring-cloud-app-broker-autoconfigure/src/test/java/org/springframework/cloud/appbroker/autoconfigure/AppBrokerAutoConfigurationTest.java index d890893..5814e6b 100644 --- a/spring-cloud-app-broker-autoconfigure/src/test/java/org/springframework/cloud/appbroker/autoconfigure/AppBrokerAutoConfigurationTest.java +++ b/spring-cloud-app-broker-autoconfigure/src/test/java/org/springframework/cloud/appbroker/autoconfigure/AppBrokerAutoConfigurationTest.java @@ -25,6 +25,7 @@ import org.springframework.cloud.appbroker.deployer.BackingApplications; import org.springframework.cloud.appbroker.deployer.BrokeredServices; import org.springframework.cloud.appbroker.deployer.DeployerClient; import org.springframework.cloud.appbroker.extensions.credentials.CredentialProviderService; +import org.springframework.cloud.appbroker.extensions.targets.TargetService; import org.springframework.cloud.appbroker.service.WorkflowServiceInstanceService; import org.springframework.cloud.appbroker.workflow.instance.AppDeploymentCreateServiceInstanceWorkflow; import org.springframework.cloud.appbroker.extensions.parameters.ParametersTransformationService; @@ -95,6 +96,7 @@ class AppBrokerAutoConfigurationTest { assertThat(context).hasSingleBean(BackingAppDeploymentService.class); assertThat(context).hasSingleBean(ParametersTransformationService.class); assertThat(context).hasSingleBean(CredentialProviderService.class); + assertThat(context).hasSingleBean(TargetService.class); assertThat(context).hasSingleBean(WorkflowServiceInstanceService.class); assertThat(context).hasSingleBean(AppDeploymentCreateServiceInstanceWorkflow.class); assertThat(context).hasSingleBean(AppDeploymentDeleteServiceInstanceWorkflow.class); diff --git a/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/deployer/BackingApplication.java b/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/deployer/BackingApplication.java index fcad010..ccdf18a 100644 --- a/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/deployer/BackingApplication.java +++ b/spring-cloud-app-broker-core/src/main/java/org/springframework/cloud/appbroker/deployer/BackingApplication.java @@ -26,7 +26,7 @@ import java.util.Objects; public class BackingApplication { private static final String VALUE_HIDDEN = "