diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/routes/DefaultRoutes.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/routes/DefaultRoutes.java index bd02a06ff4..d718a3fd88 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/routes/DefaultRoutes.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/routes/DefaultRoutes.java @@ -1,17 +1,15 @@ /* * Copyright 2013-2021 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 + * 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 + * 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. + * 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.operations.routes; @@ -27,10 +25,9 @@ import org.cloudfoundry.client.v2.privatedomains.PrivateDomainResource; import org.cloudfoundry.client.v2.routes.AbstractRouteResource; import org.cloudfoundry.client.v2.routes.CreateRouteResponse; -import org.cloudfoundry.client.v2.routes.DeleteRouteResponse; import org.cloudfoundry.client.v2.routes.ListRouteApplicationsRequest; import org.cloudfoundry.client.v2.routes.RouteEntity; -import org.cloudfoundry.client.v2.routes.RouteExistsRequest; + import org.cloudfoundry.client.v2.routes.RouteResource; import org.cloudfoundry.client.v2.serviceinstances.UnionServiceInstanceResource; import org.cloudfoundry.client.v2.shareddomains.ListSharedDomainsRequest; @@ -39,6 +36,10 @@ import org.cloudfoundry.client.v2.spaces.ListSpaceRoutesRequest; import org.cloudfoundry.client.v2.spaces.ListSpaceServiceInstancesRequest; import org.cloudfoundry.client.v2.spaces.SpaceResource; +import org.cloudfoundry.client.v3.domains.CheckReservedRoutesRequest; +import org.cloudfoundry.client.v3.organizations.ListOrganizationDomainsRequest; +import org.cloudfoundry.client.v3.domains.DomainResource; +import org.cloudfoundry.client.v3.spaces.DeleteUnmappedRoutesRequest; import org.cloudfoundry.operations.util.OperationsLogging; import org.cloudfoundry.util.ExceptionUtils; import org.cloudfoundry.util.JobUtils; @@ -58,479 +59,526 @@ import java.util.function.UnaryOperator; import static org.cloudfoundry.util.tuple.TupleUtils.function; -import static org.cloudfoundry.util.tuple.TupleUtils.predicate; public final class DefaultRoutes implements Routes { - private final Mono cloudFoundryClient; - - private final Mono organizationId; - - private final Mono spaceId; - - public DefaultRoutes(Mono cloudFoundryClient, Mono organizationId, Mono spaceId) { - this.cloudFoundryClient = cloudFoundryClient; - this.organizationId = organizationId; - this.spaceId = spaceId; - } - - @Override - public Mono check(CheckRouteRequest request) { - return Mono - .zip(this.cloudFoundryClient, this.organizationId) - .flatMap(function((cloudFoundryClient, organizationId) -> Mono.zip( - Mono.just(cloudFoundryClient), - getOptionalDomainId(cloudFoundryClient, organizationId, request.getDomain()) - ))) - .flatMap(function((cloudFoundryClient, domainId) -> requestRouteExists(cloudFoundryClient, domainId, request.getHost(), request.getPath()))) - .defaultIfEmpty(false) - .transform(OperationsLogging.log("Check Route Exists")) - .checkpoint(); - } - - @Override - public Mono create(CreateRouteRequest request) { - return Mono - .zip(this.cloudFoundryClient, this.organizationId) - .flatMap(function((cloudFoundryClient, organizationId) -> Mono.zip( - Mono.just(cloudFoundryClient), - getSpaceId(cloudFoundryClient, organizationId, request.getSpace()), - getDomainId(cloudFoundryClient, organizationId, request.getDomain()) - ))) - .flatMap(function((cloudFoundryClient, spaceId, domainId) -> - requestCreateRoute(cloudFoundryClient, domainId, request.getHost(), request.getPath(), request.getPort(), request.getRandomPort(), spaceId) - .map(ResourceUtils::getEntity) - .flatMap(routeEntity -> Mono.justOrEmpty(routeEntity.getPort())) - )) - .transform(OperationsLogging.log("Create Route")) - .checkpoint(); - } - - @Override - public Mono delete(DeleteRouteRequest request) { - return Mono - .zip(this.cloudFoundryClient, this.organizationId) - .flatMap(function((cloudFoundryClient, organizationId) -> Mono.zip( - Mono.just(cloudFoundryClient), - getDomainId(cloudFoundryClient, organizationId, request.getDomain()) - ))) - .flatMap(function((cloudFoundryClient, domainId) -> Mono.zip( - Mono.just(cloudFoundryClient), - Mono.just(request.getCompletionTimeout()), - getRouteId(cloudFoundryClient, request.getHost(), request.getDomain(), domainId, request.getPath(), request.getPort()) - ))) - .flatMap(function(DefaultRoutes::deleteRoute)) - .transform(OperationsLogging.log("Delete Route")) - .checkpoint(); - } - - @Override - public Mono deleteOrphanedRoutes(DeleteOrphanedRoutesRequest request) { - return Mono - .zip(this.cloudFoundryClient, this.spaceId) - .flatMapMany(function((cloudFoundryClient, spaceId) -> requestSpaceRoutes(cloudFoundryClient, spaceId) - .filter(route -> isRouteOrphan(ResourceUtils.getEntity(route))) - .map(ResourceUtils::getId) - .map(routeId -> Tuples.of(cloudFoundryClient, routeId)))) - .flatMap(function((cloudFoundryClient, routeId) -> getApplications(cloudFoundryClient, routeId) - .map(applicationResources -> Tuples.of(cloudFoundryClient, applicationResources, routeId)))) - .filter(predicate((cloudFoundryClient, applicationResources, routeId) -> isApplicationOrphan(applicationResources))) - .flatMap(function((cloudFoundryClient, applicationResources, routeId) -> deleteRoute(cloudFoundryClient, request.getCompletionTimeout(), routeId))) - .then() - .transform(OperationsLogging.log("Delete Orphaned Routes")) - .checkpoint(); - } - - @Override - public Flux list(ListRoutesRequest request) { - return Mono - .zip(this.cloudFoundryClient, this.organizationId) - .flatMap(function((cloudFoundryClient, organizationId) -> Mono.zip( - Mono.just(cloudFoundryClient), - getAllDomains(cloudFoundryClient, organizationId), - getAllSpaces(cloudFoundryClient, organizationId) - ))) - .flatMapMany(function((cloudFoundryClient, domains, spaces) -> getRoutes(cloudFoundryClient, request, this.organizationId, this.spaceId) - .map(route -> Tuples.of(cloudFoundryClient, domains, route, spaces)))) - .flatMap(function((cloudFoundryClient, domains, route, spaces) -> Mono - .zip( - getApplicationNames(cloudFoundryClient, ResourceUtils.getId(route)), - getDomainName(domains, ResourceUtils.getEntity(route).getDomainId()), - Mono.just(route), - getServiceName(cloudFoundryClient, ResourceUtils.getEntity(route)), - getSpaceName(spaces, ResourceUtils.getEntity(route).getSpaceId()) - ))) - .map(function(DefaultRoutes::toRoute)) - .transform(OperationsLogging.log("List Routes")) - .checkpoint(); - } - - @Override - public Mono map(MapRouteRequest request) { - return Mono - .zip(this.cloudFoundryClient, this.organizationId, this.spaceId) - .flatMap(function((cloudFoundryClient, organizationId, spaceId) -> Mono.zip( - Mono.just(cloudFoundryClient), - getOrCreateRoute(cloudFoundryClient, organizationId, spaceId, request.getDomain(), request.getHost(), request.getPath(), request.getPort(), request.getRandomPort()), - getApplicationId(cloudFoundryClient, request.getApplicationName(), spaceId) - ))) - .flatMap(function((cloudFoundryClient, routeResource, applicationId) -> requestAssociateRoute(cloudFoundryClient, applicationId, ResourceUtils.getId(routeResource)))) - .then(Mono.justOrEmpty(request.getPort())) - .transform(OperationsLogging.log("Map Route")) - .checkpoint(); - } - - @Override - public Mono unmap(UnmapRouteRequest request) { - return Mono - .zip(this.cloudFoundryClient, this.organizationId, this.spaceId) - .flatMap(function((cloudFoundryClient, organizationId, spaceId) -> Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationId(cloudFoundryClient, request.getApplicationName(), spaceId), - getDomainId(cloudFoundryClient, organizationId, request.getDomain()) - .flatMap(domainId -> getRouteId(cloudFoundryClient, request.getHost(), request.getDomain(), domainId, request.getPath(), request.getPort())) - ))) - .flatMap(function(DefaultRoutes::requestRemoveRouteFromApplication)) - .transform(OperationsLogging.log("Unmap Route")) - .checkpoint(); - } - - private static Mono deleteRoute(CloudFoundryClient cloudFoundryClient, Duration completionTimeout, String routeId) { - return requestDeleteRoute(cloudFoundryClient, routeId) - .flatMap(job -> JobUtils.waitForCompletion(cloudFoundryClient, completionTimeout, job)); - } - - private static Mono> getAllDomains(CloudFoundryClient cloudFoundryClient, String organizationId) { - return requestAllPrivateDomains(cloudFoundryClient, organizationId) - .map(resource -> Tuples.of(ResourceUtils.getId(resource), ResourceUtils.getEntity(resource).getName())) - .mergeWith(requestAllSharedDomains(cloudFoundryClient) - .map(resource -> Tuples.of(ResourceUtils.getId(resource), ResourceUtils.getEntity(resource).getName()))) - .collectMap(function((id, name) -> id), function((id, name) -> name)); - } - - private static Mono> getAllSpaces(CloudFoundryClient cloudFoundryClient, String organizationId) { - return requestAllSpaces(cloudFoundryClient, organizationId) - .map(resource -> Tuples.of(ResourceUtils.getId(resource), ResourceUtils.getEntity(resource).getName())) - .collectMap(function((id, name) -> id), function((id, name) -> name)); - } - - private static Mono getApplication(CloudFoundryClient cloudFoundryClient, String application, String spaceId) { - return requestApplications(cloudFoundryClient, application, spaceId) - .single() - .onErrorResume(NoSuchElementException.class, t -> ExceptionUtils.illegalArgument("Application %s does not exist", application)); - } - - private static Mono getApplicationId(CloudFoundryClient cloudFoundryClient, String application, String spaceId) { - return getApplication(cloudFoundryClient, application, spaceId) - .map(ResourceUtils::getId); - } - - private static Mono> getApplicationNames(CloudFoundryClient cloudFoundryClient, String routeId) { - return requestApplications(cloudFoundryClient, routeId) - .map(resource -> ResourceUtils.getEntity(resource).getName()) - .collectList(); - } - - private static Mono> getApplications(CloudFoundryClient cloudFoundryClient, String routeId) { - return requestApplications(cloudFoundryClient, routeId) - .collectList(); - } - - private static Mono> getDomain(CloudFoundryClient cloudFoundryClient, String organizationId, String domain) { - return getDomains(cloudFoundryClient, organizationId, domain) - .single() - .onErrorResume(NoSuchElementException.class, t -> ExceptionUtils.illegalArgument("Domain %s does not exist", domain)); - } - - private static Mono getDomainId(CloudFoundryClient cloudFoundryClient, String organizationId, String domain) { - return getDomain(cloudFoundryClient, organizationId, domain) - .map(ResourceUtils::getId); - } - - private static Mono getDomainName(Map domains, String domainId) { - return Mono.just(domains.get(domainId)); - } - - private static Flux> getDomains(CloudFoundryClient cloudFoundryClient, String organizationId, String domain) { - return requestPrivateDomains(cloudFoundryClient, organizationId, domain) - .map((Function>) in -> in) - .switchIfEmpty(requestSharedDomains(cloudFoundryClient, domain)); - } - - private static Mono getOptionalDomainId(CloudFoundryClient cloudFoundryClient, String organizationId, String domain) { - return getDomains(cloudFoundryClient, organizationId, domain) - .singleOrEmpty() - .map(ResourceUtils::getId); - } - - private static Mono getOrCreateRoute(CloudFoundryClient cloudFoundryClient, String organizationId, String spaceId, String domain, String host, String path, Integer port, - Boolean randomPort) { - if (randomPort != null) { - return getDomainId(cloudFoundryClient, organizationId, domain) - .flatMap(domainId -> requestCreateRoute(cloudFoundryClient, domainId, host, path, port, randomPort, spaceId)); - } - - return getDomainId(cloudFoundryClient, organizationId, domain) - .flatMap(domainId -> getRoute(cloudFoundryClient, domainId, host, path, port) - .cast(AbstractRouteResource.class) - .switchIfEmpty(requestCreateRoute(cloudFoundryClient, domainId, host, path, port, randomPort, spaceId))); - } - - private static Mono getRoute(CloudFoundryClient cloudFoundryClient, String domainId, String domain, String host, String path, Integer port) { - return getRoute(cloudFoundryClient, domainId, host, path, port) - .switchIfEmpty(ExceptionUtils.illegalArgument("Route for %s does not exist", domain)); - } - - private static Mono getRoute(CloudFoundryClient cloudFoundryClient, String domainId, String host, String path, Integer port) { - if (port != null) { - return requestRoutes(cloudFoundryClient, domainId, null, null, port) - .singleOrEmpty(); - } else { - return requestRoutes(cloudFoundryClient, domainId, host, path, port) - .filter(resource -> isIdentical(nullSafe(host), ResourceUtils.getEntity(resource).getHost())) - .filter(resource -> isIdentical(Optional.ofNullable(path).orElse(""), ResourceUtils.getEntity(resource).getPath())) - .singleOrEmpty(); - } - } - - private static Mono getRouteId(CloudFoundryClient cloudFoundryClient, String host, String domain, String domainId, String path, Integer port) { - return getRoute(cloudFoundryClient, domainId, domain, host, path, port) - .map(ResourceUtils::getId); - } - - private static Flux getRoutes(CloudFoundryClient cloudFoundryClient, ListRoutesRequest request, Mono organizationId, Mono spaceId) { - if (Level.ORGANIZATION == request.getLevel()) { - return organizationId - .flatMapMany(organizationId1 -> requestRoutes(cloudFoundryClient, builder -> builder.organizationId(organizationId1))); - } else { - return spaceId - .flatMapMany(spaceId1 -> requestSpaceRoutes(cloudFoundryClient, spaceId1)); - } - } - - private static Mono> getServiceInstanceName(CloudFoundryClient cloudFoundryClient, String serviceInstanceId, String spaceId) { - return requestListSpaceServiceInstances(cloudFoundryClient, spaceId) - .filter(resource -> serviceInstanceId.equals(ResourceUtils.getId(resource))) - .single() - .map(resource -> Optional.of(ResourceUtils.getEntity(resource).getName())); - } - - private static Mono> getServiceName(CloudFoundryClient cloudFoundryClient, RouteEntity route) { - return Mono.justOrEmpty(route.getServiceInstanceId()) - .flatMap(serviceInstanceId -> getServiceInstanceName(cloudFoundryClient, serviceInstanceId, route.getSpaceId())) - .defaultIfEmpty(Optional.empty()); - } - - private static Mono getSpace(CloudFoundryClient cloudFoundryClient, String organizationId, String space) { - return requestSpaces(cloudFoundryClient, organizationId, space) - .single() - .onErrorResume(NoSuchElementException.class, t -> ExceptionUtils.illegalArgument("Space %s does not exist", space)); - } - - private static Mono getSpaceId(CloudFoundryClient cloudFoundryClient, String organizationId, String space) { - return getSpace(cloudFoundryClient, organizationId, space) - .map(ResourceUtils::getId); - } - - private static Mono getSpaceName(Map spaces, String spaceId) { - return Mono.just(spaces.get(spaceId)); - } - - private static boolean isApplicationOrphan(List applications) { - return applications.isEmpty(); - } - - private static boolean isIdentical(String s, String t) { - return s == null ? t == null : s.equals(t); - } - - private static String nullSafe(String host) { - return host == null ? "" : host; - } - - private static Flux requestAllPrivateDomains(CloudFoundryClient cloudFoundryClient, String organizationId) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.organizations() - .listPrivateDomains(ListOrganizationPrivateDomainsRequest.builder() - .organizationId(organizationId) - .page(page) - .build())); - } - - private static Flux requestAllSharedDomains(CloudFoundryClient cloudFoundryClient) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.sharedDomains() - .list(ListSharedDomainsRequest.builder() - .page(page) - .build())); - } - - private static Flux requestAllSpaces(CloudFoundryClient cloudFoundryClient, String organizationId) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.organizations() - .listSpaces(ListOrganizationSpacesRequest.builder() - .organizationId(organizationId) - .page(page) - .build())); - } - - private static Flux requestApplications(CloudFoundryClient cloudFoundryClient, String routeId) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.routes() - .listApplications(ListRouteApplicationsRequest.builder() - .routeId(routeId) - .page(page) - .build())); - } - - private static Flux requestApplications(CloudFoundryClient cloudFoundryClient, String application, String spaceId) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.spaces() - .listApplications(ListSpaceApplicationsRequest.builder() - .name(application) - .page(page) - .spaceId(spaceId) - .build())); - } - - private static Mono requestAssociateRoute(CloudFoundryClient cloudFoundryClient, String applicationId, String routeId) { - return cloudFoundryClient.applicationsV2() - .associateRoute(AssociateApplicationRouteRequest.builder() - .applicationId(applicationId) - .routeId(routeId) - .build()); - } - - private static Mono requestCreateRoute(CloudFoundryClient cloudFoundryClient, String domainId, String host, String path, Integer port, Boolean randomPort, String spaceId) { - - org.cloudfoundry.client.v2.routes.CreateRouteRequest.Builder builder = org.cloudfoundry.client.v2.routes.CreateRouteRequest.builder(); - - if (randomPort != null && randomPort) { - builder.generatePort(true); - } else if (port != null) { - builder.port(port); - } else { - builder.host(host); - builder.path(path); - } - - return cloudFoundryClient.routes() - .create(builder - .domainId(domainId) - .spaceId(spaceId) - .build()); - } - - private static Mono requestDeleteRoute(CloudFoundryClient cloudFoundryClient, String routeId) { - return cloudFoundryClient.routes() - .delete(org.cloudfoundry.client.v2.routes.DeleteRouteRequest.builder() - .async(true) - .routeId(routeId) - .build()); - } - - private static Flux requestListSpaceServiceInstances(CloudFoundryClient cloudFoundryClient, String spaceId) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.spaces() - .listServiceInstances(ListSpaceServiceInstancesRequest.builder() - .page(page) - .returnUserProvidedServiceInstances(true) - .spaceId(spaceId) - .build())); - } - - private static Flux requestPrivateDomains(CloudFoundryClient cloudFoundryClient, String organizationId, String domain) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.organizations() - .listPrivateDomains(ListOrganizationPrivateDomainsRequest.builder() - .organizationId(organizationId) - .name(domain) - .page(page) - .build())); - } - - private static Mono requestRemoveRouteFromApplication(CloudFoundryClient cloudFoundryClient, String applicationId, String routeId) { - return cloudFoundryClient.applicationsV2() - .removeRoute(RemoveApplicationRouteRequest.builder() - .applicationId(applicationId) - .routeId(routeId) - .build()); - } - - private static Mono requestRouteExists(CloudFoundryClient cloudFoundryClient, String domainId, String host, String path) { - return cloudFoundryClient.routes() - .exists(RouteExistsRequest.builder() - .domainId(domainId) - .host(host) - .path(path) - .build()); - } - - private static Flux requestRoutes(CloudFoundryClient cloudFoundryClient, UnaryOperator modifier) { - - org.cloudfoundry.client.v2.routes.ListRoutesRequest.Builder listBuilder = modifier.apply(org.cloudfoundry.client.v2.routes.ListRoutesRequest.builder()); - - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.routes() - .list(listBuilder - .page(page) - .build())); - } - - private static Flux requestRoutes(CloudFoundryClient cloudFoundryClient, String domainId, String host, String path, Integer port) { - return requestRoutes(cloudFoundryClient, builder -> builder - .domainId(domainId) - .hosts(Optional.ofNullable(host).map(Collections::singletonList).orElse(null)) - .paths(Optional.ofNullable(path).map(Collections::singletonList).orElse(null)) - .port(Optional.ofNullable(port).orElse(null)) - ); - } - - private static Flux requestSharedDomains(CloudFoundryClient cloudFoundryClient, String domain) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.sharedDomains() - .list(ListSharedDomainsRequest.builder() - .name(domain) - .page(page) - .build())); - } - - private static Flux requestSpaceRoutes(CloudFoundryClient cloudFoundryClient, String spaceId) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.spaces() - .listRoutes(ListSpaceRoutesRequest.builder() - .spaceId(spaceId) - .page(page) - .build())); - } - - private static Flux requestSpaces(CloudFoundryClient cloudFoundryClient, String organizationId, String space) { - return PaginationUtils - .requestClientV2Resources(page -> cloudFoundryClient.organizations() - .listSpaces(ListOrganizationSpacesRequest.builder() - .organizationId(organizationId) - .name(space) - .page(page) - .build())); - } - - private static Route toRoute(List applications, String domain, RouteResource resource, Optional service, String space) { - RouteEntity entity = ResourceUtils.getEntity(resource); - Route.Builder builder = Route.builder() - .applications(applications) - .domain(domain) - .host(entity.getHost()) - .id(ResourceUtils.getId(resource)) - .path(entity.getPath()) - .space(space); - - service.ifPresent(builder::service); - - return builder.build(); - } - - private boolean isRouteOrphan(RouteEntity entity) { - return entity.getServiceInstanceId() == null || entity.getServiceInstanceId().isEmpty(); - } + private final Mono cloudFoundryClient; + + private final Mono organizationId; + + private final Mono spaceId; + + public DefaultRoutes(Mono cloudFoundryClient, + Mono organizationId, Mono spaceId) { + this.cloudFoundryClient = cloudFoundryClient; + this.organizationId = organizationId; + this.spaceId = spaceId; + } + + @Override + public Mono check(CheckRouteRequest request) { + return Mono.zip(this.cloudFoundryClient, this.organizationId) + .flatMap(function((client, organizationId) -> Mono.zip( + this.cloudFoundryClient, + getOptionalDomainIdByName(client, organizationId, + request.getDomain())))) + .flatMap(function((client, domainId) -> routeExists(client, + domainId, request.getHost(), request.getPath()))) + .defaultIfEmpty(false) + .transform(OperationsLogging.log("Check Route Exists")) + .checkpoint(); + } + + private static Mono routeExists(CloudFoundryClient cloudFoundryClient, + String domainId, String host, String path) { + return cloudFoundryClient.domainsV3() + .checkReservedRoutes(CheckReservedRoutesRequest.builder() + .domainId(domainId).host(host).path(path).build()) + .flatMap(response -> Mono.just(response.getMatchingRoute())); + } + + private static Mono getOptionalDomainIdByName(CloudFoundryClient cloudFoundryClient, + String organizationId, String domain) { + return listDomains(cloudFoundryClient, organizationId, new String[] {domain}) + .singleOrEmpty().map(resource -> resource.getId()); + } + + private static Flux listDomains(CloudFoundryClient cloudFoundryClient, + String organizationId, String[] domainNamesFilter) { + return PaginationUtils.requestClientV3Resources(page -> cloudFoundryClient + .organizationsV3() + .listDomains(ListOrganizationDomainsRequest.builder() + .names(domainNamesFilter).page(page) + .organizationId(organizationId).build())); + } + + @Override + public Mono create(CreateRouteRequest request) { + return Mono.zip(this.cloudFoundryClient, this.organizationId) + .flatMap(function((cloudFoundryClient, organizationId) -> Mono.zip( + Mono.just(cloudFoundryClient), + getSpaceId(cloudFoundryClient, organizationId, + request.getSpace()), + getDomainId(cloudFoundryClient, organizationId, + request.getDomain())))) + .flatMap(function((cloudFoundryClient, spaceId, + domainId) -> requestCreateRoute(cloudFoundryClient, + domainId, request.getHost(), + request.getPath(), + request.getPort(), request + .getRandomPort(), + spaceId).map(ResourceUtils::getEntity) + .flatMap(routeEntity -> Mono + .justOrEmpty(routeEntity + .getPort())))) + .transform(OperationsLogging.log("Create Route")).checkpoint(); + } + + @Override + public Mono delete(DeleteRouteRequest request) { + return Mono.zip(this.cloudFoundryClient, this.organizationId) + .flatMap(function((cloudFoundryClient, organizationId) -> Mono.zip( + Mono.just(cloudFoundryClient), + getDomainId(cloudFoundryClient, organizationId, + request.getDomain())))) + .flatMap(function((cloudFoundryClient, domainId) -> Mono.zip( + Mono.just(cloudFoundryClient), + Mono.just(request.getCompletionTimeout()), + getRouteId(cloudFoundryClient, request.getHost(), + request.getDomain(), domainId, + request.getPath(), + request.getPort())))) + .flatMap(function(DefaultRoutes::deleteRoute)) + .transform(OperationsLogging.log("Delete Route")).checkpoint(); + } + + @Override + public Mono deleteOrphanedRoutes(DeleteOrphanedRoutesRequest request) { + return Mono.zip(this.cloudFoundryClient, this.spaceId).flatMap(function((client, + spaceId) -> Mono.zip(this.cloudFoundryClient, client.spacesV3() + .deleteUnmappedRoutes(DeleteUnmappedRoutesRequest + .builder().spaceId(spaceId) + .build())))) + .flatMap(function((client, job) -> JobUtils.waitForCompletion( + client, request.getCompletionTimeout(), job))) + .transform(OperationsLogging.log("Delete Orphaned Routes")) + .checkpoint(); + + } + + @Override + public Flux list(ListRoutesRequest request) { + return Mono.zip(this.cloudFoundryClient, this.organizationId) + .flatMap(function((cloudFoundryClient, organizationId) -> Mono.zip( + Mono.just(cloudFoundryClient), + getAllDomains(cloudFoundryClient, organizationId), + getAllSpaces(cloudFoundryClient, organizationId)))) + .flatMapMany(function((cloudFoundryClient, domains, + spaces) -> getRoutes(cloudFoundryClient, request, + this.organizationId, this.spaceId) + .map(route -> Tuples + .of(cloudFoundryClient, + domains, + route, + spaces)))) + .flatMap(function((cloudFoundryClient, domains, route, + spaces) -> Mono.zip(getApplicationNames( + cloudFoundryClient, + ResourceUtils.getId(route)), + getDomainName(domains, ResourceUtils + .getEntity(route) + .getDomainId()), + Mono.just(route), + getServiceName(cloudFoundryClient, + ResourceUtils.getEntity( + route)), + getSpaceName(spaces, ResourceUtils + .getEntity(route) + .getSpaceId())))) + .map(function(DefaultRoutes::toRoute)) + .transform(OperationsLogging.log("List Routes")).checkpoint(); + } + + @Override + public Mono map(MapRouteRequest request) { + return Mono.zip(this.cloudFoundryClient, this.organizationId, this.spaceId).flatMap( + function((cloudFoundryClient, organizationId, spaceId) -> Mono.zip( + Mono.just(cloudFoundryClient), + getOrCreateRoute(cloudFoundryClient, organizationId, + spaceId, request.getDomain(), + request.getHost(), + request.getPath(), + request.getPort(), + request.getRandomPort()), + getApplicationId(cloudFoundryClient, + request.getApplicationName(), + spaceId)))) + .flatMap(function((cloudFoundryClient, routeResource, + applicationId) -> requestAssociateRoute( + cloudFoundryClient, applicationId, + ResourceUtils.getId( + routeResource)))) + .then(Mono.justOrEmpty(request.getPort())) + .transform(OperationsLogging.log("Map Route")).checkpoint(); + } + + @Override + public Mono unmap(UnmapRouteRequest request) { + return Mono.zip(this.cloudFoundryClient, this.organizationId, this.spaceId).flatMap( + function((cloudFoundryClient, organizationId, spaceId) -> Mono.zip( + Mono.just(cloudFoundryClient), + getApplicationId(cloudFoundryClient, + request.getApplicationName(), + spaceId), + getDomainId(cloudFoundryClient, organizationId, + request.getDomain()).flatMap( + domainId -> getRouteId( + cloudFoundryClient, + request.getHost(), + request.getDomain(), + domainId, + request.getPath(), + request.getPort()))))) + .flatMap(function(DefaultRoutes::requestRemoveRouteFromApplication)) + .transform(OperationsLogging.log("Unmap Route")).checkpoint(); + } + + private static Mono> getAllDomains( + CloudFoundryClient cloudFoundryClient, String organizationId) { + return requestAllPrivateDomains(cloudFoundryClient, organizationId) + .map(resource -> Tuples.of(ResourceUtils.getId(resource), + ResourceUtils.getEntity(resource).getName())) + .mergeWith(requestAllSharedDomains(cloudFoundryClient).map( + resource -> Tuples.of(ResourceUtils.getId(resource), + ResourceUtils.getEntity(resource) + .getName()))) + .collectMap(function((id, name) -> id), + function((id, name) -> name)); + } + + private static Mono> getAllSpaces(CloudFoundryClient cloudFoundryClient, + String organizationId) { + return requestAllSpaces(cloudFoundryClient, organizationId) + .map(resource -> Tuples.of(ResourceUtils.getId(resource), + ResourceUtils.getEntity(resource).getName())) + .collectMap(function((id, name) -> id), + function((id, name) -> name)); + } + + private static Mono getApplication( + CloudFoundryClient cloudFoundryClient, String application, String spaceId) { + return requestApplications(cloudFoundryClient, application, spaceId).single() + .onErrorResume(NoSuchElementException.class, + t -> ExceptionUtils.illegalArgument( + "Application %s does not exist", + application)); + } + + private static Mono getApplicationId(CloudFoundryClient cloudFoundryClient, + String application, String spaceId) { + return getApplication(cloudFoundryClient, application, spaceId) + .map(ResourceUtils::getId); + } + + private static Mono> getApplicationNames(CloudFoundryClient cloudFoundryClient, + String routeId) { + return requestApplications(cloudFoundryClient, routeId) + .map(resource -> ResourceUtils.getEntity(resource).getName()) + .collectList(); + } + + private static Mono> getDomain(CloudFoundryClient cloudFoundryClient, + String organizationId, String domain) { + return getDomains(cloudFoundryClient, organizationId, domain).single() + .onErrorResume(NoSuchElementException.class, + t -> ExceptionUtils.illegalArgument( + "Domain %s does not exist", + domain)); + } + + private static Mono getDomainId(CloudFoundryClient cloudFoundryClient, + String organizationId, String domain) { + return getDomain(cloudFoundryClient, organizationId, domain) + .map(ResourceUtils::getId); + } + + private static Mono getDomainName(Map domains, String domainId) { + return Mono.just(domains.get(domainId)); + } + + private static Flux> getDomains(CloudFoundryClient cloudFoundryClient, + String organizationId, String domain) { + return requestPrivateDomains(cloudFoundryClient, organizationId, domain) + .map((Function>) in -> in) + .switchIfEmpty(requestSharedDomains(cloudFoundryClient, domain)); + } + + private static Mono getOrCreateRoute( + CloudFoundryClient cloudFoundryClient, String organizationId, + String spaceId, String domain, String host, String path, Integer port, + Boolean randomPort) { + if (randomPort != null) { + return getDomainId(cloudFoundryClient, organizationId, domain).flatMap( + domainId -> requestCreateRoute(cloudFoundryClient, domainId, + host, path, port, randomPort, spaceId)); + } + + return getDomainId(cloudFoundryClient, organizationId, domain).flatMap( + domainId -> getRoute(cloudFoundryClient, domainId, host, path, port) + .cast(AbstractRouteResource.class) + .switchIfEmpty(requestCreateRoute( + cloudFoundryClient, domainId, host, + path, port, randomPort, spaceId))); + } + + private static Mono getRoute(CloudFoundryClient cloudFoundryClient, + String domainId, String domain, String host, String path, Integer port) { + return getRoute(cloudFoundryClient, domainId, host, path, port).switchIfEmpty( + ExceptionUtils.illegalArgument("Route for %s does not exist", + domain)); + } + + private static Mono getRoute(CloudFoundryClient cloudFoundryClient, + String domainId, String host, String path, Integer port) { + if (port != null) { + return requestRoutes(cloudFoundryClient, domainId, null, null, port) + .singleOrEmpty(); + } else { + return requestRoutes(cloudFoundryClient, domainId, host, path, port) + .filter(resource -> isIdentical(nullSafe(host), + ResourceUtils.getEntity(resource) + .getHost())) + .filter(resource -> isIdentical( + Optional.ofNullable(path).orElse(""), + ResourceUtils.getEntity(resource) + .getPath())) + .singleOrEmpty(); + } + } + + private static Mono getRouteId(CloudFoundryClient cloudFoundryClient, String host, + String domain, String domainId, String path, Integer port) { + return getRoute(cloudFoundryClient, domainId, domain, host, path, port) + .map(ResourceUtils::getId); + } + + private static Flux getRoutes(CloudFoundryClient cloudFoundryClient, + ListRoutesRequest request, Mono organizationId, + Mono spaceId) { + if (Level.ORGANIZATION == request.getLevel()) { + return organizationId.flatMapMany(organizationId1 -> requestRoutes( + cloudFoundryClient, + builder -> builder.organizationId(organizationId1))); + } else { + return spaceId.flatMapMany(spaceId1 -> requestSpaceRoutes( + cloudFoundryClient, spaceId1)); + } + } + + private static Mono> getServiceInstanceName( + CloudFoundryClient cloudFoundryClient, String serviceInstanceId, + String spaceId) { + return requestListSpaceServiceInstances(cloudFoundryClient, spaceId).filter( + resource -> serviceInstanceId.equals(ResourceUtils.getId(resource))) + .single().map(resource -> Optional + .of(ResourceUtils.getEntity(resource).getName())); + } + + private static Mono> getServiceName(CloudFoundryClient cloudFoundryClient, + RouteEntity route) { + return Mono.justOrEmpty(route.getServiceInstanceId()) + .flatMap(serviceInstanceId -> getServiceInstanceName( + cloudFoundryClient, serviceInstanceId, + route.getSpaceId())) + .defaultIfEmpty(Optional.empty()); + } + + private static Mono getSpace(CloudFoundryClient cloudFoundryClient, + String organizationId, String space) { + return requestSpaces(cloudFoundryClient, organizationId, space).single() + .onErrorResume(NoSuchElementException.class, t -> ExceptionUtils + .illegalArgument("Space %s does not exist", space)); + } + + private static Mono getSpaceId(CloudFoundryClient cloudFoundryClient, + String organizationId, String space) { + return getSpace(cloudFoundryClient, organizationId, space) + .map(ResourceUtils::getId); + } + + private static Mono getSpaceName(Map spaces, String spaceId) { + return Mono.just(spaces.get(spaceId)); + } + + private static boolean isIdentical(String s, String t) { + return s == null ? t == null : s.equals(t); + } + + private static String nullSafe(String host) { + return host == null ? "" : host; + } + + private static Flux requestAllPrivateDomains( + CloudFoundryClient cloudFoundryClient, String organizationId) { + return PaginationUtils.requestClientV2Resources(page -> cloudFoundryClient + .organizations() + .listPrivateDomains(ListOrganizationPrivateDomainsRequest.builder() + .organizationId(organizationId).page(page) + .build())); + } + + private static Flux requestAllSharedDomains( + CloudFoundryClient cloudFoundryClient) { + return PaginationUtils.requestClientV2Resources(page -> cloudFoundryClient + .sharedDomains() + .list(ListSharedDomainsRequest.builder().page(page).build())); + } + + private static Flux requestAllSpaces(CloudFoundryClient cloudFoundryClient, + String organizationId) { + return PaginationUtils + .requestClientV2Resources(page -> cloudFoundryClient.organizations() + .listSpaces(ListOrganizationSpacesRequest.builder() + .organizationId(organizationId) + .page(page).build())); + } + + private static Flux requestApplications( + CloudFoundryClient cloudFoundryClient, String routeId) { + return PaginationUtils.requestClientV2Resources(page -> cloudFoundryClient.routes() + .listApplications(ListRouteApplicationsRequest.builder() + .routeId(routeId).page(page).build())); + } + + private static Flux requestApplications( + CloudFoundryClient cloudFoundryClient, String application, String spaceId) { + return PaginationUtils.requestClientV2Resources(page -> cloudFoundryClient.spaces() + .listApplications(ListSpaceApplicationsRequest.builder() + .name(application).page(page).spaceId(spaceId) + .build())); + } + + private static Mono requestAssociateRoute( + CloudFoundryClient cloudFoundryClient, String applicationId, + String routeId) { + return cloudFoundryClient.applicationsV2() + .associateRoute(AssociateApplicationRouteRequest.builder() + .applicationId(applicationId).routeId(routeId) + .build()); + } + + private static Mono requestCreateRoute( + CloudFoundryClient cloudFoundryClient, String domainId, String host, + String path, Integer port, Boolean randomPort, String spaceId) { + + org.cloudfoundry.client.v2.routes.CreateRouteRequest.Builder builder = + org.cloudfoundry.client.v2.routes.CreateRouteRequest.builder(); + + if (randomPort != null && randomPort) { + builder.generatePort(true); + } else if (port != null) { + builder.port(port); + } else { + builder.host(host); + builder.path(path); + } + + return cloudFoundryClient.routes() + .create(builder.domainId(domainId).spaceId(spaceId).build()); + } + + private static Mono deleteRoute(CloudFoundryClient cloudFoundryClient, + Duration completionTimeout, String routeId) { + return requestDeleteRoute(cloudFoundryClient, routeId).flatMap(job -> JobUtils + .waitForCompletion(cloudFoundryClient, completionTimeout, job)); + } + + private static Mono requestDeleteRoute(CloudFoundryClient cloudFoundryClient, + String routeId) { + return cloudFoundryClient.routesV3() + .delete(org.cloudfoundry.client.v3.routes.DeleteRouteRequest + .builder().routeId(routeId).build()); + } + + private static Flux requestListSpaceServiceInstances( + CloudFoundryClient cloudFoundryClient, String spaceId) { + return PaginationUtils.requestClientV2Resources(page -> cloudFoundryClient.spaces() + .listServiceInstances(ListSpaceServiceInstancesRequest.builder() + .page(page).returnUserProvidedServiceInstances(true) + .spaceId(spaceId).build())); + } + + private static Flux requestPrivateDomains( + CloudFoundryClient cloudFoundryClient, String organizationId, + String domain) { + return PaginationUtils.requestClientV2Resources(page -> cloudFoundryClient + .organizations() + .listPrivateDomains(ListOrganizationPrivateDomainsRequest.builder() + .organizationId(organizationId).name(domain) + .page(page).build())); + } + + private static Mono requestRemoveRouteFromApplication( + CloudFoundryClient cloudFoundryClient, String applicationId, + String routeId) { + return cloudFoundryClient.applicationsV2().removeRoute(RemoveApplicationRouteRequest + .builder().applicationId(applicationId).routeId(routeId).build()); + } + + private static Flux requestRoutes(CloudFoundryClient cloudFoundryClient, + UnaryOperator modifier) { + + org.cloudfoundry.client.v2.routes.ListRoutesRequest.Builder listBuilder = + modifier.apply(org.cloudfoundry.client.v2.routes.ListRoutesRequest + .builder()); + + return PaginationUtils.requestClientV2Resources(page -> cloudFoundryClient.routes() + .list(listBuilder.page(page).build())); + } + + private static Flux requestRoutes(CloudFoundryClient cloudFoundryClient, + String domainId, String host, String path, Integer port) { + return requestRoutes(cloudFoundryClient, builder -> builder.domainId(domainId) + .hosts(Optional.ofNullable(host).map(Collections::singletonList) + .orElse(null)) + .paths(Optional.ofNullable(path).map(Collections::singletonList) + .orElse(null)) + .port(Optional.ofNullable(port).orElse(null))); + } + + private static Flux requestSharedDomains( + CloudFoundryClient cloudFoundryClient, String domain) { + return PaginationUtils.requestClientV2Resources(page -> cloudFoundryClient + .sharedDomains().list(ListSharedDomainsRequest.builder() + .name(domain).page(page).build())); + } + + private static Flux requestSpaceRoutes(CloudFoundryClient cloudFoundryClient, + String spaceId) { + return PaginationUtils.requestClientV2Resources(page -> cloudFoundryClient.spaces() + .listRoutes(ListSpaceRoutesRequest.builder().spaceId(spaceId) + .page(page).build())); + } + + private static Flux requestSpaces(CloudFoundryClient cloudFoundryClient, + String organizationId, String space) { + return PaginationUtils + .requestClientV2Resources(page -> cloudFoundryClient.organizations() + .listSpaces(ListOrganizationSpacesRequest.builder() + .organizationId(organizationId) + .name(space).page(page).build())); + } + + private static Route toRoute(List applications, String domain, + RouteResource resource, Optional service, String space) { + RouteEntity entity = ResourceUtils.getEntity(resource); + Route.Builder builder = Route.builder().applications(applications).domain(domain) + .host(entity.getHost()).id(ResourceUtils.getId(resource)) + .path(entity.getPath()).space(space); + + service.ifPresent(builder::service); + + return builder.build(); + } } diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java index 4efb6e4b9d..d2ddf8b47e 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java @@ -1,17 +1,15 @@ /* * Copyright 2013-2021 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 + * 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 + * 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. + * 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.operations; @@ -20,14 +18,18 @@ import org.cloudfoundry.client.v2.applications.ApplicationsV2; import org.cloudfoundry.client.v2.buildpacks.Buildpacks; import org.cloudfoundry.client.v2.domains.Domains; +import org.cloudfoundry.client.v3.domains.DomainsV3; import org.cloudfoundry.client.v2.events.Events; import org.cloudfoundry.client.v2.featureflags.FeatureFlags; import org.cloudfoundry.client.v2.jobs.Jobs; +import org.cloudfoundry.client.v3.jobs.JobsV3; import org.cloudfoundry.client.v2.organizationquotadefinitions.OrganizationQuotaDefinitions; import org.cloudfoundry.client.v2.organizations.Organizations; +import org.cloudfoundry.client.v3.organizations.OrganizationsV3; import org.cloudfoundry.client.v2.privatedomains.PrivateDomains; import org.cloudfoundry.client.v2.resourcematch.ResourceMatch; import org.cloudfoundry.client.v2.routes.Routes; +import org.cloudfoundry.client.v3.routes.RoutesV3; import org.cloudfoundry.client.v2.servicebindings.ServiceBindingsV2; import org.cloudfoundry.client.v2.servicebrokers.ServiceBrokers; import org.cloudfoundry.client.v2.serviceinstances.ServiceInstances; @@ -38,6 +40,7 @@ import org.cloudfoundry.client.v2.shareddomains.SharedDomains; import org.cloudfoundry.client.v2.spacequotadefinitions.SpaceQuotaDefinitions; import org.cloudfoundry.client.v2.spaces.Spaces; +import org.cloudfoundry.client.v3.spaces.SpacesV3; import org.cloudfoundry.client.v2.stacks.Stacks; import org.cloudfoundry.client.v2.userprovidedserviceinstances.UserProvidedServiceInstances; import org.cloudfoundry.client.v2.users.Users; @@ -58,13 +61,17 @@ public abstract class AbstractOperationsTest { - protected static final Mono MISSING_ID = Mono.error(new java.lang.IllegalStateException("MISSING_ID")); + protected static final Mono MISSING_ID = + Mono.error(new java.lang.IllegalStateException("MISSING_ID")); - protected static final Mono MISSING_ORGANIZATION_ID = Mono.error(new java.lang.IllegalStateException("MISSING_ORGANIZATION_ID")); + protected static final Mono MISSING_ORGANIZATION_ID = + Mono.error(new java.lang.IllegalStateException("MISSING_ORGANIZATION_ID")); - protected static final Mono MISSING_SPACE_ID = Mono.error(new java.lang.IllegalStateException("MISSING_SPACE_ID")); + protected static final Mono MISSING_SPACE_ID = + Mono.error(new java.lang.IllegalStateException("MISSING_SPACE_ID")); - protected static final Mono MISSING_USERNAME = Mono.error(new java.lang.IllegalStateException("MISSING_USERNAME")); + protected static final Mono MISSING_USERNAME = + Mono.error(new java.lang.IllegalStateException("MISSING_USERNAME")); protected static final String TEST_ORGANIZATION_ID = "test-organization-id"; @@ -84,9 +91,11 @@ public abstract class AbstractOperationsTest { protected final Buildpacks buildpacks = mock(Buildpacks.class, RETURNS_SMART_NULLS); - protected final CloudFoundryClient cloudFoundryClient = mock(CloudFoundryClient.class, RETURNS_SMART_NULLS); + protected final CloudFoundryClient cloudFoundryClient = + mock(CloudFoundryClient.class, RETURNS_SMART_NULLS); protected final Domains domains = mock(Domains.class, RETURNS_SMART_NULLS); + protected final DomainsV3 domainsV3 = mock(DomainsV3.class, RETURNS_SMART_NULLS); protected final DopplerClient dopplerClient = mock(DopplerClient.class, RETURNS_SMART_NULLS); @@ -95,10 +104,14 @@ public abstract class AbstractOperationsTest { protected final FeatureFlags featureFlags = mock(FeatureFlags.class, RETURNS_SMART_NULLS); protected final Jobs jobs = mock(Jobs.class, RETURNS_SMART_NULLS); + protected final JobsV3 jobsV3 = mock(JobsV3.class, RETURNS_SMART_NULLS); - protected final OrganizationQuotaDefinitions organizationQuotaDefinitions = mock(OrganizationQuotaDefinitions.class, RETURNS_SMART_NULLS); + protected final OrganizationQuotaDefinitions organizationQuotaDefinitions = + mock(OrganizationQuotaDefinitions.class, RETURNS_SMART_NULLS); protected final Organizations organizations = mock(Organizations.class, RETURNS_SMART_NULLS); + protected final OrganizationsV3 organizationsV3 = + mock(OrganizationsV3.class, RETURNS_SMART_NULLS); protected final PrivateDomains privateDomains = mock(PrivateDomains.class, RETURNS_SMART_NULLS); @@ -107,18 +120,22 @@ public abstract class AbstractOperationsTest { protected final RouterGroups routerGroups = mock(RouterGroups.class, RETURNS_SMART_NULLS); protected final Routes routes = mock(Routes.class, RETURNS_SMART_NULLS); + protected final RoutesV3 routesV3 = mock(RoutesV3.class, RETURNS_SMART_NULLS); protected final RoutingClient routingClient = mock(RoutingClient.class, RETURNS_SMART_NULLS); - protected final ServiceBindingsV2 serviceBindingsV2 = mock(ServiceBindingsV2.class, RETURNS_SMART_NULLS); + protected final ServiceBindingsV2 serviceBindingsV2 = + mock(ServiceBindingsV2.class, RETURNS_SMART_NULLS); protected final ServiceBrokers serviceBrokers = mock(ServiceBrokers.class, RETURNS_SMART_NULLS); - protected final ServiceInstances serviceInstances = mock(ServiceInstances.class, RETURNS_SMART_NULLS); + protected final ServiceInstances serviceInstances = + mock(ServiceInstances.class, RETURNS_SMART_NULLS); protected final ServiceKeys serviceKeys = mock(ServiceKeys.class, RETURNS_SMART_NULLS); - protected final ServicePlanVisibilities servicePlanVisibilities = mock(ServicePlanVisibilities.class, RETURNS_SMART_NULLS); + protected final ServicePlanVisibilities servicePlanVisibilities = + mock(ServicePlanVisibilities.class, RETURNS_SMART_NULLS); protected final ServicePlans servicePlans = mock(ServicePlans.class, RETURNS_SMART_NULLS); @@ -126,9 +143,11 @@ public abstract class AbstractOperationsTest { protected final SharedDomains sharedDomains = mock(SharedDomains.class, RETURNS_SMART_NULLS); - protected final SpaceQuotaDefinitions spaceQuotaDefinitions = mock(SpaceQuotaDefinitions.class, RETURNS_SMART_NULLS); + protected final SpaceQuotaDefinitions spaceQuotaDefinitions = + mock(SpaceQuotaDefinitions.class, RETURNS_SMART_NULLS); protected final Spaces spaces = mock(Spaces.class, RETURNS_SMART_NULLS); + protected final SpacesV3 spacesV3 = mock(SpacesV3.class, RETURNS_SMART_NULLS); protected final Stacks stacks = mock(Stacks.class, RETURNS_SMART_NULLS); @@ -138,9 +157,11 @@ public abstract class AbstractOperationsTest { protected final UaaClient uaaClient = mock(UaaClient.class, RETURNS_SMART_NULLS); - protected final org.cloudfoundry.uaa.users.Users uaaUsers = mock(org.cloudfoundry.uaa.users.Users.class, RETURNS_SMART_NULLS); + protected final org.cloudfoundry.uaa.users.Users uaaUsers = + mock(org.cloudfoundry.uaa.users.Users.class, RETURNS_SMART_NULLS); - protected final UserProvidedServiceInstances userProvidedServiceInstances = mock(UserProvidedServiceInstances.class, RETURNS_SMART_NULLS); + protected final UserProvidedServiceInstances userProvidedServiceInstances = + mock(UserProvidedServiceInstances.class, RETURNS_SMART_NULLS); protected final Users users = mock(Users.class, RETURNS_SMART_NULLS); @@ -150,14 +171,18 @@ public final void mockClient() { when(this.cloudFoundryClient.applicationsV3()).thenReturn(this.applicationsV3); when(this.cloudFoundryClient.buildpacks()).thenReturn(this.buildpacks); when(this.cloudFoundryClient.domains()).thenReturn(this.domains); + when(this.cloudFoundryClient.domainsV3()).thenReturn(this.domainsV3); when(this.cloudFoundryClient.events()).thenReturn(this.events); when(this.cloudFoundryClient.featureFlags()).thenReturn(this.featureFlags); when(this.cloudFoundryClient.jobs()).thenReturn(this.jobs); + when(this.cloudFoundryClient.jobsV3()).thenReturn(this.jobsV3); when(this.cloudFoundryClient.organizations()).thenReturn(this.organizations); + when(this.cloudFoundryClient.organizationsV3()).thenReturn(this.organizationsV3); when(this.cloudFoundryClient.organizationQuotaDefinitions()).thenReturn(this.organizationQuotaDefinitions); when(this.cloudFoundryClient.privateDomains()).thenReturn(this.privateDomains); when(this.cloudFoundryClient.resourceMatch()).thenReturn(this.resourceMatch); when(this.cloudFoundryClient.routes()).thenReturn(this.routes); + when(this.cloudFoundryClient.routesV3()).thenReturn(this.routesV3); when(this.cloudFoundryClient.serviceBindingsV2()).thenReturn(this.serviceBindingsV2); when(this.cloudFoundryClient.serviceBrokers()).thenReturn(this.serviceBrokers); when(this.cloudFoundryClient.serviceInstances()).thenReturn(this.serviceInstances); @@ -168,6 +193,7 @@ public final void mockClient() { when(this.cloudFoundryClient.sharedDomains()).thenReturn(this.sharedDomains); when(this.cloudFoundryClient.spaceQuotaDefinitions()).thenReturn(this.spaceQuotaDefinitions); when(this.cloudFoundryClient.spaces()).thenReturn(this.spaces); + when(this.cloudFoundryClient.spacesV3()).thenReturn(this.spacesV3); when(this.cloudFoundryClient.stacks()).thenReturn(this.stacks); when(this.cloudFoundryClient.tasks()).thenReturn(this.tasks); when(this.cloudFoundryClient.userProvidedServiceInstances()).thenReturn(this.userProvidedServiceInstances); diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/routes/DefaultRoutesTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/routes/DefaultRoutesTest.java index 31e015f1ec..c86ce38a62 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/routes/DefaultRoutesTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/routes/DefaultRoutesTest.java @@ -1,48 +1,39 @@ /* * Copyright 2013-2021 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 + * 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 + * 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. + * 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.operations.routes; import org.cloudfoundry.client.CloudFoundryClient; -import org.cloudfoundry.client.v2.ClientV2Exception; import org.cloudfoundry.client.v2.Metadata; import org.cloudfoundry.client.v2.applications.ApplicationResource; import org.cloudfoundry.client.v2.applications.AssociateApplicationRouteRequest; import org.cloudfoundry.client.v2.applications.AssociateApplicationRouteResponse; import org.cloudfoundry.client.v2.applications.RemoveApplicationRouteRequest; -import org.cloudfoundry.client.v2.jobs.ErrorDetails; -import org.cloudfoundry.client.v2.jobs.GetJobRequest; -import org.cloudfoundry.client.v2.jobs.GetJobResponse; -import org.cloudfoundry.client.v2.jobs.JobEntity; +import org.cloudfoundry.client.v3.jobs.GetJobRequest; +import org.cloudfoundry.client.v3.jobs.GetJobResponse; +import org.cloudfoundry.client.v3.jobs.JobState; import org.cloudfoundry.client.v2.organizations.ListOrganizationPrivateDomainsRequest; import org.cloudfoundry.client.v2.organizations.ListOrganizationPrivateDomainsResponse; import org.cloudfoundry.client.v2.organizations.ListOrganizationSpacesRequest; import org.cloudfoundry.client.v2.organizations.ListOrganizationSpacesResponse; import org.cloudfoundry.client.v2.privatedomains.PrivateDomainResource; import org.cloudfoundry.client.v2.routes.CreateRouteResponse; -import org.cloudfoundry.client.v2.routes.DeleteRouteResponse; import org.cloudfoundry.client.v2.routes.ListRouteApplicationsRequest; import org.cloudfoundry.client.v2.routes.ListRouteApplicationsResponse; import org.cloudfoundry.client.v2.routes.ListRoutesResponse; import org.cloudfoundry.client.v2.routes.RouteEntity; -import org.cloudfoundry.client.v2.routes.RouteExistsRequest; import org.cloudfoundry.client.v2.routes.RouteResource; -import org.cloudfoundry.client.v2.serviceinstances.GetServiceInstanceRequest; -import org.cloudfoundry.client.v2.serviceinstances.GetServiceInstanceResponse; -import org.cloudfoundry.client.v2.serviceinstances.ServiceInstanceResource; import org.cloudfoundry.client.v2.serviceinstances.UnionServiceInstanceEntity; import org.cloudfoundry.client.v2.serviceinstances.UnionServiceInstanceResource; import org.cloudfoundry.client.v2.shareddomains.ListSharedDomainsRequest; @@ -56,94 +47,92 @@ import org.cloudfoundry.client.v2.spaces.ListSpaceServiceInstancesResponse; import org.cloudfoundry.client.v2.spaces.SpaceEntity; import org.cloudfoundry.client.v2.spaces.SpaceResource; +import org.cloudfoundry.client.v3.domains.CheckReservedRoutesRequest; +import org.cloudfoundry.client.v3.domains.CheckReservedRoutesResponse; +import org.cloudfoundry.client.v3.organizations.ListOrganizationDomainsRequest; +import org.cloudfoundry.client.v3.organizations.ListOrganizationDomainsResponse; +import org.cloudfoundry.client.v3.Pagination; +import org.cloudfoundry.client.v3.Relationship; +import org.cloudfoundry.client.v3.ToManyRelationship; +import org.cloudfoundry.client.v3.ToOneRelationship; +import org.cloudfoundry.client.v3.domains.DomainRelationships; +import org.cloudfoundry.client.v3.domains.DomainResource; +import org.cloudfoundry.client.v3.spaces.DeleteUnmappedRoutesRequest; + import org.cloudfoundry.operations.AbstractOperationsTest; import org.junit.Test; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; -import reactor.test.scheduler.VirtualTimeScheduler; - import java.time.Duration; -import java.util.Arrays; import java.util.Collections; -import java.util.LinkedList; import java.util.Optional; -import java.util.Queue; -import java.util.function.Supplier; import static org.assertj.core.api.Assertions.assertThat; import static org.cloudfoundry.operations.TestObjects.fill; import static org.mockito.Mockito.when; -public final class DefaultRoutesTest extends AbstractOperationsTest { - private final DefaultRoutes routes = new DefaultRoutes(Mono.just(this.cloudFoundryClient), Mono.just(TEST_ORGANIZATION_ID), Mono.just(TEST_SPACE_ID)); +public final class DefaultRoutesTest extends AbstractOperationsTest { - @Test - public void checkRouteInvalidDomain() { - requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestSharedDomainsEmpty(this.cloudFoundryClient, "test-domain"); + private final DefaultRoutes routes = new DefaultRoutes(Mono.just(this.cloudFoundryClient), + Mono.just(TEST_ORGANIZATION_ID), Mono.just(TEST_SPACE_ID)); + private static final String TEST_DOMAIN_ID = "3a5d3d89-3f89-4f05-8188-8a2b298c79d5"; + private static final String TEST_DOMAIN_NAME = "domain-name"; + private static final String TEST_PATH = "test-path"; + private static final String TEST_HOST = "192.168.0,.1"; - this.routes - .check(CheckRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .build()) - .as(StepVerifier::create) - .expectNext(false) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } + private static final String TEST_JOB_ID = "test-job-id"; @Test - public void checkRouteInvalidHost() { - requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRouteExistsFalse(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path"); + public void checkRoute() { + mockListDomains(this.cloudFoundryClient); + mockCheckReservedRoutes(this.cloudFoundryClient); this.routes - .check(CheckRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectNext(false) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - public void checkRoutePrivateDomain() { - requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRouteExistsTrue(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path"); + .check(CheckRouteRequest.builder().host(TEST_HOST).path(TEST_PATH) + .domain(TEST_DOMAIN_NAME).build()) + .as(StepVerifier::create).expectNext(true).expectComplete() + .verify(Duration.ofSeconds(5)); - this.routes - .check(CheckRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectNext(true) - .expectComplete() - .verify(Duration.ofSeconds(5)); } - @Test - public void checkRouteSharedDomain() { - requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestSharedDomains(this.cloudFoundryClient, "test-domain"); - requestRouteExistsTrue(this.cloudFoundryClient, "test-shared-domain-metadata-id", "test-host", "test-path"); + private static void mockCheckReservedRoutes(CloudFoundryClient cloudFoundryClient){ + when(cloudFoundryClient.domainsV3().checkReservedRoutes(CheckReservedRoutesRequest.builder() + .domainId(TEST_DOMAIN_ID) + .host(TEST_HOST) + .path(TEST_PATH) + .build())) + .thenReturn(Mono.just( + CheckReservedRoutesResponse.builder().matchingRoute(true).build())); + } - this.routes - .check(CheckRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectNext(true) - .expectComplete() - .verify(Duration.ofSeconds(5)); + private static void mockListDomains(CloudFoundryClient cloudFoundryClient){ + when(cloudFoundryClient.organizationsV3().listDomains( + ListOrganizationDomainsRequest.builder() + .name(TEST_DOMAIN_NAME) + .page(1) + .organizationId(TEST_ORGANIZATION_ID).build())) + .thenReturn(Mono.just( ListOrganizationDomainsResponse.builder() + .pagination(Pagination.builder() + .totalResults(1) + .totalPages(1) + .build()) + .resource(DomainResource.builder() + .id(TEST_DOMAIN_ID) + .createdAt("2019-03-08T01:06:19Z") + .updatedAt("2019-03-08T01:06:19Z") + .name(TEST_DOMAIN_NAME) + .isInternal(false) + .relationships(DomainRelationships.builder() + .organization(ToOneRelationship.builder() + .data(Relationship.builder() + .id(TEST_ORGANIZATION_ID) + .build()) + .build()) + .sharedOrganizations(ToManyRelationship.builder().build()) + .build()) + .build()) + .build())); } @Test @@ -151,18 +140,14 @@ public void createRouteAssignedPort() { requestSpaces(this.cloudFoundryClient, TEST_ORGANIZATION_ID, TEST_SPACE_NAME); requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); requestSharedDomains(this.cloudFoundryClient, "test-domain"); - requestCreateRoute(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, null, null, 9999, "test-space-id"); + requestCreateRoute(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, null, + null, 9999, "test-space-id"); this.routes - .create(CreateRouteRequest.builder() - .domain("test-domain") - .port(9999) - .space(TEST_SPACE_NAME) - .build()) - .as(StepVerifier::create) - .expectNext(1) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .create(CreateRouteRequest.builder().domain("test-domain").port(9999) + .space(TEST_SPACE_NAME).build()) + .as(StepVerifier::create).expectNext(1).expectComplete() + .verify(Duration.ofSeconds(5)); } @Test @@ -172,14 +157,12 @@ public void createRouteInvalidDomain() { requestSharedDomainsEmpty(this.cloudFoundryClient, "test-domain"); this.routes - .create(CreateRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .space(TEST_SPACE_NAME) - .build()) - .as(StepVerifier::create) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("Domain test-domain does not exist")) - .verify(Duration.ofSeconds(5)); + .create(CreateRouteRequest.builder().domain("test-domain").host("test-host") + .space(TEST_SPACE_NAME).build()) + .as(StepVerifier::create) + .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Domain test-domain does not exist")) + .verify(Duration.ofSeconds(5)); } @Test @@ -188,70 +171,54 @@ public void createRouteInvalidSpace() { requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); this.routes - .create(CreateRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .space(TEST_SPACE_NAME) - .build()) - .as(StepVerifier::create) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("Space test-space-name does not exist")) - .verify(Duration.ofSeconds(5)); + .create(CreateRouteRequest.builder().domain("test-domain").host("test-host") + .path("test-path").space(TEST_SPACE_NAME).build()) + .as(StepVerifier::create) + .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Space test-space-name does not exist")) + .verify(Duration.ofSeconds(5)); } @Test public void createRouteNoHost() { requestSpaces(this.cloudFoundryClient, TEST_ORGANIZATION_ID, TEST_SPACE_NAME); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", null, null, "test-path", null, "test-space-id"); + requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", null, null, + "test-path", null, "test-space-id"); this.routes - .create(CreateRouteRequest.builder() - .domain("test-domain") - .path("test-path") - .space(TEST_SPACE_NAME) - .build()) - .as(StepVerifier::create) - .expectNext(1) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .create(CreateRouteRequest.builder().domain("test-domain").path("test-path") + .space(TEST_SPACE_NAME).build()) + .as(StepVerifier::create).expectNext(1).expectComplete() + .verify(Duration.ofSeconds(5)); } @Test public void createRouteNoPath() { requestSpaces(this.cloudFoundryClient, TEST_ORGANIZATION_ID, TEST_SPACE_NAME); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", null, null, null, "test-space-id"); + requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + null, null, null, "test-space-id"); this.routes - .create(CreateRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .space(TEST_SPACE_NAME) - .build()) - .as(StepVerifier::create) - .expectNext(1) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .create(CreateRouteRequest.builder().domain("test-domain").host("test-host") + .space(TEST_SPACE_NAME).build()) + .as(StepVerifier::create).expectNext(1).expectComplete() + .verify(Duration.ofSeconds(5)); } @Test public void createRoutePrivateDomain() { requestSpaces(this.cloudFoundryClient, TEST_ORGANIZATION_ID, TEST_SPACE_NAME); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", null, "test-path", null, "test-space-id"); + requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + null, "test-path", null, "test-space-id"); this.routes - .create(CreateRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .space(TEST_SPACE_NAME) - .build()) - .as(StepVerifier::create) - .expectNext(1) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .create(CreateRouteRequest.builder().domain("test-domain").host("test-host") + .path("test-path").space(TEST_SPACE_NAME).build()) + .as(StepVerifier::create).expectNext(1).expectComplete() + .verify(Duration.ofSeconds(5)); } @Test @@ -259,190 +226,54 @@ public void createRouteRandomPort() { requestSpaces(this.cloudFoundryClient, TEST_ORGANIZATION_ID, TEST_SPACE_NAME); requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); requestSharedDomains(this.cloudFoundryClient, "test-domain"); - requestCreateRoute(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, true, null, null, "test-space-id"); + requestCreateRoute(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, true, + null, null, "test-space-id"); this.routes - .create(CreateRouteRequest.builder() - .domain("test-domain") - .randomPort(true) - .space(TEST_SPACE_NAME) - .build()) - .as(StepVerifier::create) - .expectNext(1) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .create(CreateRouteRequest.builder().domain("test-domain").randomPort(true) + .space(TEST_SPACE_NAME).build()) + .as(StepVerifier::create).expectNext(1).expectComplete() + .verify(Duration.ofSeconds(5)); } @Test - public void deleteAssignedPort() { - requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestSharedDomains(this.cloudFoundryClient, "test-domain"); - requestRoutes(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, null, 9999); - requestDeleteRoute(this.cloudFoundryClient, "test-route-id"); - requestJobSuccess(this.cloudFoundryClient, "test-job-entity-id"); + public void deleteOrphanedRoutes() { + mockDeleteOrphanedRoutes(this.cloudFoundryClient); - StepVerifier.withVirtualTime(() -> this.routes - .delete(DeleteRouteRequest.builder() - .domain("test-domain") - .port(9999) - .build())) - .then(() -> VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(3))) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - public void deleteFailure() { - requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutes(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path", null); - requestDeleteRoute(this.cloudFoundryClient, "test-route-id"); - requestJobFailure(this.cloudFoundryClient, "test-job-entity-id"); - - StepVerifier.withVirtualTime(() -> this.routes - .delete(DeleteRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .build())) - .then(() -> VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(3))) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(ClientV2Exception.class).hasMessage("test-error-details-errorCode(1): test-error-details-description")) - .verify(Duration.ofSeconds(5)); + this.routes.deleteOrphanedRoutes(DeleteOrphanedRoutesRequest.builder().build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } - @Test - public void deleteInvalidDomain() { - requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestSharedDomainsEmpty(this.cloudFoundryClient, "test-domain"); - - this.routes - .delete(DeleteRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("Domain test-domain does not exist")) - .verify(Duration.ofSeconds(5)); + private static void mockDeleteOrphanedRoutes(CloudFoundryClient cloudFoundryClient){ + when(cloudFoundryClient.spacesV3() + .deleteUnmappedRoutes(DeleteUnmappedRoutesRequest.builder() + .spaceId(TEST_SPACE_ID) + .build())) + .thenReturn(Mono.just(TEST_JOB_ID)); + when(cloudFoundryClient.jobsV3().get( GetJobRequest.builder().jobId(TEST_JOB_ID).build())).thenReturn( + Mono.just(fill( GetJobResponse.builder()).state( JobState.COMPLETE).build())); } @Test - public void deleteInvalidRoute() { + public void deleteRoute() { requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutesEmpty(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path", null); - - this.routes - .delete(DeleteRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("Route for test-domain does not exist")) - .verify(Duration.ofSeconds(5)); - } - - @Test - public void deleteOrphanedRoutesAssociatedApplication() { - requestSpaceRoutes(this.cloudFoundryClient, TEST_SPACE_ID); - requestApplications(this.cloudFoundryClient, "test-route-id"); + requestRoutes(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + "test-path", null); + mockDeleteRequest(this.cloudFoundryClient, "test-route-id"); this.routes - .deleteOrphanedRoutes(DeleteOrphanedRoutesRequest.builder() - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .delete(DeleteRouteRequest.builder().host("test-host").path("test-path") + .domain("test-domain").build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } - @Test - public void deleteOrphanedRoutesAssociatedService() { - requestSpaceRoutesService(this.cloudFoundryClient, TEST_SPACE_ID); - - this.routes - .deleteOrphanedRoutes(DeleteOrphanedRoutesRequest.builder() - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - public void deleteOrphanedRoutesNoAssociations() { - requestSpaceRoutes(this.cloudFoundryClient, TEST_SPACE_ID); - requestApplicationsEmpty(this.cloudFoundryClient, "test-route-id"); - requestDeleteRoute(this.cloudFoundryClient, "test-route-id"); - requestJobSuccess(this.cloudFoundryClient, "test-job-entity-id"); - - StepVerifier.withVirtualTime(() -> this.routes - .deleteOrphanedRoutes(DeleteOrphanedRoutesRequest.builder() - .build())) - .then(() -> VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(3))) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - public void deleteOrphanedRoutesNoAssociationsFailure() { - requestSpaceRoutes(this.cloudFoundryClient, TEST_SPACE_ID); - requestApplicationsEmpty(this.cloudFoundryClient, "test-route-id"); - requestDeleteRoute(this.cloudFoundryClient, "test-route-id"); - requestJobFailure(this.cloudFoundryClient, "test-job-entity-id"); - - StepVerifier.withVirtualTime(() -> this.routes - .deleteOrphanedRoutes(DeleteOrphanedRoutesRequest.builder() - .build())) - .then(() -> VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(3))) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(ClientV2Exception.class).hasMessage("test-error-details-errorCode(1): test-error-details-description")) - .verify(Duration.ofSeconds(5)); - } - - @Test - public void deleteOrphanedRoutesNoRoutes() { - requestSpaceRoutesEmpty(this.cloudFoundryClient, TEST_SPACE_ID); - - this.routes - .deleteOrphanedRoutes(DeleteOrphanedRoutesRequest.builder() - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - public void deletePrivateDomain() { - requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutes(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path", null); - requestDeleteRoute(this.cloudFoundryClient, "test-route-id"); - requestJobSuccess(this.cloudFoundryClient, "test-job-entity-id"); - - StepVerifier.withVirtualTime(() -> this.routes - .delete(DeleteRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .build())) - .then(() -> VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(3))) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - public void deleteSharedDomain() { - requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestSharedDomains(this.cloudFoundryClient, "test-domain"); - requestRoutes(this.cloudFoundryClient, "test-shared-domain-metadata-id", "test-host", "test-path", null); - requestDeleteRoute(this.cloudFoundryClient, "test-route-id"); - requestJobSuccess(this.cloudFoundryClient, "test-job-entity-id"); - - StepVerifier.withVirtualTime(() -> this.routes - .delete(DeleteRouteRequest.builder() - .domain("test-domain") - .host("test-host") - .path("test-path") - .build())) - .then(() -> VirtualTimeScheduler.get().advanceTimeBy(Duration.ofSeconds(3))) - .expectComplete() - .verify(Duration.ofSeconds(5)); + private static void mockDeleteRequest(CloudFoundryClient cloudFoundryClient,String routeId){ + when(cloudFoundryClient.routesV3().delete(org.cloudfoundry.client.v3.routes.DeleteRouteRequest.builder() + .routeId(routeId) + .build())) + .thenReturn(Mono.just("test-delete-job")); + when(cloudFoundryClient.jobsV3().get(org.cloudfoundry.client.v3.jobs.GetJobRequest.builder().jobId("test-delete-job").build())).thenReturn( + Mono.just(fill(org.cloudfoundry.client.v3.jobs.GetJobResponse.builder()).state(org.cloudfoundry.client.v3.jobs.JobState.COMPLETE).build())); } @Test @@ -451,25 +282,18 @@ public void listCurrentOrganizationNoSpace() { requestPrivateDomainsAll(this.cloudFoundryClient, TEST_ORGANIZATION_ID); requestSharedDomainsAll(this.cloudFoundryClient); requestSpacesAll(this.cloudFoundryClient, TEST_ORGANIZATION_ID); - requestSpaceServiceInstances(this.cloudFoundryClient, "test-route-entity-serviceInstanceId", "test-route-entity-spaceId"); + requestSpaceServiceInstances(this.cloudFoundryClient, "test-route-entity-serviceInstanceId", + "test-route-entity-spaceId"); requestApplications(this.cloudFoundryClient, "test-id"); - this.routes - .list(ListRoutesRequest.builder() - .level(Level.ORGANIZATION) - .build()) - .as(StepVerifier::create) - .expectNext(Route.builder() - .application("test-application-name") - .domain("test-shared-domain-name") - .host("test-route-entity-host") - .id("test-id") - .path("test-route-entity-path") - .service("test-service-instance-entityname") - .space("test-space-entity-name") - .build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); + this.routes.list(ListRoutesRequest.builder().level(Level.ORGANIZATION).build()) + .as(StepVerifier::create) + .expectNext(Route.builder().application("test-application-name") + .domain("test-shared-domain-name").host("test-route-entity-host") + .id("test-id").path("test-route-entity-path") + .service("test-service-instance-entityname").space("test-space-entity-name") + .build()) + .expectComplete().verify(Duration.ofSeconds(5)); } @Test @@ -480,13 +304,8 @@ public void listCurrentOrganizationNoSpaceNoRoutes() { requestSpacesAll(this.cloudFoundryClient, TEST_ORGANIZATION_ID); requestApplications(this.cloudFoundryClient, "test-id"); - this.routes - .list(ListRoutesRequest.builder() - .level(Level.ORGANIZATION) - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + this.routes.list(ListRoutesRequest.builder().level(Level.ORGANIZATION).build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } @Test @@ -497,21 +316,13 @@ public void listCurrentSpace() { requestSpacesAll(this.cloudFoundryClient, TEST_ORGANIZATION_ID); requestApplications(this.cloudFoundryClient, "test-route-id"); - this.routes - .list(ListRoutesRequest.builder() - .level(Level.SPACE) - .build()) - .as(StepVerifier::create) - .expectNext(Route.builder() - .application("test-application-name") - .domain("test-shared-domain-name") - .host("test-route-entity-host") - .id("test-route-id") - .path("test-route-entity-path") - .space("test-space-entity-name") - .build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); + this.routes.list(ListRoutesRequest.builder().level(Level.SPACE).build()) + .as(StepVerifier::create) + .expectNext(Route.builder().application("test-application-name") + .domain("test-shared-domain-name").host("test-route-entity-host") + .id("test-route-id").path("test-route-entity-path") + .space("test-space-entity-name").build()) + .expectComplete().verify(Duration.ofSeconds(5)); } @Test @@ -522,20 +333,12 @@ public void listCurrentSpaceNoPath() { requestSpacesAll(this.cloudFoundryClient, TEST_ORGANIZATION_ID); requestApplications(this.cloudFoundryClient, "test-route-id"); - this.routes - .list(ListRoutesRequest.builder() - .level(Level.SPACE) - .build()) - .as(StepVerifier::create) - .expectNext(Route.builder() - .application("test-application-name") - .domain("test-shared-domain-name") - .host("test-route-entity-host") - .id("test-route-id") - .space("test-space-entity-name") - .build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); + this.routes.list(ListRoutesRequest.builder().level(Level.SPACE).build()) + .as(StepVerifier::create) + .expectNext(Route.builder().application("test-application-name") + .domain("test-shared-domain-name").host("test-route-entity-host") + .id("test-route-id").space("test-space-entity-name").build()) + .expectComplete().verify(Duration.ofSeconds(5)); } @Test @@ -543,58 +346,49 @@ public void mapRouteAssignedPort() { requestApplications(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); requestSharedDomains(this.cloudFoundryClient, "test-domain"); - requestRoutesEmpty(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, null, 9999); - requestCreateRoute(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, null, null, 9999, TEST_SPACE_ID); + requestRoutesEmpty(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, null, + 9999); + requestCreateRoute(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, null, + null, 9999, TEST_SPACE_ID); requestAssociateRoute(this.cloudFoundryClient, "test-application-id", "test-route-id"); this.routes - .map(MapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .port(9999) - .build()) - .as(StepVerifier::create) - .expectNext(9999) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .map(MapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").port(9999).build()) + .as(StepVerifier::create).expectNext(9999).expectComplete() + .verify(Duration.ofSeconds(5)); } @Test public void mapRouteExists() { requestApplications(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutes(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path", null); + requestRoutes(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + "test-path", null); requestAssociateRoute(this.cloudFoundryClient, "test-application-id", "test-route-id"); this.routes - .map(MapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .map(MapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").path("test-path").build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } @Test public void mapRouteInvalidApplicationName() { requestApplicationsEmpty(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutesEmpty(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path", null); - requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", null, "test-path", null, "test-space-id"); + requestRoutesEmpty(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + "test-path", null); + requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + null, "test-path", null, "test-space-id"); this.routes - .map(MapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("Application test-application-name does not exist")) - .verify(Duration.ofSeconds(5)); + .map(MapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").path("test-path").build()) + .as(StepVerifier::create) + .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Application test-application-name does not exist")) + .verify(Duration.ofSeconds(5)); } @Test @@ -604,73 +398,58 @@ public void mapRouteInvalidDomain() { requestSharedDomainsEmpty(this.cloudFoundryClient, "test-domain"); this.routes - .map(MapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("Domain test-domain does not exist")) - .verify(Duration.ofSeconds(5)); + .map(MapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").path("test-path").build()) + .as(StepVerifier::create) + .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Domain test-domain does not exist")) + .verify(Duration.ofSeconds(5)); } @Test public void mapRouteNoHost() { requestApplications(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutesEmpty(this.cloudFoundryClient, "test-private-domain-metadata-id", null, "test-path", null); - requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", null, null, "test-path", null, TEST_SPACE_ID); + requestRoutesEmpty(this.cloudFoundryClient, "test-private-domain-metadata-id", null, + "test-path", null); + requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", null, null, + "test-path", null, TEST_SPACE_ID); requestAssociateRoute(this.cloudFoundryClient, "test-application-id", "test-route-id"); this.routes - .map(MapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .map(MapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").path("test-path").build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } @Test public void mapRoutePath() { requestApplications(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutesTwo(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path"); + requestRoutesTwo(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + "test-path"); requestAssociateRoute(this.cloudFoundryClient, "test-application-id", "test-route-id"); this.routes - .map(MapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .map(MapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").path("test-path").build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } @Test public void mapRoutePrivateDomain() { requestApplications(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutesEmpty(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path", null); - requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", null, "test-path", null, TEST_SPACE_ID); + requestRoutesEmpty(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + "test-path", null); + requestCreateRoute(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + null, "test-path", null, TEST_SPACE_ID); requestAssociateRoute(this.cloudFoundryClient, "test-application-id", "test-route-id"); this.routes - .map(MapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .map(MapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").path("test-path").build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } @Test @@ -678,20 +457,16 @@ public void mapRouteSharedDomain() { requestApplications(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); requestSharedDomains(this.cloudFoundryClient, "test-domain"); - requestRoutesEmpty(this.cloudFoundryClient, "test-shared-domain-metadata-id", "test-host", "test-path", null); - requestCreateRoute(this.cloudFoundryClient, "test-shared-domain-metadata-id", "test-host", null, "test-path", null, TEST_SPACE_ID); + requestRoutesEmpty(this.cloudFoundryClient, "test-shared-domain-metadata-id", "test-host", + "test-path", null); + requestCreateRoute(this.cloudFoundryClient, "test-shared-domain-metadata-id", "test-host", + null, "test-path", null, TEST_SPACE_ID); requestAssociateRoute(this.cloudFoundryClient, "test-application-id", "test-route-id"); this.routes - .map(MapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .map(MapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").path("test-path").build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } @Test @@ -700,17 +475,13 @@ public void unmapRouteAssignedPort() { requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); requestSharedDomains(this.cloudFoundryClient, "test-domain"); requestRoutes(this.cloudFoundryClient, "test-shared-domain-metadata-id", null, null, 9999); - requestRemoveRouteFromApplication(this.cloudFoundryClient, "test-application-id", "test-route-id"); + requestRemoveRouteFromApplication(this.cloudFoundryClient, "test-application-id", + "test-route-id"); this.routes - .unmap(UnmapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .port(9999) - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .unmap(UnmapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").port(9999).build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } @Test @@ -719,14 +490,12 @@ public void unmapRouteInvalidApplicationName() { requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); this.routes - .unmap(UnmapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .build()) - .as(StepVerifier::create) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("Application test-application-name does not exist")) - .verify(Duration.ofSeconds(5)); + .unmap(UnmapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").build()) + .as(StepVerifier::create) + .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Application test-application-name does not exist")) + .verify(Duration.ofSeconds(5)); } @Test @@ -736,51 +505,43 @@ public void unmapRouteInvalidDomain() { requestSharedDomainsEmpty(this.cloudFoundryClient, "test-domain"); this.routes - .unmap(UnmapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .build()) - .as(StepVerifier::create) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("Domain test-domain does not exist")) - .verify(Duration.ofSeconds(5)); + .unmap(UnmapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").build()) + .as(StepVerifier::create) + .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Domain test-domain does not exist")) + .verify(Duration.ofSeconds(5)); } @Test public void unmapRouteInvalidRoute() { requestApplications(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutesEmpty(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path", null); + requestRoutesEmpty(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + "test-path", null); this.routes - .unmap(UnmapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class).hasMessage("Route for test-domain does not exist")) - .verify(Duration.ofSeconds(5)); + .unmap(UnmapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").path("test-path").build()) + .as(StepVerifier::create) + .consumeErrorWith(t -> assertThat(t).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Route for test-domain does not exist")) + .verify(Duration.ofSeconds(5)); } @Test public void unmapRoutePrivateDomain() { requestApplications(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomains(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); - requestRoutes(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", "test-path", null); - requestRemoveRouteFromApplication(this.cloudFoundryClient, "test-application-id", "test-route-id"); + requestRoutes(this.cloudFoundryClient, "test-private-domain-metadata-id", "test-host", + "test-path", null); + requestRemoveRouteFromApplication(this.cloudFoundryClient, "test-application-id", + "test-route-id"); this.routes - .unmap(UnmapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .unmap(UnmapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").path("test-path").build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } @Test @@ -788,19 +549,15 @@ public void unmapRouteSharedDomain() { requestApplications(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); requestPrivateDomainsEmpty(this.cloudFoundryClient, TEST_ORGANIZATION_ID, "test-domain"); requestSharedDomains(this.cloudFoundryClient, "test-domain"); - requestRoutes(this.cloudFoundryClient, "test-shared-domain-metadata-id", "test-host", "test-path", null); - requestRemoveRouteFromApplication(this.cloudFoundryClient, "test-application-id", "test-route-id"); + requestRoutes(this.cloudFoundryClient, "test-shared-domain-metadata-id", "test-host", + "test-path", null); + requestRemoveRouteFromApplication(this.cloudFoundryClient, "test-application-id", + "test-route-id"); this.routes - .unmap(UnmapRouteRequest.builder() - .applicationName("test-application-name") - .domain("test-domain") - .host("test-host") - .path("test-path") - .build()) - .as(StepVerifier::create) - .expectComplete() - .verify(Duration.ofSeconds(5)); + .unmap(UnmapRouteRequest.builder().applicationName("test-application-name") + .domain("test-domain").host("test-host").path("test-path").build()) + .as(StepVerifier::create).expectComplete().verify(Duration.ofSeconds(5)); } private static void requestApplications(CloudFoundryClient cloudFoundryClient, String routeId) { @@ -879,79 +636,6 @@ private static void requestCreateRoute(CloudFoundryClient cloudFoundryClient, St .build())); } - private static void requestDeleteRoute(CloudFoundryClient cloudFoundryClient, String routeId) { - when(cloudFoundryClient.routes() - .delete(org.cloudfoundry.client.v2.routes.DeleteRouteRequest.builder() - .async(true) - .routeId(routeId) - .build())) - .thenReturn(Mono - .just(fill(DeleteRouteResponse.builder()) - .entity(fill(JobEntity.builder(), "job-entity-") - .build()) - .build())); - } - - private static void requestJobFailure(CloudFoundryClient cloudFoundryClient, String jobId) { - when(cloudFoundryClient.jobs() - .get(GetJobRequest.builder() - .jobId(jobId) - .build())) - .thenReturn(Mono - .defer(new Supplier>() { - - private final Queue responses = new LinkedList<>(Arrays.asList( - fill(GetJobResponse.builder(), "job-") - .entity(fill(JobEntity.builder()) - .status("running") - .build()) - .build(), - fill(GetJobResponse.builder(), "job-") - .entity(fill(JobEntity.builder()) - .errorDetails(fill(ErrorDetails.builder(), "error-details-") - .build()) - .status("failed") - .build()) - .build() - )); - - @Override - public Mono get() { - return Mono.just(this.responses.poll()); - } - - })); - } - - private static void requestJobSuccess(CloudFoundryClient cloudFoundryClient, String jobId) { - when(cloudFoundryClient.jobs() - .get(GetJobRequest.builder() - .jobId(jobId) - .build())) - .thenReturn(Mono - .defer(new Supplier>() { - - private final Queue responses = new LinkedList<>(Arrays.asList( - fill(GetJobResponse.builder(), "job-") - .entity(fill(JobEntity.builder()) - .status("running") - .build()) - .build(), - fill(GetJobResponse.builder(), "job-") - .entity(fill(JobEntity.builder()) - .status("finished") - .build()) - .build() - )); - - @Override - public Mono get() { - return Mono.just(this.responses.poll()); - } - - })); - } - private static void requestOrganizationsRoutes(CloudFoundryClient cloudFoundryClient, String organizationId) { when(cloudFoundryClient.routes() .list(org.cloudfoundry.client.v2.routes.ListRoutesRequest.builder() @@ -1031,28 +715,6 @@ private static void requestRemoveRouteFromApplication(CloudFoundryClient cloudFo .thenReturn(Mono.empty()); } - private static void requestRouteExistsFalse(CloudFoundryClient cloudFoundryClient, String domainId, String host, String path) { - when(cloudFoundryClient.routes() - .exists(RouteExistsRequest.builder() - .domainId(domainId) - .host(host) - .path(path) - .build())) - .thenReturn(Mono - .just(false)); - } - - private static void requestRouteExistsTrue(CloudFoundryClient cloudFoundryClient, String domainId, String host, String path) { - when(cloudFoundryClient.routes() - .exists(RouteExistsRequest.builder() - .domainId(domainId) - .host(host) - .path(path) - .build())) - .thenReturn(Mono - .just(true)); - } - private static void requestRoutes(CloudFoundryClient cloudFoundryClient, String domainId, String host, String path, Integer port) { when(cloudFoundryClient.routes() .list(org.cloudfoundry.client.v2.routes.ListRoutesRequest.builder()