From ead9d1dd954d1b175596cd401b1d54dbdf1d51ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20W=C3=B3jcicki?= Date: Wed, 22 May 2019 13:44:36 +0200 Subject: [PATCH] Fix BaseApiListingResource when concurrent execution --- .../jaxrs/listing/BaseApiListingResource.java | 4 +- .../listing/BaseApiListingResourceTest.java | 73 +++++++++++++++++++ .../ConcurrentProcessSampleResource.java | 22 ++++++ 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 modules/swagger-jaxrs/src/test/java/io/swagger/jaxrs/listing/BaseApiListingResourceTest.java create mode 100644 modules/swagger-jaxrs/src/test/java/io/swagger/jaxrs/listing/ConcurrentProcessSampleResource.java diff --git a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/listing/BaseApiListingResource.java b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/listing/BaseApiListingResource.java index 4399f0cf89..8905977ed7 100644 --- a/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/listing/BaseApiListingResource.java +++ b/modules/swagger-jaxrs/src/main/java/io/swagger/jaxrs/listing/BaseApiListingResource.java @@ -10,7 +10,6 @@ import io.swagger.jaxrs.config.ReaderConfigUtils; import io.swagger.jaxrs.config.SwaggerContextService; import io.swagger.models.Swagger; -import io.swagger.util.Yaml; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -101,8 +100,9 @@ protected Swagger process( .withServletConfig(sc) .withBasePath(getBasePath(uriInfo)); - Swagger swagger = ctxService.getSwagger(); + Swagger swagger; synchronized (ApiListingResource.class) { + swagger = ctxService.getSwagger(); if (SwaggerContextService.isScannerIdInitParamDefined(sc)) { if (!initializedScanner.containsKey(sc.getServletName() + "_" + SwaggerContextService.getScannerIdFromInitParam(sc))) { swagger = scan(app, servletContext, sc, uriInfo); diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/jaxrs/listing/BaseApiListingResourceTest.java b/modules/swagger-jaxrs/src/test/java/io/swagger/jaxrs/listing/BaseApiListingResourceTest.java new file mode 100644 index 0000000000..537295938e --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/jaxrs/listing/BaseApiListingResourceTest.java @@ -0,0 +1,73 @@ +package io.swagger.jaxrs.listing; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; +import java.net.URI; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import io.swagger.models.Swagger; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + + +public class BaseApiListingResourceTest { + + @Test(description = "it should process everything concurrently") + public void testProcessConcurrent() throws InterruptedException, ExecutionException { + //given + final Application app = mock(Application.class); + final MockApiListingResource underTest = new MockApiListingResource(); + final ServletContext servletContext = mock(ServletContext.class); + final ServletConfig servletConfig = mock(ServletConfig.class); + final HttpHeaders headers = mock(HttpHeaders.class); + final UriInfo uriInfo = mock(UriInfo.class); + final URI uri = URI.create("testUrl"); + + given(app.getClasses()).willReturn(new HashSet>(Arrays.asList(ConcurrentProcessSampleResource.class))); + given(servletConfig.getServletContext()).willReturn(servletContext); + given(uriInfo.getBaseUri()).willReturn(uri); + + //when + ExecutorService executorService = Executors.newFixedThreadPool(2); + List> futures = executorService.invokeAll(Arrays.asList( + callProcess(underTest, app, servletContext, servletConfig, headers, uriInfo), + callProcess(underTest, app, servletContext, servletConfig, headers, uriInfo) + )); + executorService.awaitTermination(1, TimeUnit.SECONDS); + + //then + Swagger swaggerA = futures.get(0).get(); + Swagger swaggerB = futures.get(1).get(); + + Assert.assertNotNull(swaggerA); + Assert.assertNotNull(swaggerB); + Assert.assertEquals(swaggerA, swaggerB); + } + + private Callable callProcess(final MockApiListingResource underTest, final Application app, final ServletContext servletContext, final ServletConfig servletConfig, final HttpHeaders headers, final UriInfo uriInfo) { + return new Callable() { + @Override + public Swagger call() { + return underTest.process(app, servletContext, servletConfig, headers, uriInfo); + } + }; + } + + private class MockApiListingResource extends BaseApiListingResource { + + } +} \ No newline at end of file diff --git a/modules/swagger-jaxrs/src/test/java/io/swagger/jaxrs/listing/ConcurrentProcessSampleResource.java b/modules/swagger-jaxrs/src/test/java/io/swagger/jaxrs/listing/ConcurrentProcessSampleResource.java new file mode 100644 index 0000000000..7b6e8b4056 --- /dev/null +++ b/modules/swagger-jaxrs/src/test/java/io/swagger/jaxrs/listing/ConcurrentProcessSampleResource.java @@ -0,0 +1,22 @@ +package io.swagger.jaxrs.listing; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; + +@Api(value = "foo") +@Path("foo") +public class ConcurrentProcessSampleResource { + @GET + @ApiOperation(value = "test of sample operation") + @Path("/bar") + public Response operationWithReadOnly(@ApiParam(value = "test") @QueryParam("sampleParam") String sampleParam) { + return Response.ok().build(); + } + +}