From 3354d2de537175a173ab69ea62cb8e81be3894d7 Mon Sep 17 00:00:00 2001 From: Stef Date: Tue, 4 Jul 2023 22:04:37 +0200 Subject: [PATCH 1/3] raise minimal compatible version to 3.41.0-01 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f996c26a..c71ab1a3 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ org.sonatype.nexus.plugins nexus-plugins - 3.39.0-01 + 3.41.0-01 composer-parent @@ -42,7 +42,7 @@ - 3.39.0-01 + 3.41.0-01 From 616bfcc7b9bdd33ec51e9bab678e7876337524d7 Mon Sep 17 00:00:00 2001 From: Stef Date: Tue, 4 Jul 2023 22:24:48 +0200 Subject: [PATCH 2/3] add API classes --- .../ComposerGroupRepositoriesApiResource.java | 58 +++++++++++++++++++ ...omposerGroupRepositoriesApiResourceV1.java | 15 +++++ .../ComposerGroupRepositoryApiRequest.java | 23 ++++++++ ...oryApiRequestToConfigurationConverter.java | 10 ++++ ...ComposerHostedRepositoriesApiResource.java | 58 +++++++++++++++++++ ...mposerHostedRepositoriesApiResourceV1.java | 14 +++++ .../ComposerHostedRepositoryApiRequest.java | 25 ++++++++ ...oryApiRequestToConfigurationConverter.java | 11 ++++ .../ComposerProxyRepositoriesApiResource.java | 57 ++++++++++++++++++ ...omposerProxyRepositoriesApiResourceV1.java | 16 +++++ .../ComposerProxyRepositoryApiRequest.java | 38 ++++++++++++ ...oryApiRequestToConfigurationConverter.java | 16 +++++ 12 files changed, 341 insertions(+) create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoriesApiResource.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoriesApiResourceV1.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoryApiRequest.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoryApiRequestToConfigurationConverter.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoriesApiResource.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoriesApiResourceV1.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoryApiRequest.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoryApiRequestToConfigurationConverter.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoriesApiResource.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoriesApiResourceV1.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoryApiRequest.java create mode 100644 nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoryApiRequestToConfigurationConverter.java diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoriesApiResource.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoriesApiResource.java new file mode 100644 index 00000000..9b0f58e0 --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoriesApiResource.java @@ -0,0 +1,58 @@ +package org.sonatype.nexus.repository.composer.rest; + +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import org.sonatype.nexus.repository.rest.api.AbstractGroupRepositoriesApiResource; +import org.sonatype.nexus.validation.Validate; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.shiro.authz.annotation.RequiresAuthentication; + +import static org.sonatype.nexus.rest.ApiDocConstants.API_REPOSITORY_MANAGEMENT; +import static org.sonatype.nexus.rest.ApiDocConstants.AUTHENTICATION_REQUIRED; +import static org.sonatype.nexus.rest.ApiDocConstants.INSUFFICIENT_PERMISSIONS; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_CREATED; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_UPDATED; + +@Api(value = API_REPOSITORY_MANAGEMENT) +public abstract class ComposerGroupRepositoriesApiResource extends AbstractGroupRepositoriesApiResource { + @ApiOperation("Create composer group repository") + @ApiResponses(value = { + @ApiResponse(code = 201, message = REPOSITORY_CREATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @POST + @RequiresAuthentication + @Validate + @Override + public Response createRepository(final ComposerGroupRepositoryApiRequest request) { + return super.createRepository(request); + } + + @ApiOperation("Update composer group repository") + @ApiResponses(value = { + @ApiResponse(code = 204, message = REPOSITORY_UPDATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @PUT + @Path("/{repositoryName}") + @RequiresAuthentication + @Validate + @Override + public Response updateRepository( + final ComposerGroupRepositoryApiRequest request, + @ApiParam(value = "Name of the repository to update") @PathParam("repositoryName") final String repositoryName) + { + return super.updateRepository(request, repositoryName); + } +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoriesApiResourceV1.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoriesApiResourceV1.java new file mode 100644 index 00000000..b128bb4a --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoriesApiResourceV1.java @@ -0,0 +1,15 @@ +package org.sonatype.nexus.repository.composer.rest; + +import javax.inject.Named; +import javax.inject.Singleton; +import javax.ws.rs.Path; + +import org.sonatype.nexus.repository.rest.api.RepositoriesApiResourceV1; + +@Named +@Singleton +@Path(ComposerGroupRepositoriesApiResourceV1.RESOURCE_URI) +public class ComposerGroupRepositoriesApiResourceV1 extends ComposerGroupRepositoriesApiResource +{ + static final String RESOURCE_URI = RepositoriesApiResourceV1.RESOURCE_URI + "/composer/group"; +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoryApiRequest.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoryApiRequest.java new file mode 100644 index 00000000..ac4df916 --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoryApiRequest.java @@ -0,0 +1,23 @@ +package org.sonatype.nexus.repository.composer.rest; + +import org.sonatype.nexus.repository.composer.internal.ComposerFormat; +import org.sonatype.nexus.repository.rest.api.model.GroupAttributes; +import org.sonatype.nexus.repository.rest.api.model.GroupRepositoryApiRequest; +import org.sonatype.nexus.repository.rest.api.model.StorageAttributes; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties({"format", "type"}) +public class ComposerGroupRepositoryApiRequest extends GroupRepositoryApiRequest { + @JsonCreator + public ComposerGroupRepositoryApiRequest( + @JsonProperty("name") final String name, + @JsonProperty("online") final Boolean online, + @JsonProperty("storage") final StorageAttributes storage, + @JsonProperty("group") final GroupAttributes group) { + super(name, ComposerFormat.NAME, online, storage, group); + } + +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoryApiRequestToConfigurationConverter.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoryApiRequestToConfigurationConverter.java new file mode 100644 index 00000000..03c3bc2a --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerGroupRepositoryApiRequestToConfigurationConverter.java @@ -0,0 +1,10 @@ +package org.sonatype.nexus.repository.composer.rest; + +import org.sonatype.nexus.repository.rest.GroupRepositoryApiRequestToConfigurationConverter; + +import javax.inject.Named; + +@Named +public class ComposerGroupRepositoryApiRequestToConfigurationConverter extends GroupRepositoryApiRequestToConfigurationConverter { + +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoriesApiResource.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoriesApiResource.java new file mode 100644 index 00000000..78109dfc --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoriesApiResource.java @@ -0,0 +1,58 @@ +package org.sonatype.nexus.repository.composer.rest; + +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import org.sonatype.nexus.repository.rest.api.AbstractHostedRepositoriesApiResource; +import org.sonatype.nexus.validation.Validate; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.shiro.authz.annotation.RequiresAuthentication; + +import static org.sonatype.nexus.rest.ApiDocConstants.API_REPOSITORY_MANAGEMENT; +import static org.sonatype.nexus.rest.ApiDocConstants.AUTHENTICATION_REQUIRED; +import static org.sonatype.nexus.rest.ApiDocConstants.INSUFFICIENT_PERMISSIONS; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_CREATED; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_UPDATED; + +@Api(value = API_REPOSITORY_MANAGEMENT) +public abstract class ComposerHostedRepositoriesApiResource extends AbstractHostedRepositoriesApiResource { + @ApiOperation("Create composer hosted repository") + @ApiResponses(value = { + @ApiResponse(code = 201, message = REPOSITORY_CREATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @POST + @RequiresAuthentication + @Validate + @Override + public Response createRepository(ComposerHostedRepositoryApiRequest request) { + return super.createRepository(request); + } + + @ApiOperation("Update composer hosted repository") + @ApiResponses(value = { + @ApiResponse(code = 204, message = REPOSITORY_UPDATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @PUT + @Path("/{repositoryName}") + @RequiresAuthentication + @Validate + @Override + public Response updateRepository( + final ComposerHostedRepositoryApiRequest request, + @ApiParam(value = "Name of the repository to update") @PathParam("repositoryName") final String repositoryName) + { + return super.updateRepository(request, repositoryName); + } +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoriesApiResourceV1.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoriesApiResourceV1.java new file mode 100644 index 00000000..02bf6a3f --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoriesApiResourceV1.java @@ -0,0 +1,14 @@ +package org.sonatype.nexus.repository.composer.rest; + +import javax.inject.Named; +import javax.inject.Singleton; +import javax.ws.rs.Path; + +import org.sonatype.nexus.repository.rest.api.RepositoriesApiResourceV1; + +@Named +@Singleton +@Path(ComposerHostedRepositoriesApiResourceV1.RESOURCE_URI) +public class ComposerHostedRepositoriesApiResourceV1 extends ComposerHostedRepositoriesApiResource { + static final String RESOURCE_URI = RepositoriesApiResourceV1.RESOURCE_URI + "/composer/hosted"; +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoryApiRequest.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoryApiRequest.java new file mode 100644 index 00000000..02205324 --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoryApiRequest.java @@ -0,0 +1,25 @@ +package org.sonatype.nexus.repository.composer.rest; + +import org.sonatype.nexus.repository.composer.internal.ComposerFormat; +import org.sonatype.nexus.repository.rest.api.model.CleanupPolicyAttributes; +import org.sonatype.nexus.repository.rest.api.model.ComponentAttributes; +import org.sonatype.nexus.repository.rest.api.model.HostedRepositoryApiRequest; +import org.sonatype.nexus.repository.rest.api.model.HostedStorageAttributes; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties({"format", "type"}) +public class ComposerHostedRepositoryApiRequest extends HostedRepositoryApiRequest { + @JsonCreator + public ComposerHostedRepositoryApiRequest( + @JsonProperty("name") final String name, + @JsonProperty("online") final Boolean online, + @JsonProperty("storage") final HostedStorageAttributes storage, + @JsonProperty("cleanup") final CleanupPolicyAttributes cleanup, + @JsonProperty("component") final ComponentAttributes componentAttributes) + { + super(name, ComposerFormat.NAME, online, storage, cleanup, componentAttributes); + } +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoryApiRequestToConfigurationConverter.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoryApiRequestToConfigurationConverter.java new file mode 100644 index 00000000..d77a6050 --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerHostedRepositoryApiRequestToConfigurationConverter.java @@ -0,0 +1,11 @@ +package org.sonatype.nexus.repository.composer.rest; + +import javax.inject.Named; + +import org.sonatype.nexus.repository.rest.api.HostedRepositoryApiRequestToConfigurationConverter; + +@Named +public class ComposerHostedRepositoryApiRequestToConfigurationConverter extends HostedRepositoryApiRequestToConfigurationConverter +{ + +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoriesApiResource.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoriesApiResource.java new file mode 100644 index 00000000..425a211a --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoriesApiResource.java @@ -0,0 +1,57 @@ +package org.sonatype.nexus.repository.composer.rest; + +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import org.sonatype.nexus.repository.rest.api.AbstractProxyRepositoriesApiResource; +import org.sonatype.nexus.validation.Validate; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.shiro.authz.annotation.RequiresAuthentication; + +import static org.sonatype.nexus.rest.ApiDocConstants.API_REPOSITORY_MANAGEMENT; +import static org.sonatype.nexus.rest.ApiDocConstants.AUTHENTICATION_REQUIRED; +import static org.sonatype.nexus.rest.ApiDocConstants.INSUFFICIENT_PERMISSIONS; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_CREATED; +import static org.sonatype.nexus.rest.ApiDocConstants.REPOSITORY_UPDATED; + +@Api(value = API_REPOSITORY_MANAGEMENT) +public abstract class ComposerProxyRepositoriesApiResource extends AbstractProxyRepositoriesApiResource { + @ApiOperation("Create composer proxy repository") + @ApiResponses(value = { + @ApiResponse(code = 201, message = REPOSITORY_CREATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @POST + @RequiresAuthentication + @Validate + @Override + public Response createRepository(final ComposerProxyRepositoryApiRequest request) { + return super.createRepository(request); + } + + @ApiOperation("Update composer proxy repository") + @ApiResponses(value = { + @ApiResponse(code = 204, message = REPOSITORY_UPDATED), + @ApiResponse(code = 401, message = AUTHENTICATION_REQUIRED), + @ApiResponse(code = 403, message = INSUFFICIENT_PERMISSIONS) + }) + @PUT + @Path("/{repositoryName}") + @RequiresAuthentication + @Validate + @Override + public Response updateRepository( + final ComposerProxyRepositoryApiRequest request, + @ApiParam(value = "Name of the repository to update") @PathParam("repositoryName") final String repositoryName) { + return super.updateRepository(request, repositoryName); + } +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoriesApiResourceV1.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoriesApiResourceV1.java new file mode 100644 index 00000000..1646c562 --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoriesApiResourceV1.java @@ -0,0 +1,16 @@ +package org.sonatype.nexus.repository.composer.rest; + +import javax.inject.Named; +import javax.inject.Singleton; +import javax.ws.rs.Path; + +import org.sonatype.nexus.repository.rest.api.RepositoriesApiResourceV1; + +@Named +@Singleton +@Path(ComposerProxyRepositoriesApiResourceV1.RESOURCE_URI) +public class ComposerProxyRepositoriesApiResourceV1 + extends ComposerProxyRepositoriesApiResource +{ + static final String RESOURCE_URI = RepositoriesApiResourceV1.RESOURCE_URI + "/composer/proxy"; +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoryApiRequest.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoryApiRequest.java new file mode 100644 index 00000000..1d302d4c --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoryApiRequest.java @@ -0,0 +1,38 @@ +package org.sonatype.nexus.repository.composer.rest; + +import org.sonatype.nexus.repository.composer.internal.ComposerFormat; +import org.sonatype.nexus.repository.rest.api.model.CleanupPolicyAttributes; +import org.sonatype.nexus.repository.rest.api.model.HttpClientAttributes; +import org.sonatype.nexus.repository.rest.api.model.NegativeCacheAttributes; +import org.sonatype.nexus.repository.rest.api.model.ProxyAttributes; +import org.sonatype.nexus.repository.rest.api.model.ProxyRepositoryApiRequest; +import org.sonatype.nexus.repository.rest.api.model.ReplicationAttributes; +import org.sonatype.nexus.repository.rest.api.model.StorageAttributes; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties({"format", "type"}) +public class ComposerProxyRepositoryApiRequest extends ProxyRepositoryApiRequest +{ + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + @SuppressWarnings("squid:S00107") // suppress constructor parameter count + public ComposerProxyRepositoryApiRequest( + @JsonProperty("name") final String name, + @JsonProperty("online") final Boolean online, + @JsonProperty("storage") final StorageAttributes storage, + @JsonProperty("cleanup") final CleanupPolicyAttributes cleanup, + @JsonProperty("proxy") final ProxyAttributes proxy, + @JsonProperty("negativeCache") final NegativeCacheAttributes negativeCache, + @JsonProperty("httpClient") final HttpClientAttributes httpClient, + @JsonProperty("routingRule") final String routingRule, + @JsonProperty("replication") @JsonInclude(value= Include.NON_EMPTY, content=Include.NON_NULL) + final ReplicationAttributes replication) + { + super(name, ComposerFormat.NAME, online, storage, cleanup, proxy, negativeCache, httpClient, routingRule, replication); + } + +} diff --git a/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoryApiRequestToConfigurationConverter.java b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoryApiRequestToConfigurationConverter.java new file mode 100644 index 00000000..c0812436 --- /dev/null +++ b/nexus-repository-composer/src/main/java/org/sonatype/nexus/repository/composer/rest/ComposerProxyRepositoryApiRequestToConfigurationConverter.java @@ -0,0 +1,16 @@ +package org.sonatype.nexus.repository.composer.rest; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.sonatype.nexus.repository.rest.api.ProxyRepositoryApiRequestToConfigurationConverter; +import org.sonatype.nexus.repository.routing.RoutingRuleStore; + +@Named +public class ComposerProxyRepositoryApiRequestToConfigurationConverter extends ProxyRepositoryApiRequestToConfigurationConverter +{ + @Inject + public ComposerProxyRepositoryApiRequestToConfigurationConverter(final RoutingRuleStore routingRuleStore) { + super(routingRuleStore); + } +} From 1dda5e5db786f724d9e30dc98cedea63e82576f8 Mon Sep 17 00:00:00 2001 From: Stef Date: Wed, 12 Jul 2023 21:33:00 +0200 Subject: [PATCH 3/3] add integration tests for API testing - Add integration tests for hosted and group repository - Fix asserts to handle changing port number - Make parent class abstract and use it to factor common code for integration tests - Add API tests using integration tests --- docs/REST_CONFIGURATION.md | 249 ++++++++++++++++++ .../composer/internal/ComposerClient.java | 24 ++ .../composer/internal/ComposerGroupIT.java | 79 ++++++ .../composer/internal/ComposerHostedIT.java | 73 +++++ .../composer/internal/ComposerITSupport.java | 108 +++++++- .../composer/internal/ComposerProxyIT.java | 119 +++------ .../fixtures/ComposerRepoRecipes.groovy | 12 + 7 files changed, 574 insertions(+), 90 deletions(-) create mode 100644 docs/REST_CONFIGURATION.md create mode 100644 nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerGroupIT.java create mode 100644 nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerHostedIT.java diff --git a/docs/REST_CONFIGURATION.md b/docs/REST_CONFIGURATION.md new file mode 100644 index 00000000..4d017ecd --- /dev/null +++ b/docs/REST_CONFIGURATION.md @@ -0,0 +1,249 @@ +# REST CONFIGURATION + +You can create, update and delete composer repositories through the rest API. + +Setup NEXUS_HOST to the nexus url, for instance in case of a local test instance : +NEXUS_HOST=http://localhost:8081 + +## Hosted repository + +### Create +```shell +curl -X 'POST' \ + '$NEXUS_HOST/service/rest/v1/repositories/composer/hosted' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'NX-ANTI-CSRF-TOKEN: 0.5903676711737454' \ + -H 'X-Nexus-UI: true' \ + -d '{ + "name": "composer-hosted", + "online": true, + "storage": { + "blobStoreName": "default", + "strictContentTypeValidation": true, + "writePolicy": "allow_once" + }, + "cleanup": { + "policyNames": [ + "string" + ] + }, + "component": { + "proprietaryComponents": true + } +}' +``` + +### Get information +```shell +curl -X 'GET' \ + $NEXUS_HOST/service/rest/v1/repositories/composer/hosted/composer-hosted \ + -H 'accept: application/json' \ + -H 'NX-ANTI-CSRF-TOKEN: 0.5903676711737454' \ + -H 'X-Nexus-UI: true' +``` + +### Update +```shell +curl -X 'PUT' \ + '$NEXUS_HOST/service/rest/v1/repositories/composer/hosted/composer-hosted' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'NX-ANTI-CSRF-TOKEN: 0.5903676711737454' \ + -H 'X-Nexus-UI: true' \ + -d '{ + "name": "composer-hosted", + "format": "composer", + "url": "$NEXUS_HOST/repository/composer-hosted", + "online": true, + "storage": { + "blobStoreName": "default", + "strictContentTypeValidation": true, + "writePolicy": "allow_once" + }, + "cleanup": { + "policyNames": [ + "string" + ] + }, + "component": { + "proprietaryComponents": false + }, + "type": "hosted" +}' +``` + +## Proxy repository + +### Create +```shell +curl -X 'POST' \ + '$NEXUS_HOST/service/rest/v1/repositories/composer/proxy' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'NX-ANTI-CSRF-TOKEN: 0.5903676711737454' \ + -H 'X-Nexus-UI: true' \ + -d '{ + "name": "composer-proxy", + "online": true, + "storage": { + "blobStoreName": "default", + "strictContentTypeValidation": true + }, + "cleanup": { + "policyNames": [ + "string" + ] + }, + "proxy": { + "remoteUrl": "https://packagist.org", + "contentMaxAge": 1440, + "metadataMaxAge": 1440 + }, + "negativeCache": { + "enabled": true, + "timeToLive": 1440 + }, + "httpClient": { + "blocked": false, + "autoBlock": true, + "connection": { + "retries": 0, + "userAgentSuffix": "string", + "timeout": 60, + "enableCircularRedirects": false, + "enableCookies": false, + "useTrustStore": false + }, + "authentication": { + "type": "username", + "username": "string", + "password": "string", + "ntlmHost": "string", + "ntlmDomain": "string" + } + } +}' +``` + +### Get information + +```shell +curl -X 'GET' \ + '$NEXUS_HOST/service/rest/v1/repositories/composer/proxy/composer-proxy' \ + -H 'accept: application/json' \ + -H 'NX-ANTI-CSRF-TOKEN: 0.5903676711737454' \ + -H 'X-Nexus-UI: true' +``` + +### Update + +```shell +curl -X 'PUT' \ + '$NEXUS_HOST/service/rest/v1/repositories/composer/proxy/composer-proxy' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'NX-ANTI-CSRF-TOKEN: 0.5903676711737454' \ + -H 'X-Nexus-UI: true' \ + -d '{ + "name": "composer-proxy", + "format": "composer", + "url": "$NEXUS_HOST/repository/composer-proxy", + "online": true, + "storage": { + "blobStoreName": "default", + "strictContentTypeValidation": false + }, + "cleanup": { + "policyNames": [ + "string" + ] + }, + "proxy": { + "remoteUrl": "https://packagist.org", + "contentMaxAge": 1440, + "metadataMaxAge": 1440 + }, + "negativeCache": { + "enabled": true, + "timeToLive": 1440 + }, + "httpClient": { + "blocked": false, + "autoBlock": true, + "connection": { + "retries": 0, + "userAgentSuffix": "string", + "timeout": 60, + "enableCircularRedirects": false, + "enableCookies": false, + "useTrustStore": false + } + }, + "routingRuleName": null, + "type": "proxy" +}' +``` + +## Group repository + +### Create +```shell +curl -X 'POST' \ + '$NEXUS_HOST/service/rest/v1/repositories/composer/group' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'NX-ANTI-CSRF-TOKEN: 0.5903676711737454' \ + -H 'X-Nexus-UI: true' \ + -d '{ + "name": "composer-group", + "online": true, + "storage": { + "blobStoreName": "default", + "strictContentTypeValidation": true + }, + "group": { + "memberNames": [ + "composer-hosted" + ] + } +}' +``` + +### Get information + +```shell +curl -X 'GET' \ + '$NEXUS_HOST/service/rest/v1/repositories/composer/proxy/composer-group' \ + -H 'accept: application/json' \ + -H 'NX-ANTI-CSRF-TOKEN: 0.5903676711737454' \ + -H 'X-Nexus-UI: true' +``` + +### Update + +```shell +curl -X 'PUT' \ + '$NEXUS_HOST/service/rest/v1/repositories/composer/group/composer-group' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H 'NX-ANTI-CSRF-TOKEN: 0.5903676711737454' \ + -H 'X-Nexus-UI: true' \ + -d '{ + "name": "composer-group", + "format": "composer", + "url": "$NEXUS_HOST/repository/composer-group", + "online": true, + "storage": { + "blobStoreName": "default", + "strictContentTypeValidation": true + }, + "group": { + "memberNames": [ + "composer-hosted", + "composer-proxy" + ] + }, + "type": "group" +}' +``` \ No newline at end of file diff --git a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerClient.java b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerClient.java index 76b91f6a..dde294cf 100644 --- a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerClient.java +++ b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerClient.java @@ -12,13 +12,20 @@ */ package org.sonatype.nexus.repository.composer.internal; +import java.io.File; +import java.io.IOException; import java.net.URI; +import org.apache.http.entity.ContentType; import org.sonatype.nexus.testsuite.testsupport.FormatClientSupport; +import org.apache.http.client.entity.EntityBuilder; +import org.apache.http.client.methods.HttpPut; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.impl.client.CloseableHttpClient; +import static com.google.common.base.Preconditions.checkNotNull; + public class ComposerClient extends FormatClientSupport { public ComposerClient( @@ -28,4 +35,21 @@ public class ComposerClient { super(httpClient, httpClientContext, repositoryBaseUri); } + + public int put(final String path, final File file) throws Exception { + checkNotNull(path); + checkNotNull(file); + + HttpPut put = new HttpPut(repositoryBaseUri.resolve(path)); + put.setEntity(EntityBuilder.create().setContentType(ContentType.parse("application/zip")).setFile(file).build()); + return status(execute(put)); + } + + public int put(String path, String string) throws IOException { + checkNotNull(path); + checkNotNull(string); + HttpPut put = new HttpPut(repositoryBaseUri.resolve(path)); + put.setEntity(EntityBuilder.create().setContentType(ContentType.parse("application/json")).setText(string).build()); + return status(execute(put)); + } } diff --git a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerGroupIT.java b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerGroupIT.java new file mode 100644 index 00000000..2817bc5c --- /dev/null +++ b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerGroupIT.java @@ -0,0 +1,79 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2018-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.repository.composer.internal; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.Before; +import org.junit.Test; +import org.sonatype.nexus.repository.Repository; +import org.sonatype.nexus.repository.http.HttpStatus; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.sonatype.nexus.testsuite.testsupport.FormatClientSupport.status; + +public class ComposerGroupIT + extends ComposerITSupport +{ + private static final String COMPOSER_TEST_GROUP = "composer-test-group"; + + private static final String COMPOSER_TEST_HOSTED = "composer-test-hosted"; + + private ComposerClient groupClient; + + private ComposerClient hostedClient; + + @Before + public void setup() throws Exception { + startServer(); + + + hostedClient= composerClient(repos.createComposerHosted(COMPOSER_TEST_HOSTED)); + Repository groupRepo = repos.createComposerGroup(COMPOSER_TEST_GROUP, COMPOSER_TEST_HOSTED); + groupClient = composerClient(groupRepo); + } + + @Test + public void nonExistingPackageProduces404() throws Exception { + assertThat(status(groupClient.get(BAD_PATH)), is(HttpStatus.NOT_FOUND)); + } + + @Test + public void putAndGetOk() throws Exception { + // given : check package not exists + assertThat(status(groupClient.get(VALID_ZIPBALL_URL)), is(HttpStatus.NOT_FOUND)); + + // when : upload package on hosted + assertThat(hostedClient.put(NAME_PACKAGES + "/upload/" + VALID_ZIPBALL_BASE_URL, testData.resolveFile(ZIPBALL_FILE_NAME)), is(200)); + + // then : download on group + assertThat(status(groupClient.get(VALID_ZIPBALL_URL)), is(HttpStatus.OK)); + } + + @Test + public void checkRestAPI() throws Exception { + assertThat(status(groupClient.get("/service/rest/v1/repositories")), is(HttpStatus.OK)); + } + + @Test + public void badPutGroupConfigurationByAPI() throws Exception { + assertThat(groupClient.put("/service/rest/v1/repositories/composer/group/" + COMPOSER_TEST_GROUP, "bad request"), is(HttpStatus.BAD_REQUEST)); + } + + @Test + public void getAndUpdateGroupConfigurationByAPI() throws Exception { + JsonObject expected = new JsonParser().parse("{\"name\":\"composer-test-group\",\"format\":\"composer\",\"online\":true,\"storage\":{\"blobStoreName\":\"default\",\"strictContentTypeValidation\":true},\"group\":{\"memberNames\":[\"composer-test-hosted\"],\"writableMember\":\"None\"},\"type\":\"group\"}").getAsJsonObject(); + getAndUpdateConfig(expected, COMPOSER_TEST_GROUP, "group", groupClient); + } +} diff --git a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerHostedIT.java b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerHostedIT.java new file mode 100644 index 00000000..9fc96912 --- /dev/null +++ b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerHostedIT.java @@ -0,0 +1,73 @@ +/* + * Sonatype Nexus (TM) Open Source Version + * Copyright (c) 2018-present Sonatype, Inc. + * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions. + * + * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0, + * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks + * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the + * Eclipse Foundation. All other trademarks are the property of their respective owners. + */ +package org.sonatype.nexus.repository.composer.internal; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.Before; +import org.junit.Test; +import org.sonatype.nexus.repository.Repository; +import org.sonatype.nexus.repository.http.HttpStatus; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.sonatype.nexus.testsuite.testsupport.FormatClientSupport.status; + +public class ComposerHostedIT + extends ComposerITSupport +{ + private static final String COMPOSER_TEST_HOSTED = "composer-test-hosted"; + + private ComposerClient hostedClient; + + @Before + public void setup() throws Exception { + startServer(); + + Repository hostedRepo = repos.createComposerHosted(COMPOSER_TEST_HOSTED); + hostedClient = composerClient(hostedRepo); + } + + @Test + public void nonExistingPackageProduces404() throws Exception { + assertThat(status(hostedClient.get(BAD_PATH)), is(HttpStatus.NOT_FOUND)); + } + + @Test + public void putAndGetOk() throws Exception { + // given + assertThat(status(hostedClient.get(VALID_ZIPBALL_URL)), is(HttpStatus.NOT_FOUND)); + + // when + assertThat(hostedClient.put(NAME_PACKAGES + "/upload/" + VALID_ZIPBALL_BASE_URL, testData.resolveFile(ZIPBALL_FILE_NAME)), is(200)); + + // then + assertThat(status(hostedClient.get(VALID_ZIPBALL_URL)), is(HttpStatus.OK)); + } + + @Test + public void checkRestAPI() throws Exception { + assertThat(status(hostedClient.get("/service/rest/v1/repositories")), is(HttpStatus.OK)); + } + + @Test + public void badPutHostedConfigurationByAPI() throws Exception { + assertThat(hostedClient.put("/service/rest/v1/repositories/composer/hosted/" + COMPOSER_TEST_HOSTED, "bad request"), is(HttpStatus.BAD_REQUEST)); + } + + @Test + public void getAndUpdateHostedConfigurationByAPI() throws Exception { + JsonObject expected = new JsonParser().parse("{\"name\":\"composer-test-hosted\",\"format\":\"composer\",\"online\":true,\"storage\":{\"blobStoreName\":\"default\",\"strictContentTypeValidation\":true,\"writePolicy\":\"ALLOW\"},\"cleanup\":null,\"component\":{\"proprietaryComponents\":false},\"type\":\"hosted\"}").getAsJsonObject(); + getAndUpdateConfig(expected, COMPOSER_TEST_HOSTED, "hosted", hostedClient); + } +} diff --git a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerITSupport.java b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerITSupport.java index 8c5dcc68..4add7ea1 100644 --- a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerITSupport.java +++ b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerITSupport.java @@ -12,28 +12,86 @@ */ package org.sonatype.nexus.repository.composer.internal; +import java.io.IOException; import java.net.URL; import javax.annotation.Nonnull; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.junit.After; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.Option; +import org.sonatype.goodies.httpfixture.server.fluent.Behaviours; +import org.sonatype.goodies.httpfixture.server.fluent.Server; import org.sonatype.nexus.pax.exam.NexusPaxExamSupport; import org.sonatype.nexus.repository.Repository; import org.sonatype.nexus.repository.composer.internal.fixtures.RepositoryRuleComposer; +import org.sonatype.nexus.repository.http.HttpStatus; import org.sonatype.nexus.repository.storage.Asset; import org.sonatype.nexus.repository.storage.MetadataNodeEntityAdapter; import org.sonatype.nexus.repository.storage.StorageFacet; import org.sonatype.nexus.repository.storage.StorageTx; +import org.sonatype.nexus.testsuite.testsupport.NexusITSupport; import org.sonatype.nexus.testsuite.testsupport.RepositoryITSupport; import org.junit.Rule; import static com.google.common.base.Preconditions.checkNotNull; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.sonatype.nexus.testsuite.testsupport.FormatClientSupport.bytes; +import static org.sonatype.nexus.testsuite.testsupport.FormatClientSupport.status; +import static org.testcontainers.shaded.org.hamcrest.text.MatchesPattern.matchesPattern; -public class ComposerITSupport +abstract public class ComposerITSupport extends RepositoryITSupport { + protected static final String ZIPBALL_FILE_NAME = "rjkip-ftp-php-v1.1.0.zip"; + + protected static final String NAME_VENDOR = "rjkip"; + + protected static final String NAME_PROJECT = "ftp-php"; + + protected static final String NAME_VERSION = "v1.1.0"; + + protected static final String NAME_PACKAGES = "packages"; + + protected static final String EXTENSION_ZIP = ".zip"; + + protected static final String VALID_ZIPBALL_BASE_URL = NAME_VENDOR + "/" + NAME_PROJECT + "/" + NAME_VERSION; + + protected static final String FILE_ZIPBALL = NAME_VENDOR + "-" + NAME_PROJECT + "-" + NAME_VERSION + EXTENSION_ZIP; + + protected static final String VALID_ZIPBALL_URL = VALID_ZIPBALL_BASE_URL + "/" + FILE_ZIPBALL; + + protected static final String NAME_LIST = "list"; + + protected static final String EXTENSION_JSON = ".json"; + + protected static final String FILE_PROVIDER = NAME_PROJECT + EXTENSION_JSON; + + protected static final String FILE_PACKAGES = NAME_PACKAGES + EXTENSION_JSON; + + protected static final String FILE_LIST = NAME_LIST + EXTENSION_JSON; + + protected static final String PACKAGE_BASE_PATH = "p/" + NAME_VENDOR + "/"; + + protected static final String LIST_BASE_PATH = "packages/"; + + protected static final String VALID_PROVIDER_URL = PACKAGE_BASE_PATH + FILE_PROVIDER; + + protected static final String VALID_LIST_URL = LIST_BASE_PATH + FILE_LIST; + + protected static final String MIME_TYPE_JSON = "application/json"; + + protected static final String MIME_TYPE_ZIP = "application/zip"; + protected static final String BAD_PATH = "/this/path/is/not/valid"; + @Rule public RepositoryRuleComposer repos = new RepositoryRuleComposer(() -> repositoryManager); + protected Server server; @Override protected RepositoryRuleComposer createRepositoryRule() { @@ -68,4 +126,52 @@ public static Asset findAsset(Repository repository, String path) { protected static StorageTx getStorageTx(final Repository repository) { return repository.facet(StorageFacet.class).txSupplier().get(); } + + @Configuration + public static Option[] configureNexus() { + return NexusPaxExamSupport.options( + NexusITSupport.configureNexusBase(), + nexusFeature("org.sonatype.nexus.plugins", "nexus-repository-composer") + ); + } + + protected void startServer() throws Exception { + server = Server.withPort(0) + .serve("/" + FILE_PACKAGES) + .withBehaviours(Behaviours.file(testData.resolveFile(FILE_PACKAGES))) + .serve("/" + VALID_LIST_URL) + .withBehaviours(Behaviours.file(testData.resolveFile(FILE_LIST))) + .serve("/" + VALID_PROVIDER_URL) + .withBehaviours(Behaviours.file(testData.resolveFile(FILE_PROVIDER))) + .serve("/" + VALID_ZIPBALL_URL) + .withBehaviours(Behaviours.file(testData.resolveFile(ZIPBALL_FILE_NAME))) + .start(); + } + + @After + public void tearDown() throws Exception { + server.stop(); + } + + protected void getAndUpdateConfig(JsonObject expected, String repoName, String repoType, ComposerClient repoClient) throws IOException { + // when + CloseableHttpResponse response = repoClient.get("/service/rest/v1/repositories/composer/"+ repoType + "/" + repoName); + String config = new String(bytes(response)); + JsonObject jsonConfig = (JsonObject) new JsonParser().parse(config); + + // then + assertThat(status(response), is(HttpStatus.OK)); + // check url field matches http://localhost:[0-9]*/repository/composer-test- + assertThat(matchesPattern("http://localhost:[0-9]*/repository/" + repoName).matches(jsonConfig.get("url").getAsString()), is(true)); + // compare ignoring url field + jsonConfig.remove("url"); + assertThat(jsonConfig, is(expected)); + + // set online to false, remove optional connection properties, then update repository + jsonConfig.remove("online"); + jsonConfig.remove("connection"); + jsonConfig.addProperty("online", false); + int code = repoClient.put("/service/rest/v1/repositories/composer/"+ repoType + "/" + repoName, jsonConfig.toString()); + assertThat(code, is(HttpStatus.NO_CONTENT)); + } } diff --git a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerProxyIT.java b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerProxyIT.java index 030e7373..1273b9df 100644 --- a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerProxyIT.java +++ b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/ComposerProxyIT.java @@ -12,113 +12,39 @@ */ package org.sonatype.nexus.repository.composer.internal; -import org.sonatype.goodies.httpfixture.server.fluent.Behaviours; -import org.sonatype.goodies.httpfixture.server.fluent.Server; -import org.sonatype.nexus.pax.exam.NexusPaxExamSupport; -import org.sonatype.nexus.repository.Repository; -import org.sonatype.nexus.repository.http.HttpStatus; -import org.sonatype.nexus.repository.storage.Asset; -import org.sonatype.nexus.testsuite.testsupport.NexusITSupport; - import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; - -import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.ops4j.pax.exam.Configuration; -import org.ops4j.pax.exam.Option; +import org.sonatype.nexus.repository.Repository; +import org.sonatype.nexus.repository.http.HttpStatus; +import org.sonatype.nexus.repository.storage.Asset; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.*; import static org.sonatype.nexus.testsuite.testsupport.FormatClientSupport.status; +import static org.testcontainers.shaded.org.hamcrest.text.MatchesPattern.matchesPattern; public class ComposerProxyIT extends ComposerITSupport { private static final String FORMAT_NAME = "composer"; - private static final String MIME_TYPE_JSON = "application/json"; - - private static final String MIME_TYPE_ZIP = "application/zip"; - - private static final String NAME_VENDOR = "rjkip"; - - private static final String NAME_PROJECT = "ftp-php"; - - private static final String NAME_VERSION = "v1.1.0"; - - private static final String NAME_PACKAGES = "packages"; - - private static final String NAME_LIST = "list"; - - private static final String EXTENSION_JSON = ".json"; - - private static final String EXTENSION_ZIP = ".zip"; - - private static final String FILE_PROVIDER = NAME_PROJECT + EXTENSION_JSON; - - private static final String FILE_PACKAGES = NAME_PACKAGES + EXTENSION_JSON; - - private static final String FILE_PACKAGES_CHANGED = NAME_PACKAGES + "-changed" + EXTENSION_JSON; - - private static final String FILE_LIST = NAME_LIST + EXTENSION_JSON; - - private static final String FILE_ZIPBALL = NAME_VENDOR + "-" + NAME_PROJECT + "-" + NAME_VERSION + EXTENSION_ZIP; - - private static final String PACKAGE_BASE_PATH = "p/" + NAME_VENDOR + "/"; - - private static final String LIST_BASE_PATH = "packages/"; - - private static final String BAD_PATH = "/this/path/is/not/valid"; - - private static final String VALID_PROVIDER_URL = PACKAGE_BASE_PATH + FILE_PROVIDER; - - private static final String VALID_LIST_URL = LIST_BASE_PATH + FILE_LIST; - - private static final String VALID_ZIPBALL_URL = NAME_VENDOR + "/" + NAME_PROJECT + "/" + NAME_VERSION + "/" + FILE_ZIPBALL; - - private static final String ZIPBALL_FILE_NAME = "rjkip-ftp-php-v1.1.0.zip"; - - private static final String COMPONENT_NAME = "ftp-php"; - - private static final String PACKAGE_NAME = COMPONENT_NAME + EXTENSION_JSON; - - private static final String VALID_PACKAGE_URL = PACKAGE_BASE_PATH + PACKAGE_NAME; + private static final String COMPOSER_TEST_PROXY = "composer-test-proxy"; private ComposerClient proxyClient; private Repository proxyRepo; - private Server server; - - @Configuration - public static Option[] configureNexus() { - return NexusPaxExamSupport.options( - NexusITSupport.configureNexusBase(), - nexusFeature("org.sonatype.nexus.plugins", "nexus-repository-composer") - ); - } - @Before public void setup() throws Exception { - server = Server.withPort(0) - .serve("/" + FILE_PACKAGES) - .withBehaviours(Behaviours.file(testData.resolveFile(FILE_PACKAGES))) - .serve("/" + VALID_LIST_URL) - .withBehaviours(Behaviours.file(testData.resolveFile(FILE_LIST))) - .serve("/" + VALID_PROVIDER_URL) - .withBehaviours(Behaviours.file(testData.resolveFile(FILE_PROVIDER))) - .serve("/" + VALID_ZIPBALL_URL) - .withBehaviours(Behaviours.file(testData.resolveFile(ZIPBALL_FILE_NAME))) - .start(); - - proxyRepo = repos.createComposerProxy("composer-test-proxy", server.getUrl().toExternalForm()); + startServer(); + + proxyRepo = repos.createComposerProxy(COMPOSER_TEST_PROXY, server.getUrl().toExternalForm()); proxyClient = composerClient(proxyRepo); } @@ -127,6 +53,7 @@ public void unresponsiveRemoteProduces404() throws Exception { assertThat(status(proxyClient.get(BAD_PATH)), is(HttpStatus.NOT_FOUND)); } + @Test public void retrievePackagesJSONFromProxyWhenRemoteOnline() throws Exception { assertThat(status(proxyClient.get(FILE_PACKAGES)), is(HttpStatus.OK)); @@ -144,8 +71,7 @@ public void providersURLChangedToNXRM() throws Exception { HttpEntity entity = response.getEntity(); JsonElement element = new JsonParser().parse(IOUtils.toString(entity.getContent())); JsonObject json = element.getAsJsonObject(); - - assertThat(json.get("providers-url").toString(), is(equalTo("\"http://localhost:10000/repository/composer-test-proxy/p/%package%.json\""))); + assertThat(matchesPattern("http://localhost:[0-9]*/repository/composer-test-proxy/p/%package%.json").matches(json.get("providers-url").getAsString()), is(true)); } } @@ -178,9 +104,24 @@ public void retrieveProviderJSONFromProxyWhenRemoteOnline() throws Exception { // assertThat(asset.contentType(), is(equalTo(MIME_TYPE_ZIP))); // assertThat(asset.format(), is(equalTo(FORMAT_NAME))); //} - - @After - public void tearDown() throws Exception { - server.stop(); + + @Test + public void checkRestAPI() throws Exception { + assertThat(status(proxyClient.get("/service/rest/v1/repositories")), is(HttpStatus.OK)); + } + + @Test + public void badPutProxyConfigurationByAPI() throws Exception { + assertThat(proxyClient.put("/service/rest/v1/repositories/composer/proxy/" + COMPOSER_TEST_PROXY, "bad request"), is(HttpStatus.BAD_REQUEST)); } + + @Test + public void getAndUpdateProxyConfigurationByAPI() throws Exception { + // given + int port = server.getPort(); + JsonObject expected = new JsonParser().parse("{\"name\":\"composer-test-proxy\",\"format\":\"composer\",\"online\":true,\"storage\":{\"blobStoreName\":\"default\",\"strictContentTypeValidation\":true},\"cleanup\":null,\"proxy\":{\"remoteUrl\":\"http://localhost:" + port + "\",\"contentMaxAge\":1440,\"metadataMaxAge\":1440},\"negativeCache\":{\"enabled\":true,\"timeToLive\":1440},\"httpClient\":{\"blocked\":false,\"autoBlock\":false,\"connection\":{\"retries\":null,\"userAgentSuffix\":null,\"timeout\":null,\"enableCircularRedirects\":false,\"enableCookies\":false,\"useTrustStore\":false},\"authentication\":null},\"routingRuleName\":null,\"type\":\"proxy\"}").getAsJsonObject(); + + getAndUpdateConfig(expected, COMPOSER_TEST_PROXY, "proxy", proxyClient); + } + } diff --git a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/fixtures/ComposerRepoRecipes.groovy b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/fixtures/ComposerRepoRecipes.groovy index 80972beb..ecb6378e 100644 --- a/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/fixtures/ComposerRepoRecipes.groovy +++ b/nexus-repository-composer-it/src/test/java/org/sonatype/nexus/repository/composer/internal/fixtures/ComposerRepoRecipes.groovy @@ -37,5 +37,17 @@ trait ComposerRepoRecipes createRepository(createProxy(name, 'composer-proxy', remoteUrl)) } + @Nonnull + Repository createComposerHosted(final String name) + { + createRepository(createHosted(name, 'composer-hosted')) + } + + @Nonnull + Repository createComposerGroup(final String name, final String... members) + { + createRepository(createGroup(name, 'composer-group', members)) + } + abstract Repository createRepository(final Configuration configuration) }