diff --git a/build.gradle b/build.gradle index df96cb0..05a2d27 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,7 @@ ext { openServiceBrokerVersion = "3.0.4.RELEASE" springCredhubVersion = "2.0.1.RELEASE" cfJavaClientVersion = "3.16.0.RELEASE" + junitJupiterVersion = "5.5.2" checkstyleVersion = "8.21" pmdVersion = "6.19.0" @@ -50,6 +51,7 @@ if (project.hasProperty("springFrameworkVersion")) { if (project.hasProperty("reactorVersion")) { ext['reactor-bom.version'] = ext.reactorVersion } +ext['junit-jupiter.version'] = ext.junitJupiterVersion // NoHttp has to be applied at the root level // so that it reads all the root files, including the gradle ones. 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 e73f263..f0d287f 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -51,6 +51,7 @@ import org.cloudfoundry.operations.spaces.SpaceSummary; import org.cloudfoundry.uaa.clients.GetClientResponse; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,6 +90,14 @@ abstract class CloudFoundryAcceptanceTest { private static final Logger LOG = LoggerFactory.getLogger(CloudFoundryAcceptanceTest.class); + private static final String BACKING_SERVICE_PLAN_ID = UUID.randomUUID().toString(); + + private static final String SERVICE_ID = UUID.randomUUID().toString(); + + private static final String PLAN_ID = UUID.randomUUID().toString(); + + private static final String BACKING_SERVICE_ID = UUID.randomUUID().toString(); + protected static final String PLAN_NAME = "standard"; protected static final String BACKING_APP_PATH = "classpath:backing-app.jar"; @@ -123,22 +132,32 @@ abstract class CloudFoundryAcceptanceTest { } @BeforeEach - void setUp(BrokerProperties brokerProperties) { + void setUp(TestInfo testInfo, BrokerProperties brokerProperties) { + List appBrokerProperties = getAppBrokerProperties(brokerProperties); + blockingSubscribe(initializeBroker(appBrokerProperties)); + } + + void setUpForBrokerUpdate(BrokerProperties brokerProperties) { + List appBrokerProperties = getAppBrokerProperties(brokerProperties); + blockingSubscribe(updateBroker(appBrokerProperties)); + } + + private List getAppBrokerProperties(BrokerProperties brokerProperties) { String[] openServiceBrokerProperties = { - "spring.cloud.openservicebroker.catalog.services[0].id=" + UUID.randomUUID().toString(), + "spring.cloud.openservicebroker.catalog.services[0].id=" + SERVICE_ID, "spring.cloud.openservicebroker.catalog.services[0].name=" + appServiceName(), "spring.cloud.openservicebroker.catalog.services[0].description=A service that deploys a backing app", "spring.cloud.openservicebroker.catalog.services[0].bindable=true", - "spring.cloud.openservicebroker.catalog.services[0].plans[0].id=" + UUID.randomUUID().toString(), + "spring.cloud.openservicebroker.catalog.services[0].plans[0].id=" + PLAN_ID, "spring.cloud.openservicebroker.catalog.services[0].plans[0].name=standard", "spring.cloud.openservicebroker.catalog.services[0].plans[0].bindable=true", "spring.cloud.openservicebroker.catalog.services[0].plans[0].description=A simple plan", "spring.cloud.openservicebroker.catalog.services[0].plans[0].free=true", - "spring.cloud.openservicebroker.catalog.services[1].id=" + UUID.randomUUID().toString(), + "spring.cloud.openservicebroker.catalog.services[1].id=" + BACKING_SERVICE_ID, "spring.cloud.openservicebroker.catalog.services[1].name=" + backingServiceName(), "spring.cloud.openservicebroker.catalog.services[1].description=A backing service that can be bound to backing apps", "spring.cloud.openservicebroker.catalog.services[1].bindable=true", - "spring.cloud.openservicebroker.catalog.services[1].plans[0].id=" + UUID.randomUUID().toString(), + "spring.cloud.openservicebroker.catalog.services[1].plans[0].id=" + BACKING_SERVICE_PLAN_ID, "spring.cloud.openservicebroker.catalog.services[1].plans[0].name=standard", "spring.cloud.openservicebroker.catalog.services[1].plans[0].bindable=true", "spring.cloud.openservicebroker.catalog.services[1].plans[0].description=A simple plan", @@ -148,8 +167,7 @@ abstract class CloudFoundryAcceptanceTest { List appBrokerProperties = new ArrayList<>(); appBrokerProperties.addAll(Arrays.asList(openServiceBrokerProperties)); appBrokerProperties.addAll(brokerProperties.getProperties()); - - blockingSubscribe(initializeBroker(appBrokerProperties)); + return appBrokerProperties; } @BeforeEach @@ -177,7 +195,7 @@ abstract class CloudFoundryAcceptanceTest { } @AfterEach - public void tearDown() { + public void tearDown(TestInfo testInfo) { blockingSubscribe(cloudFoundryService.getOrCreateDefaultOrganization() .map(OrganizationSummary::getId) .flatMap(orgId -> cloudFoundryService.getOrCreateDefaultSpace() @@ -206,6 +224,12 @@ abstract class CloudFoundryAcceptanceTest { .then(cloudFoundryService.enableServiceBrokerAccess(backingServiceName())))); } + private Mono updateBroker(List appBrokerProperties) { + return cloudFoundryService + .updateBrokerApp(testBrokerAppName(), brokerClientId(), appBrokerProperties) + .then(cloudFoundryService.updateServiceBroker(serviceBrokerName(), testBrokerAppName())); + } + private Mono cleanup(String orgId, String spaceId) { return cloudFoundryService.deleteServiceBroker(serviceBrokerName()) .then(cloudFoundryService.deleteApp(testBrokerAppName())) diff --git a/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/UpgradeInstanceAcceptanceTest.java b/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/UpgradeInstanceAcceptanceTest.java new file mode 100644 index 0000000..cade779 --- /dev/null +++ b/spring-cloud-app-broker-acceptance-tests/src/test/java/org/springframework/cloud/appbroker/acceptance/UpgradeInstanceAcceptanceTest.java @@ -0,0 +1,158 @@ +/* + * Copyright 2002-2020 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 + * + * https://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 com.jayway.jsonpath.DocumentContext; +import org.cloudfoundry.operations.applications.ApplicationSummary; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.TestMethodOrder; + +import org.springframework.beans.factory.annotation.Autowired; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +class UpgradeInstanceAcceptanceTest extends CloudFoundryAcceptanceTest { + + private static final String APP_NAME = "app-upgrade"; + + private static final int FIRST_TEST = 1; + + private static final int SECOND_TEST = 2; + + private static final String SI_NAME = "si-upgrade"; + + private static final String SUFFIX = "upgrade"; + + private static final String APP_SERVICE_NAME = "app-service-" + SUFFIX; + + private static final String BACKING_SERVICE_NAME = "backing-service-" + SUFFIX; + + @Autowired + private HealthListener healthListener; + + @Override + protected String testSuffix() { + return SUFFIX; + } + + @Override + protected String appServiceName() { + return APP_SERVICE_NAME; + } + + @Override + protected String backingServiceName() { + return BACKING_SERVICE_NAME; + } + + @Test + @Tag("first") + @Order(FIRST_TEST) + @AppBrokerTestProperties({ + "spring.cloud.appbroker.services[0].service-name=" + APP_SERVICE_NAME, + "spring.cloud.appbroker.services[0].plan-name=" + PLAN_NAME, + "spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME, + "spring.cloud.appbroker.services[0].apps[0].path=" + BACKING_APP_PATH, + "spring.cloud.appbroker.services[0].apps[0].environment.parameter1=old-config1", + "spring.cloud.appbroker.services[0].apps[0].environment.parameter2=old-config2" + }) + void createsServiceInstance() { + // when a service instance is created + createServiceInstance(SI_NAME); + + // then a backing application is deployed + Optional backingApplication = getApplicationSummary(APP_NAME); + assertThat(backingApplication).hasValueSatisfying(app -> + assertThat(app.getRunningInstances()).isEqualTo(1)); + + // and the environment variables are applied correctly + DocumentContext json = getSpringAppJson(APP_NAME); + assertThat(json.read("$.parameter1").toString()).isEqualTo("old-config1"); + assertThat(json.read("$.parameter2").toString()).isEqualTo("old-config2"); + + String path = backingApplication.get().getUrls().get(0); + healthListener.start(path); + } + + @Test + @Order(SECOND_TEST) + @Tag("last") + @AppBrokerTestProperties({ + "spring.cloud.appbroker.services[0].service-name=" + APP_SERVICE_NAME, + "spring.cloud.appbroker.services[0].plan-name=" + PLAN_NAME, + "spring.cloud.appbroker.services[0].apps[0].name=" + APP_NAME, + "spring.cloud.appbroker.services[0].apps[0].path=" + BACKING_APP_PATH, + "spring.cloud.appbroker.services[0].apps[0].environment.parameter1=new-config1", + "spring.cloud.appbroker.services[0].apps[0].environment.parameter3=new-config3" + }) + void upgradesTheServiceInstanceWithNewBackingServiceAndEnvironmentVariables() { + // when the service instance is updated with a new service + updateServiceInstance(SI_NAME, Collections.singletonMap("upgrade", true)); + + // then the backing application was updated with zero downtime + healthListener.stop(); + assertThat(healthListener.getFailures()).isEqualTo(0); + assertThat(healthListener.getSuccesses()).isGreaterThan(0); + + // then a backing application is re-deployed + Optional updatedBackingApplication = getApplicationSummary(APP_NAME); + assertThat(updatedBackingApplication).hasValueSatisfying(app -> + assertThat(app.getRunningInstances()).isEqualTo(1)); + + // the backing application is updated with the new parameters + DocumentContext json = getSpringAppJson(APP_NAME); + assertThat(json.read("$.parameter1").toString()).isEqualTo("new-config1"); + assertThat(json.read("$.parameter3").toString()).isEqualTo("new-config3"); + assertThat(json.jsonString()).doesNotContain("parameter2"); + + // when the service instance is deleted + deleteServiceInstance(SI_NAME); + + // then the backing application is deleted + Optional backingApplicationAfterDeletion = getApplicationSummary(APP_NAME); + assertThat(backingApplicationAfterDeletion).isEmpty(); + } + + @Override + @BeforeEach + void setUp(TestInfo testInfo, BrokerProperties brokerProperties) { + if (testInfo.getTags().contains("first")) { + super.setUp(testInfo, brokerProperties); + } + else { + setUpForBrokerUpdate(brokerProperties); + } + } + + @Override + @AfterEach + public void tearDown(TestInfo testInfo) { + if (testInfo.getTags().contains("last")) { + super.tearDown(testInfo); + } + } +} 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 2422be7..4be4614 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 @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import org.cloudfoundry.client.CloudFoundryClient; +import org.cloudfoundry.client.v2.applications.UpdateApplicationRequest; import org.cloudfoundry.client.v2.organizations.AssociateOrganizationManagerRequest; import org.cloudfoundry.client.v2.organizations.AssociateOrganizationManagerResponse; import org.cloudfoundry.client.v2.organizations.AssociateOrganizationUserRequest; @@ -43,6 +44,7 @@ import org.cloudfoundry.operations.applications.DeleteApplicationRequest; import org.cloudfoundry.operations.applications.GetApplicationEnvironmentsRequest; import org.cloudfoundry.operations.applications.GetApplicationRequest; import org.cloudfoundry.operations.applications.PushApplicationManifestRequest; +import org.cloudfoundry.operations.applications.RestartApplicationRequest; import org.cloudfoundry.operations.applications.StopApplicationRequest; import org.cloudfoundry.operations.domains.CreateDomainRequest; import org.cloudfoundry.operations.domains.Domain; @@ -52,6 +54,7 @@ import org.cloudfoundry.operations.organizations.Organizations; import org.cloudfoundry.operations.serviceadmin.CreateServiceBrokerRequest; import org.cloudfoundry.operations.serviceadmin.DeleteServiceBrokerRequest; import org.cloudfoundry.operations.serviceadmin.EnableServiceAccessRequest; +import org.cloudfoundry.operations.serviceadmin.UpdateServiceBrokerRequest; import org.cloudfoundry.operations.services.CreateServiceInstanceRequest; import org.cloudfoundry.operations.services.DeleteServiceInstanceRequest; import org.cloudfoundry.operations.services.GetServiceInstanceRequest; @@ -114,6 +117,19 @@ public class CloudFoundryService { .doOnError(error -> LOGGER.error("Error creating service broker " + brokerName + ": " + error))); } + public Mono updateServiceBroker(String brokerName, String testBrokerAppName) { + return getApplicationRoute(testBrokerAppName) + .flatMap(url -> cloudFoundryOperations.serviceAdmin() + .update(UpdateServiceBrokerRequest.builder() + .name(brokerName) + .username("user") + .password("password") + .url(url) + .build()) + .doOnSuccess(item -> LOGGER.info("Updating service broker " + brokerName)) + .doOnError(error -> LOGGER.error("Error updating service broker " + brokerName + ": " + error))); + } + public Mono getApplicationRoute(String appName) { return cloudFoundryOperations.applications() .get(GetApplicationRequest.builder() @@ -132,7 +148,7 @@ public class CloudFoundryService { return cloudFoundryOperations.applications() .pushManifest(PushApplicationManifestRequest.builder() .manifest(ApplicationManifest.builder() - .putAllEnvironmentVariables(appBrokerDeployerEnvironmentVariables(brokerClientId)) + .environmentVariables(appBrokerDeployerEnvironmentVariables(brokerClientId)) .putAllEnvironmentVariables(propertiesToEnvironment(appBrokerProperties)) .name(appName) .path(appPath) @@ -143,6 +159,29 @@ public class CloudFoundryService { .doOnError(error -> LOGGER.error("Error pushing broker app " + appName + ": " + error)); } + public Mono updateBrokerApp(String appName, String brokerClientId, List appBrokerProperties) { + return cloudFoundryOperations.applications() + .get(GetApplicationRequest.builder().name(appName).build()) + .map(ApplicationDetail::getId) + .flatMap(applicationId -> + cloudFoundryClient + .applicationsV2() + .update(UpdateApplicationRequest + .builder() + .applicationId(applicationId) + .putAllEnvironmentJsons(appBrokerDeployerEnvironmentVariables(brokerClientId)) + .putAllEnvironmentJsons(propertiesToEnvironment(appBrokerProperties)) + .name(appName) + .memory(1024) + .build()) + .thenReturn(applicationId)) + .then(cloudFoundryOperations.applications() + .restart(RestartApplicationRequest.builder().name(appName).build())) + .doOnSuccess(item -> LOGGER.info("Updated broker app " + appName)) + .doOnError(error -> LOGGER.error("Error updating broker app " + appName + ": " + error)) + .then(); + } + public Mono deleteApp(String appName) { return cloudFoundryOperations.applications() .delete(DeleteApplicationRequest.builder() diff --git a/spring-cloud-app-broker-core/build.gradle b/spring-cloud-app-broker-core/build.gradle index 5b8aad9..687396c 100644 --- a/spring-cloud-app-broker-core/build.gradle +++ b/spring-cloud-app-broker-core/build.gradle @@ -17,7 +17,6 @@ description = "Spring Cloud App Broker Core" ext { - junitJupiterVersion = "5.5.2" assertjVersion = "3.13.2" mockitoVersion = "3.0.0" } diff --git a/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployer.java b/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployer.java index 919ea5c..86b5f92 100644 --- a/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployer.java +++ b/spring-cloud-app-broker-deployer-cloudfoundry/src/main/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployer.java @@ -208,6 +208,7 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware .doOnError(e -> LOG.warn(String.format("Error getting application %s: %s", name, e.getMessage()))) .map(ApplicationDetail::getId) .flatMap(applicationId -> associateHostName(applicationId, request.getProperties())) + .flatMap(applicationId -> updateEnvironment(request, applicationId)) .flatMap(applicationId -> Mono.zip(Mono.just(applicationId), upgradeApplication(request, applicationId))) .flatMap(tuple2 -> { @@ -411,11 +412,15 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware .map(Package::getId)); } + return getPackageForApplication(applicationId); + } + + private Mono updateEnvironment(UpdateApplicationRequest request, String applicationId) { final Map environmentVariables = getApplicationEnvironment(request.getProperties(), request.getEnvironment(), request.getServiceInstanceId()); return updateApplicationEnvironment(applicationId, environmentVariables, request.getProperties()) - .flatMap(a -> getPackageForApplication(applicationId)); + .thenReturn(applicationId); } private Mono getPackageForApplication(String applicationId) { diff --git a/spring-cloud-app-broker-deployer-cloudfoundry/src/test/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployerUpdateApplicationTest.java b/spring-cloud-app-broker-deployer-cloudfoundry/src/test/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployerUpdateApplicationTest.java index 9da7ef3..e1fcb56 100644 --- a/spring-cloud-app-broker-deployer-cloudfoundry/src/test/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployerUpdateApplicationTest.java +++ b/spring-cloud-app-broker-deployer-cloudfoundry/src/test/java/org/springframework/cloud/appbroker/deployer/cloudfoundry/CloudFoundryAppDeployerUpdateApplicationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -76,17 +76,21 @@ import org.springframework.cloud.appbroker.deployer.UpdateApplicationRequest; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.ResourceLoader; +import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; +import static org.springframework.cloud.appbroker.deployer.DeploymentProperties.TARGET_PROPERTY_KEY; @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) class CloudFoundryAppDeployerUpdateApplicationTest { + private static final String APP_ID = "app-id"; + private static final String APP_NAME = "test-app"; private static final String APP_PATH = "test.jar"; @@ -247,6 +251,27 @@ class CloudFoundryAppDeployerUpdateApplicationTest { .verifyComplete(); } + @Test + void updateAppWithTarget() { + given(applicationsV2.update(any())) + .willReturn(Mono.just(UpdateApplicationResponse.builder() + .build())); + + Map properties = singletonMap(TARGET_PROPERTY_KEY, "service-instance-id"); + UpdateApplicationRequest request = UpdateApplicationRequest.builder() + .name(APP_NAME) + .path(APP_PATH) + .properties(properties) + .build(); + + StepVerifier.create(appDeployer.update(request)) + .assertNext(response -> assertThat(response.getName()).isEqualTo(APP_NAME)) + .verifyComplete(); + + then(operationsUtils).should().getOperations(properties); + then(operationsUtils).shouldHaveNoMoreInteractions(); + } + @Test void updateAppProperties() { ArgumentCaptor updateApplicationRequestCaptor = @@ -280,22 +305,56 @@ class CloudFoundryAppDeployerUpdateApplicationTest { assertThat(updateApplicationRequest.getMemory()).isEqualTo(1024); } + @Test + void updateAppEnvironment() { + ArgumentCaptor updateApplicationRequestCaptor = + ArgumentCaptor.forClass(org.cloudfoundry.client.v2.applications.UpdateApplicationRequest.class); + + given(applicationsV2.update(updateApplicationRequestCaptor.capture())) + .willReturn(Mono.just(UpdateApplicationResponse.builder() + .build())); + + UpdateApplicationRequest request = + UpdateApplicationRequest + .builder() + .name(APP_NAME) + .path(APP_PATH) + .environment("ENV_VAR", "test-env") + .build(); + + StepVerifier.create(appDeployer.update(request)) + .assertNext(response -> assertThat(response.getName()).isEqualTo(APP_NAME)) + .verifyComplete(); + + assertThat(updateApplicationRequestCaptor.getValue().getEnvironmentJsons().get("SPRING_APPLICATION_JSON")) + .isEqualTo("{\"ENV_VAR\":\"test-env\"}"); + } + @Test void updateAppWithUpgrade() { Map properties = new HashMap<>(); properties.put("upgrade", "true"); + ArgumentCaptor updateApplicationRequestCaptor = + ArgumentCaptor.forClass(org.cloudfoundry.client.v2.applications.UpdateApplicationRequest.class); + + given(applicationsV2.update(any())).willReturn(Mono.just(UpdateApplicationResponse.builder().build())); UpdateApplicationRequest request = UpdateApplicationRequest.builder() .name(APP_NAME) .path(APP_PATH) .properties(properties) + .property("upgrade", "true") + .environment("TEST_KEY", "TEST_VALUE") .build(); StepVerifier.create(appDeployer.update(request)) .assertNext(response -> assertThat(response.getName()).isEqualTo(APP_NAME)) .verifyComplete(); - then(applicationsV2).shouldHaveZeroInteractions(); + then(applicationsV2).should().update(updateApplicationRequestCaptor.capture()); + assertThat(updateApplicationRequestCaptor.getValue().getEnvironmentJsons().get("SPRING_APPLICATION_JSON")) + .isEqualTo("{\"TEST_KEY\":\"TEST_VALUE\"}"); + then(applicationsV2).shouldHaveNoMoreInteractions(); } @Test @@ -342,7 +401,7 @@ class CloudFoundryAppDeployerUpdateApplicationTest { .host("my.host") .build()); then(applicationsV2).should().associateRoute(AssociateApplicationRouteRequest.builder() - .applicationId("app-id") + .applicationId(APP_ID) .routeId("route-id") .build()); } @@ -376,9 +435,9 @@ class CloudFoundryAppDeployerUpdateApplicationTest { .assertNext(response -> assertThat(response.getName()).isEqualTo(APP_NAME)) .verifyComplete(); - verifyRouteCreatedAndMapped("myDomainComId", "my.host", "space-id", "app-id"); - verifyRouteCreatedAndMapped("myDomainInternalId", "my.host", "space-id", "app-id"); - verifyRouteCreatedAndMapped("myDomainDefaultId", "my.host", "space-id", "app-id"); + verifyRouteCreatedAndMapped("myDomainComId", "my.host", "space-id", APP_ID); + verifyRouteCreatedAndMapped("myDomainInternalId", "my.host", "space-id", APP_ID); + verifyRouteCreatedAndMapped("myDomainDefaultId", "my.host", "space-id", APP_ID); } @Test @@ -409,8 +468,8 @@ class CloudFoundryAppDeployerUpdateApplicationTest { .assertNext(response -> assertThat(response.getName()).isEqualTo(APP_NAME)) .verifyComplete(); - verifyRouteCreatedAndMapped("myDomainInternalId", "my.host", "space-id", "app-id"); - verifyRouteCreatedAndMapped("myDomainDefaultId", "my.host", "space-id", "app-id"); + verifyRouteCreatedAndMapped("myDomainInternalId", "my.host", "space-id", APP_ID); + verifyRouteCreatedAndMapped("myDomainDefaultId", "my.host", "space-id", APP_ID); } @Test @@ -457,7 +516,7 @@ class CloudFoundryAppDeployerUpdateApplicationTest { .host("my.host") .build()); then(applicationsV2).should().associateRoute(AssociateApplicationRouteRequest.builder() - .applicationId("app-id") + .applicationId(APP_ID) .routeId("route-id") .build()); } @@ -508,7 +567,7 @@ class CloudFoundryAppDeployerUpdateApplicationTest { .build()); then(applicationsV2).should().associateRoute(AssociateApplicationRouteRequest .builder() - .applicationId("app-id") + .applicationId(APP_ID) .routeId("route-id") .build()); } @@ -572,12 +631,12 @@ class CloudFoundryAppDeployerUpdateApplicationTest { private ApplicationDetail createApplicationDetail() { return ApplicationDetail .builder() - .id("app-id") + .id(APP_ID) .stack("") .diskQuota(512) .instances(1) .memoryLimit(512) - .name("app") + .name(APP_NAME) .requestedState("STARTED") .runningInstances(1) .build(); diff --git a/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/UpdateInstanceWithUpgradeComponentTest.java b/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/UpdateInstanceWithUpgradeComponentTest.java index 28fc8e7..1a9ad69 100644 --- a/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/UpdateInstanceWithUpgradeComponentTest.java +++ b/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/UpdateInstanceWithUpgradeComponentTest.java @@ -38,6 +38,7 @@ import static org.springframework.cloud.appbroker.integration.UpdateInstanceWith "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_1, + "spring.cloud.appbroker.services[0].apps[0].environment.ENV_VAR=testEnv", "spring.cloud.appbroker.services[0].apps[0].parameters-transformers[0].name=PropertyMapping", "spring.cloud.appbroker.services[0].apps[0].parameters-transformers[0].args.include=upgrade" }) diff --git a/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/fixtures/CloudControllerStubFixture.java b/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/fixtures/CloudControllerStubFixture.java index 3aa6169..8b65a6d 100644 --- a/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/fixtures/CloudControllerStubFixture.java +++ b/spring-cloud-app-broker-integration-tests/src/test/java/org/springframework/cloud/appbroker/integration/fixtures/CloudControllerStubFixture.java @@ -219,6 +219,7 @@ public class CloudControllerStubFixture extends WiremockStubFixture { } public void stubUpdateAppWithUpgrade(final String appName) { + stubUpdateEnvironment(appName); stubCreatePackage(appName); stubCreateBuild(appName); stubCreateDeployment(appName);