org.cloudfoundry.client.ApplicationsTest.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.client.ApplicationsTest.java

Source

/*
 * Copyright 2013-2016 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.cloudfoundry.client;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.cloudfoundry.AbstractIntegrationTest;
import org.cloudfoundry.client.v2.applications.ApplicationEntity;
import org.cloudfoundry.client.v2.applications.ApplicationEnvironmentRequest;
import org.cloudfoundry.client.v2.applications.ApplicationInstancesRequest;
import org.cloudfoundry.client.v2.applications.ApplicationStatisticsRequest;
import org.cloudfoundry.client.v2.applications.AssociateApplicationRouteRequest;
import org.cloudfoundry.client.v2.applications.CopyApplicationRequest;
import org.cloudfoundry.client.v2.applications.CreateApplicationRequest;
import org.cloudfoundry.client.v2.applications.DeleteApplicationRequest;
import org.cloudfoundry.client.v2.applications.DownloadApplicationDropletRequest;
import org.cloudfoundry.client.v2.applications.DownloadApplicationRequest;
import org.cloudfoundry.client.v2.applications.GetApplicationRequest;
import org.cloudfoundry.client.v2.applications.ListApplicationRoutesRequest;
import org.cloudfoundry.client.v2.applications.ListApplicationsRequest;
import org.cloudfoundry.client.v2.applications.RemoveApplicationRouteRequest;
import org.cloudfoundry.client.v2.applications.RestageApplicationRequest;
import org.cloudfoundry.client.v2.applications.SummaryApplicationRequest;
import org.cloudfoundry.client.v2.applications.SummaryApplicationResponse;
import org.cloudfoundry.client.v2.applications.TerminateApplicationInstanceRequest;
import org.cloudfoundry.client.v2.applications.UpdateApplicationRequest;
import org.cloudfoundry.client.v2.applications.UploadApplicationRequest;
import org.cloudfoundry.client.v2.domains.CreateDomainRequest;
import org.cloudfoundry.client.v2.routes.CreateRouteRequest;
import org.cloudfoundry.client.v2.routes.CreateRouteResponse;
import org.cloudfoundry.util.DelayUtils;
import org.cloudfoundry.util.JobUtils;
import org.cloudfoundry.util.OperationUtils;
import org.cloudfoundry.util.PaginationUtils;
import org.cloudfoundry.util.ResourceUtils;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.tuple.Tuple2;
import reactor.core.util.Exceptions;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.Duration;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipFile;

import static org.cloudfoundry.util.tuple.TupleUtils.consumer;
import static org.cloudfoundry.util.tuple.TupleUtils.function;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public final class ApplicationsTest extends AbstractIntegrationTest {

    @Autowired
    private CloudFoundryClient cloudFoundryClient;

    @Autowired
    private Mono<String> organizationId;

    @Autowired
    private Mono<String> spaceId;

    @Autowired
    private Mono<String> stackId;

    @Test
    public void associateRoute() {
        String applicationName = getApplicationName();
        String domainName = getDomainName();

        Mono.when(this.organizationId, this.spaceId).then(function((organizationId, spaceId) -> {
            return Mono.when(Mono.just(organizationId), Mono.just(spaceId),
                    createApplicationId(this.cloudFoundryClient, spaceId, applicationName));
        })).then(function((organizationId, spaceId,
                applicationId) -> createApplicationRoute(this.cloudFoundryClient, organizationId, spaceId,
                        domainName, applicationId).map(response -> applicationId)))
                .then(applicationId -> this.cloudFoundryClient.applicationsV2()
                        .listRoutes(ListApplicationRoutesRequest.builder().applicationId(applicationId).build())
                        .map(ResourceUtils::getResources))
                .subscribe(testSubscriber().assertCount(1));
    }

    @Test
    public void copy() {
        String applicationName = getApplicationName();
        String copyApplicationName = getApplicationName();

        this.spaceId
                .then(spaceId -> Mono.just(spaceId)
                        .and(createApplicationId(this.cloudFoundryClient, spaceId, applicationName)))
                .then(function((spaceId, applicationId) -> Mono.just(applicationId)
                        .and(this.cloudFoundryClient.applicationsV2()
                                .create(CreateApplicationRequest.builder().name(copyApplicationName)
                                        .spaceId(spaceId).build())
                                .map(ResourceUtils::getId))))
                .then(function((sourceId, targetId) -> this.cloudFoundryClient.applicationsV2()
                        .copy(CopyApplicationRequest.builder().applicationId(targetId).sourceApplicationId(sourceId)
                                .build())
                        .map(ResourceUtils::getId)))
                .flatMap(targetId -> PaginationUtils.requestResources(page -> this.cloudFoundryClient
                        .applicationsV2().list(ListApplicationsRequest.builder().page(page).build())))
                .filter(r -> {
                    String name = ResourceUtils.getEntity(r).getName();
                    return applicationName.equals(name) || copyApplicationName.equals(name);
                }).subscribe(testSubscriber().assertCount(2));
    }

    @Test
    public void create() {
        String applicationName = getApplicationName();

        this.spaceId
                .then(spaceId -> Mono.just(spaceId)
                        .and(this.cloudFoundryClient.applicationsV2()
                                .create(CreateApplicationRequest.builder().name(applicationName).spaceId(spaceId)
                                        .build())
                                .map(ResourceUtils::getEntity)))
                .subscribe(this.<Tuple2<String, ApplicationEntity>>testSubscriber()
                        .assertThat(consumer((spaceId, entity) -> {
                            assertEquals(spaceId, entity.getSpaceId());
                            assertEquals(applicationName, entity.getName());
                        })));
    }

    @Test
    public void delete() {
        String applicationName = getApplicationName();

        this.spaceId.then(spaceId -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName))
                .then(applicationId -> this.cloudFoundryClient.applicationsV2()
                        .delete(DeleteApplicationRequest.builder().applicationId(applicationId).build()))

                .subscribe(testSubscriber());
    }

    @Test
    public void download() throws IOException {
        String applicationName = getApplicationName();

        this.spaceId.then(spaceId -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName))
                .then(applicationId -> uploadApplication(this.cloudFoundryClient, applicationId))
                .flatMap(applicationId -> this.cloudFoundryClient.applicationsV2()
                        .download(DownloadApplicationRequest.builder().applicationId(applicationId).build()))
                .reduce(new ByteArrayOutputStream(), ApplicationsTest::collectIntoByteArrayInputStream)
                .map(ByteArrayOutputStream::toByteArray).map(bytes -> {
                    try {
                        File tempFile = File.createTempFile("downloadedFile", "zip");
                        new FileOutputStream(tempFile).write(bytes);
                        return new ZipFile(tempFile).size();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }).subscribe(testSubscriber()
                        .assertEquals(new ZipFile(new ClassPathResource("testApplication.zip").getFile()).size()));
    }

    @Test
    public void downloadDroplet() {
        String applicationName = getApplicationName();

        this.spaceId.then(spaceId -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName))
                .then(applicationId -> uploadAndStartApplication(this.cloudFoundryClient, applicationId))
                .flatMap(applicationId -> this.cloudFoundryClient.applicationsV2().downloadDroplet(
                        DownloadApplicationDropletRequest.builder().applicationId(applicationId).build()))
                .reduceWith(ByteArrayOutputStream::new, ApplicationsTest::collectIntoByteArrayInputStream)
                .map(bytes -> {
                    boolean staticFile = false;
                    boolean indexFile = false;

                    try {
                        TarArchiveInputStream tis = new TarArchiveInputStream(
                                new GZIPInputStream(new ByteArrayInputStream(bytes.toByteArray())));
                        for (TarArchiveEntry entry = tis.getNextTarEntry(); entry != null; entry = tis
                                .getNextTarEntry()) {
                            if (entry.getName().contains("Staticfile")) {
                                staticFile = true;
                            }
                            if (entry.getName().contains("index.html")) {
                                indexFile = true;
                            }
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                    return staticFile && indexFile;
                }).subscribe(testSubscriber().assertEquals(true));
    }

    @SuppressWarnings("unchecked")
    @Test
    public void environment() {
        String applicationName = getApplicationName();

        this.spaceId.then(spaceId -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName))
                .then(applicationId -> Mono.just(applicationId)
                        .and(this.cloudFoundryClient.applicationsV2().environment(
                                ApplicationEnvironmentRequest.builder().applicationId(applicationId).build())))
                .then(function((applicationId, response) -> {
                    Map<String, String> vcapApplication = (Map<String, String>) response
                            .getApplicationEnvironmentJsons().get("VCAP_APPLICATION");
                    String actual = vcapApplication.get("application_id");

                    return Mono.when(Mono.just(applicationId), Mono.just(actual));
                })).subscribe(this.<Tuple2<String, String>>testSubscriber().assertThat(this::assertTupleEquality));
    }

    @Test
    public void get() {
        String applicationName = getApplicationName();

        this.spaceId.then(spaceId -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName))
                .then(applicationId -> Mono.just(applicationId)
                        .and(this.cloudFoundryClient.applicationsV2()
                                .get(GetApplicationRequest.builder().applicationId(applicationId).build())
                                .map(ResourceUtils::getId)))
                .subscribe(this.<Tuple2<String, String>>testSubscriber().assertThat(this::assertTupleEquality));
    }

    @Test
    public void list() {
        String applicationName = getApplicationName();

        this.spaceId.then(spaceId -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName))
                .flatMap(applicationId -> PaginationUtils.requestResources(page -> this.cloudFoundryClient
                        .applicationsV2().list(ListApplicationsRequest.builder().page(page).build())))
                .count().subscribe(this.<Long>testSubscriber().assertThat(count -> assertTrue(count > 1)));
    }

    @Test
    public void listFilterByDiego() {
        String applicationName = getApplicationName();

        this.spaceId.then(spaceId -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName))
                .flatMap(applicationId -> PaginationUtils.requestResources(page -> this.cloudFoundryClient
                        .applicationsV2().list(ListApplicationsRequest.builder().diego(true).page(page).build())))
                .count().subscribe(this.<Long>testSubscriber().assertThat(count -> assertTrue(count > 1)));
    }

    @Test
    public void listFilterByName() {
        String applicationName = getApplicationName();

        this.spaceId.then(spaceId -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName))
                .flatMap(applicationId -> PaginationUtils
                        .requestResources(page -> this.cloudFoundryClient.applicationsV2()
                                .list(ListApplicationsRequest.builder().name(applicationName).page(page).build())))
                .subscribe(testSubscriber().assertCount(1));
    }

    @Test
    public void listFilterByOrganizationId() {
        String applicationName = getApplicationName();

        Mono.when(this.organizationId, this.spaceId)
                .then(function((organizationId,
                        spaceId) -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName)
                                .map(applicationId -> organizationId)))
                .flatMap(organizationId -> PaginationUtils
                        .requestResources(page -> this.cloudFoundryClient.applicationsV2()
                                .list(ListApplicationsRequest.builder().organizationId(organizationId).page(page)
                                        .build())))
                .count().subscribe(this.<Long>testSubscriber().assertThat(count -> assertTrue(count > 1)));
    }

    @Test
    public void listFilterBySpaceId() {
        String applicationName = getApplicationName();

        this.spaceId
                .then(spaceId -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName)
                        .map(applicationId -> spaceId))
                .flatMap(
                        spaceId -> PaginationUtils.requestResources(page -> this.cloudFoundryClient.applicationsV2()
                                .list(ListApplicationsRequest.builder().page(page).spaceId(spaceId).build())))
                .count().subscribe(this.<Long>testSubscriber().assertThat(count -> assertTrue(count > 1)));
    }

    @Test
    public void listFilterByStackId() {
        String applicationName = getApplicationName();

        Mono.when(this.spaceId, this.stackId)
                .then(function(
                        (spaceId, stackId) -> createApplicationId(this.cloudFoundryClient, spaceId, applicationName)
                                .map(applicationId -> stackId)))
                .flatMap(
                        stackId -> PaginationUtils.requestResources(page -> this.cloudFoundryClient.applicationsV2()
                                .list(ListApplicationsRequest.builder().page(page).stackId(stackId).build())))
                .count().subscribe(this.<Long>testSubscriber().assertThat(count -> assertTrue(count > 1)));
    }

    @Test
    public void listRoutes() {
        String applicationName = getApplicationName();
        String domainName = getDomainName();

        Mono.when(this.organizationId, this.spaceId).then(function((organizationId, spaceId) -> {
            return Mono.when(Mono.just(organizationId), Mono.just(spaceId),
                    createApplicationId(this.cloudFoundryClient, spaceId, applicationName));
        })).then(function((organizationId, spaceId,
                applicationId) -> createApplicationRoute(this.cloudFoundryClient, organizationId, spaceId,
                        domainName, applicationId).map(response -> applicationId)))
                .flatMap(
                        applicationId -> PaginationUtils
                                .requestResources(page -> this.cloudFoundryClient.applicationsV2()
                                        .listRoutes(ListApplicationRoutesRequest.builder()
                                                .applicationId(applicationId).page(page).build())))
                .subscribe(testSubscriber().assertCount(1));
    }

    @Test
    public void listRoutesFilterByDomainId() {
        String applicationName = getApplicationName();
        String domainName = getDomainName();

        Mono.when(this.organizationId, this.spaceId).then(function((organizationId, spaceId) -> {
            return Mono.when(Mono.just(organizationId), Mono.just(spaceId),
                    createApplicationId(this.cloudFoundryClient, spaceId, applicationName));
        })).then(function((organizationId, spaceId, applicationId) -> {
            return createApplicationRoute(this.cloudFoundryClient, organizationId, spaceId, domainName,
                    applicationId).and(Mono.just(applicationId));
        })).flatMap(function((routeResponse,
                applicationId) -> PaginationUtils.requestResources(page -> this.cloudFoundryClient.applicationsV2()
                        .listRoutes(ListApplicationRoutesRequest.builder().applicationId(applicationId)
                                .domainId(routeResponse.getEntity().getDomainId()).page(page).build()))))
                .subscribe(testSubscriber().assertCount(1));
    }

    @Test
    public void listRoutesFilterByHost() {
        String applicationName = getApplicationName();
        String domainName = getDomainName();

        Mono.when(this.organizationId, this.spaceId).then(function((organizationId, spaceId) -> {
            return Mono.when(Mono.just(organizationId), Mono.just(spaceId),
                    createApplicationId(this.cloudFoundryClient, spaceId, applicationName));
        })).then(function((organizationId, spaceId, applicationId) -> {
            return createApplicationRoute(this.cloudFoundryClient, organizationId, spaceId, domainName,
                    applicationId).and(Mono.just(applicationId));
        })).flatMap(function((routeResponse,
                applicationId) -> PaginationUtils.requestResources(page -> this.cloudFoundryClient.applicationsV2()
                        .listRoutes(ListApplicationRoutesRequest.builder().applicationId(applicationId)
                                .host(routeResponse.getEntity().getHost()).page(page).build()))))
                .subscribe(testSubscriber().assertCount(1));
    }

    @Test
    public void listRoutesFilterByPath() {
        String applicationName = getApplicationName();
        String domainName = getDomainName();

        Mono.when(this.organizationId, this.spaceId).then(function((organizationId, spaceId) -> {
            return Mono.when(Mono.just(organizationId), Mono.just(spaceId),
                    createApplicationId(this.cloudFoundryClient, spaceId, applicationName));
        })).then(function((organizationId, spaceId, applicationId) -> {
            return createApplicationRoute(this.cloudFoundryClient, organizationId, spaceId, domainName,
                    applicationId).and(Mono.just(applicationId));
        })).flatMap(function((routeResponse,
                applicationId) -> PaginationUtils.requestPages(page -> this.cloudFoundryClient.applicationsV2()
                        .listRoutes(ListApplicationRoutesRequest.builder().applicationId(applicationId)
                                .path(routeResponse.getEntity().getPath()).page(page).build()))))
                .subscribe(testSubscriber().assertCount(1));
    }

    @Test
    public void listRoutesFilterByPort() {
        String applicationName = getApplicationName();
        String domainName = getDomainName();

        Mono.when(this.organizationId, this.spaceId).then(function((organizationId, spaceId) -> {
            return Mono.when(Mono.just(organizationId), Mono.just(spaceId),
                    createApplicationId(this.cloudFoundryClient, spaceId, applicationName));
        })).then(function((organizationId, spaceId, applicationId) -> {
            return createApplicationRoute(this.cloudFoundryClient, organizationId, spaceId, domainName,
                    applicationId).and(Mono.just(applicationId));
        })).flatMap(function((routeResponse,
                applicationId) -> PaginationUtils.requestResources(page -> this.cloudFoundryClient.applicationsV2()
                        .listRoutes(ListApplicationRoutesRequest.builder().applicationId(applicationId).page(page)
                                .port(routeResponse.getEntity().getPort()).build()))))
                .subscribe(testSubscriber().assertCount(1));
    }

    //TODO Implement missing client API
    @Ignore("TODO: Awaiting CUPS https://www.pivotaltracker.com/story/show/101452058")
    @Test
    public void listServiceBindings() {
        Assert.fail();
    }

    //TODO Implement missing client API
    @Ignore("TODO: Awaiting CUPS https://www.pivotaltracker.com/story/show/101452058")
    @Test
    public void listServiceBindingsFilterByServiceInstanceId() {
        Assert.fail();
    }

    @Test
    public void removeRoute() {
        String applicationName = getApplicationName();
        String domainName = getDomainName();

        Mono.when(this.organizationId, this.spaceId).then(function((organizationId, spaceId) -> {
            return Mono.when(Mono.just(organizationId), Mono.just(spaceId),
                    createApplicationId(this.cloudFoundryClient, spaceId, applicationName));
        })).then(function((organizationId, spaceId, applicationId) -> {
            return createApplicationRoute(this.cloudFoundryClient, organizationId, spaceId, domainName,
                    applicationId).and(Mono.just(applicationId));
        })).then(
                function(
                        (routeResponse, applicationId) -> this.cloudFoundryClient.applicationsV2()
                                .removeRoute(RemoveApplicationRouteRequest.builder().applicationId(applicationId)
                                        .routeId(ResourceUtils.getId(routeResponse)).build())))
                .subscribe(testSubscriber());
    }

    //TODO Implement missing client API
    @Ignore("TODO: Awaiting CUPS https://www.pivotaltracker.com/story/show/101452058")
    @Test
    public void removeServiceBinding() {
        Assert.fail();
    }

    @Test
    public void restage() {
        String applicationName = getApplicationName();

        Mono.when(this.organizationId, this.spaceId)
                .then(function((organizationId, spaceId) -> createApplicationId(this.cloudFoundryClient, spaceId,
                        applicationName)))
                .then(applicationId -> uploadAndStartApplication(this.cloudFoundryClient, applicationId))
                .then(applicationId -> this.cloudFoundryClient.applicationsV2()
                        .restage(RestageApplicationRequest.builder().applicationId(applicationId).build())
                        .map(ResourceUtils::getId))
                .then(applicationId -> waitForStaging(this.cloudFoundryClient, applicationId))
                .subscribe(testSubscriber().assertCount(1));
    }

    @Test
    public void statistics() {
        String applicationName = getApplicationName();

        Mono.when(this.organizationId, this.spaceId)
                .then(function((organizationId, spaceId) -> createApplicationId(this.cloudFoundryClient, spaceId,
                        applicationName)))
                .then(applicationId -> uploadAndStartApplication(this.cloudFoundryClient, applicationId))
                .then(applicationId -> this.cloudFoundryClient.applicationsV2()
                        .statistics(ApplicationStatisticsRequest.builder().applicationId(applicationId).build())
                        .map(instanceStatistics -> instanceStatistics.get("0").getStatistics().getName()))
                .subscribe(testSubscriber().assertEquals(applicationName));
    }

    @Test
    public void summary() {
        String applicationName = getApplicationName();

        Mono.when(this.organizationId, this.spaceId)
                .then(function((organizationId, spaceId) -> createApplicationId(this.cloudFoundryClient, spaceId,
                        applicationName)))
                .then(applicationId -> this.cloudFoundryClient.applicationsV2()
                        .summary(SummaryApplicationRequest.builder().applicationId(applicationId).build())
                        .map(SummaryApplicationResponse::getId).and(Mono.just(applicationId)))
                .subscribe(this.<Tuple2<String, String>>testSubscriber().assertThat(this::assertTupleEquality));
    }

    @Test
    public void terminateInstance() {
        String applicationName = getApplicationName();

        Mono.when(this.organizationId, this.spaceId)
                .then(function((organizationId, spaceId) -> createApplicationId(this.cloudFoundryClient, spaceId,
                        applicationName)))
                .then(applicationId -> uploadAndStartApplication(this.cloudFoundryClient, applicationId)).then(
                        applicationId -> this.cloudFoundryClient.applicationsV2()
                                .terminateInstance(TerminateApplicationInstanceRequest.builder()
                                        .applicationId(applicationId).index("0").build()))
                .subscribe(testSubscriber());
    }

    @Test
    public void update() {
        String applicationName = getApplicationName();
        String applicationName2 = getApplicationName();

        Mono.when(this.organizationId, this.spaceId)
                .then(function((organizationId, spaceId) -> createApplicationId(this.cloudFoundryClient, spaceId,
                        applicationName)))
                .then(applicationId -> this.cloudFoundryClient.applicationsV2()
                        .update(UpdateApplicationRequest.builder().applicationId(applicationId)
                                .name(applicationName2).build())
                        .map(ResourceUtils::getId))
                .then(applicationId -> this.cloudFoundryClient.applicationsV2()
                        .get(GetApplicationRequest.builder().applicationId(applicationId).build())
                        .map(response -> response.getEntity().getName()))
                .subscribe(testSubscriber().assertEquals(applicationName2));
    }

    @Test
    public void upload() throws IOException {
        String applicationName = getApplicationName();

        Mono.when(this.organizationId, this.spaceId)
                .then(function((organizationId, spaceId) -> createApplicationId(this.cloudFoundryClient, spaceId,
                        applicationName)))
                .then(applicationId -> uploadApplication(this.cloudFoundryClient, applicationId))
                .flatMap(applicationId -> this.cloudFoundryClient.applicationsV2()
                        .download(DownloadApplicationRequest.builder().applicationId(applicationId).build()))
                .after().subscribe(testSubscriber());
    }

    private static ByteArrayOutputStream collectIntoByteArrayInputStream(ByteArrayOutputStream out, byte[] bytes) {
        try {
            out.write(bytes);
            return out;
        } catch (IOException e) {
            throw new Exceptions.UpstreamException(e);
        }
    }

    private static Mono<String> createApplicationId(CloudFoundryClient cloudFoundryClient, String spaceId,
            String applicationName) {
        return cloudFoundryClient.applicationsV2()
                .create(CreateApplicationRequest.builder().buildpack("staticfile_buildpack").diego(true)
                        .diskQuota(512).memory(64).name(applicationName).spaceId(spaceId).build())
                .map(ResourceUtils::getId);
    }

    private static Mono<CreateRouteResponse> createApplicationRoute(CloudFoundryClient cloudFoundryClient,
            String organizationId, String spaceId, String domainName, String applicationId) {
        return cloudFoundryClient.domains()
                .create(CreateDomainRequest
                        .builder().name(domainName).owningOrganizationId(organizationId).wildcard(true).build())
                .map(ResourceUtils::getId)
                .then(domainId -> cloudFoundryClient.routes()
                        .create(CreateRouteRequest.builder().domainId(domainId).host("test-host").path("/test-path")
                                .spaceId(spaceId).build()))
                .then(createRouteResponse -> cloudFoundryClient.applicationsV2()
                        .associateRoute(AssociateApplicationRouteRequest.builder().applicationId(applicationId)
                                .routeId(createRouteResponse.getMetadata().getId()).build())
                        .map(response -> createRouteResponse));
    }

    private static Mono<String> startApplication(CloudFoundryClient cloudFoundryClient, String applicationId) {
        return cloudFoundryClient.applicationsV2()
                .update(UpdateApplicationRequest.builder().applicationId(applicationId).state("STARTED").build())
                .map(ResourceUtils::getId).then(id -> waitForStaging(cloudFoundryClient, id))
                .then(id -> waitForStarting(cloudFoundryClient, id));
    }

    private static Mono<String> uploadAndStartApplication(CloudFoundryClient cloudFoundryClient,
            String applicationId) {
        return uploadApplication(cloudFoundryClient, applicationId)
                .then(id -> startApplication(cloudFoundryClient, id));
    }

    private static Mono<String> uploadApplication(CloudFoundryClient cloudFoundryClient, String applicationId) {
        try {
            return cloudFoundryClient.applicationsV2()
                    .upload(UploadApplicationRequest.builder()
                            .application(new ClassPathResource("testApplication.zip").getInputStream()).async(true)
                            .applicationId(applicationId).build())
                    .map(ResourceUtils::getId).then(jobId -> JobUtils.waitForCompletion(cloudFoundryClient, jobId))
                    .after(() -> Mono.just(applicationId));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static Mono<String> waitForStaging(CloudFoundryClient cloudFoundryClient, String applicationId) {
        return cloudFoundryClient.applicationsV2()
                .get(GetApplicationRequest.builder().applicationId(applicationId).build())
                .map(response -> response.getEntity().getPackageState()).where("STAGED"::equals)
                .repeatWhenEmpty(10, DelayUtils.exponentialBackOff(Duration.ofSeconds(1), Duration.ofSeconds(10)))
                .map(state -> applicationId);
    }

    private static Mono<String> waitForStarting(CloudFoundryClient cloudFoundryClient, String applicationId) {
        return cloudFoundryClient.applicationsV2()
                .instances(ApplicationInstancesRequest.builder().applicationId(applicationId).build())
                .flatMap(response -> Flux.fromIterable(response.values()))
                .filter(applicationInstanceInfo -> "RUNNING".equals(applicationInstanceInfo.getState())).next()
                .repeatWhenEmpty(10, DelayUtils.exponentialBackOff(Duration.ofSeconds(1), Duration.ofSeconds(10)))
                .map(info -> applicationId);
    }

}