Skip to content

Commit

Permalink
Fix BaseApiListingResource when concurrent execution
Browse files Browse the repository at this point in the history
  • Loading branch information
awojcicki authored and frantuma committed Jan 26, 2024
1 parent 0f11c7e commit ead9d1d
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Class<?>>(Arrays.asList(ConcurrentProcessSampleResource.class)));
given(servletConfig.getServletContext()).willReturn(servletContext);
given(uriInfo.getBaseUri()).willReturn(uri);

//when
ExecutorService executorService = Executors.newFixedThreadPool(2);
List<Future<Swagger>> 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<Swagger> callProcess(final MockApiListingResource underTest, final Application app, final ServletContext servletContext, final ServletConfig servletConfig, final HttpHeaders headers, final UriInfo uriInfo) {
return new Callable<Swagger>() {
@Override
public Swagger call() {
return underTest.process(app, servletContext, servletConfig, headers, uriInfo);
}
};
}

private class MockApiListingResource extends BaseApiListingResource {

}
}
Original file line number Diff line number Diff line change
@@ -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();
}

}

0 comments on commit ead9d1d

Please sign in to comment.