Bump RestEasy to 5.0.2 (#3329)

* Bump deps

* Test fix

* Add test logging

* Add test logging

* Add logging
This commit is contained in:
James Agnew 2022-01-24 20:15:41 -05:00 committed by GitHub
parent a11d72ba51
commit 31bb1d9e9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 407 additions and 304 deletions

View File

@ -79,11 +79,6 @@
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>

View File

@ -25,6 +25,7 @@
<li>Jetty Server (CLI): 9.4.43.v20210629 -> 9.4.44.v20210927</li>
<li>Spring Boot (Boot): 2.5.0 -> 2.6.2</li>
<li>Swagger UI (OpenAPI): 3.46.0 -> 4.1.3</li>
<li>Resteasy (JAX-RS): 4.0.0.Beta3 -> 5.0.2.Final</li>
</ul>
"

View File

@ -72,11 +72,6 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>ejb-api</artifactId>
@ -87,6 +82,11 @@
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_2.1_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
@ -122,11 +122,6 @@
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>

View File

@ -20,22 +20,26 @@ package ca.uhn.fhir.jaxrs.client;
* #L%
*/
import java.util.List;
import java.util.Map;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.HttpClientUtil;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.client.method.MethodUtil;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.client.api.*;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.client.method.MethodUtil;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
import java.util.List;
import java.util.Map;
/**
* A Http Request based on JaxRs. This is an adapter around the class

View File

@ -26,6 +26,8 @@ import java.util.List;
import javax.interceptor.Interceptors;
import javax.ws.rs.*;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

View File

@ -20,54 +20,77 @@ package ca.uhn.fhir.jaxrs.server;
* #L%
*/
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.PostConstruct;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.server.IRestfulResponse;
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.ResourceBinding;
import ca.uhn.fhir.rest.server.RestfulServerConfiguration;
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.provider.ServerCapabilityStatementProvider;
import ca.uhn.fhir.util.ReflectionUtil;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu2.hapi.rest.server.ServerConformanceProvider;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.CapabilityStatement;
import org.slf4j.LoggerFactory;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.jaxrs.server.util.JaxRsRequest.Builder;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.server.IRestfulResponse;
import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
import ca.uhn.fhir.util.ReflectionUtil;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* This is the conformance provider for the jax rs servers. It requires all providers to be registered during startup because the conformance profile is generated during the postconstruct phase.
*
* @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
*/
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProvider implements IResourceProvider {
/** the logger */
/**
* the logger
*/
private static final org.slf4j.Logger ourLog = LoggerFactory.getLogger(AbstractJaxRsConformanceProvider.class);
/** the server bindings */
/**
* the server bindings
*/
private ResourceBinding myServerBinding = new ResourceBinding();
/** the resource bindings */
/**
* the resource bindings
*/
private ConcurrentHashMap<String, ResourceBinding> myResourceNameToBinding = new ConcurrentHashMap<String, ResourceBinding>();
/** the server configuration */
/**
* the server configuration
*/
private RestfulServerConfiguration serverConfiguration = new RestfulServerConfiguration();
/** the conformance. It is created once during startup */
/**
* the conformance. It is created once during startup
*/
private org.hl7.fhir.r4.model.CapabilityStatement myR4CapabilityStatement;
private org.hl7.fhir.dstu3.model.CapabilityStatement myDstu3CapabilityStatement;
private org.hl7.fhir.dstu2016may.model.Conformance myDstu2_1Conformance;
@ -78,12 +101,9 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
/**
* Constructor allowing the description, servername and server to be set
*
* @param implementationDescription
* the implementation description. If null, "" is used
* @param serverName
* the server name. If null, "" is used
* @param serverVersion
* the server version. If null, "" is used
* @param implementationDescription the implementation description. If null, "" is used
* @param serverName the server name. If null, "" is used
* @param serverVersion the server version. If null, "" is used
*/
protected AbstractJaxRsConformanceProvider(String implementationDescription, String serverName, String serverVersion) {
serverConfiguration.setFhirContext(getFhirContext());
@ -95,14 +115,10 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
/**
* Constructor allowing the description, servername and server to be set
*
* @param ctx
* the {@link FhirContext} instance.
* @param implementationDescription
* the implementation description. If null, "" is used
* @param serverName
* the server name. If null, "" is used
* @param serverVersion
* the server version. If null, "" is used
* @param ctx the {@link FhirContext} instance.
* @param implementationDescription the implementation description. If null, "" is used
* @param serverName the server name. If null, "" is used
* @param serverVersion the server version. If null, "" is used
*/
protected AbstractJaxRsConformanceProvider(FhirContext ctx, String implementationDescription, String serverName, String serverVersion) {
super(ctx);
@ -230,10 +246,8 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
/**
* This method will add a provider to the conformance. This method is almost an exact copy of {@link ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods(Object)}
*
* @param theProvider
* an instance of the provider interface
* @param theProviderInterface
* the class describing the providers interface
* @param theProvider an instance of the provider interface
* @param theProviderInterface the class describing the providers interface
* @return the numbers of basemethodbindings added
* @see ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods(Object)
*/

View File

@ -23,7 +23,10 @@ package ca.uhn.fhir.jaxrs.server;
import java.io.IOException;
import javax.interceptor.Interceptors;
import javax.ws.rs.*;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

View File

@ -23,9 +23,13 @@ import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.FhirContext;

View File

@ -5,6 +5,7 @@ import ca.uhn.fhir.jaxrs.server.test.TestJaxRsDummyPatientProviderDstu2_1;
import ca.uhn.fhir.jaxrs.server.test.TestJaxRsMockPatientRestProviderDstu2_1;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IResourceProvider;
import javax.ws.rs.core.MultivaluedMap;
import org.jboss.resteasy.specimpl.ResteasyHttpHeaders;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -16,7 +17,8 @@ import java.net.URI;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -27,7 +29,7 @@ public class AbstractJaxRsConformanceProviderDstu2_1Test {
AbstractJaxRsConformanceProvider provider;
private ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> providers;
private ResteasyHttpHeaders headers;
private MultivaluedHashMap<String, String> queryParameters;
private MultivaluedMap<String, String> queryParameters;
@BeforeEach
public void setUp() throws Exception {

View File

@ -14,7 +14,6 @@ import ca.uhn.fhir.rest.api.SearchStyleEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.test.utilities.JettyUtil;
@ -36,6 +35,7 @@ import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@ -68,12 +68,9 @@ import static org.mockito.Mockito.when;
public class AbstractJaxRsResourceProviderDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AbstractJaxRsResourceProviderDstu3Test.class);
private static IGenericClient client;
private static FhirContext ourCtx = FhirContext.forDstu3();
private static final String PATIENT_NAME = "Van Houte";
private static IGenericClient client;
private static FhirContext ourCtx = FhirContext.forDstu3();
private static int ourPort;
private static String serverBase;
private static Server jettyServer;
@ -86,12 +83,6 @@ public class AbstractJaxRsResourceProviderDstu3Test {
assertEquals(id, Integer.parseInt(resource.getIdElement().getIdPart()));
}
@AfterAll
public static void afterClassClearContext() throws Exception {
JettyUtil.closeServer(jettyServer);
TestUtil.randomizeLocaleAndTimezone();
}
private void compareResultUrl(String url, IBaseResource resource) {
assertEquals(url, resource.getIdElement().getValueAsString().substring(serverBase.length() - 1));
}
@ -110,7 +101,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
return result;
}
/** Find By Id */
/**
* Find By Id
*/
@Test
public void findUsingGenericClientById() {
when(mock.find(any(IdType.class))).thenReturn(createPatient(1));
@ -144,7 +137,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
reset(mock);
}
/** Conditional Creates */
/**
* Conditional Creates
*/
@Test
public void testConditionalCreate() throws Exception {
Patient toCreate = createPatient(1);
@ -163,7 +158,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
compareResultId(1, resource);
}
/** Conformance - Server */
/**
* Conformance - Server
*/
@Test
public void testConformance() {
final CapabilityStatement conf = client.fetchConformance().ofType(CapabilityStatement.class).execute();
@ -200,7 +197,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
assertEquals("Patient?identifier=2&_format=json", conditionalCaptor.getValue());
}
/** Extended Operations */
/**
* Extended Operations
*/
@Test
public void testExtendedOperations() {
// prepare mock
@ -216,21 +215,7 @@ public class AbstractJaxRsResourceProviderDstu3Test {
Parameters outParams = client.operation().onInstance(new IdType("Patient", "1")).named("$someCustomOperation")
.withParameters(inParams).execute();
//verify
assertEquals("outputValue", ((StringType)outParams.getParameter().get(0).getValue()).getValueAsString());
}
class StringTypeMatcher implements ArgumentMatcher<StringType> {
private StringType myStringType;
public StringTypeMatcher(StringType stringType) {
myStringType = stringType;
}
@Override
public boolean matches(StringType argument) {
return myStringType.getValue().equals(argument.getValue());
}
assertEquals("outputValue", ((StringType) outParams.getParameter().get(0).getValue()).getValueAsString());
}
@Test
@ -255,7 +240,7 @@ public class AbstractJaxRsResourceProviderDstu3Test {
.execute();
// verify
assertEquals("outputValue", ((StringType)outParams.getParameter().get(0).getValue()).getValueAsString());
assertEquals("outputValue", ((StringType) outParams.getParameter().get(0).getValue()).getValueAsString());
}
@Test
@ -267,7 +252,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
assertEquals("1", idCaptor.getValue().getIdPart());
}
/** Search - Compartments */
/**
* Search - Compartments
*/
@Test
public void testSearchCompartments() {
when(mock.searchCompartment(any(IdType.class))).thenReturn(Arrays.asList((IBaseResource) createPatient(1)));
@ -278,7 +265,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
compareResultUrl("/Patient/1", resource);
}
/** */
/**
*
*/
@Test
public void testSearchPost() {
when(mock.search(ArgumentMatchers.isNull(), ArgumentMatchers.isNull()))
@ -290,7 +279,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
compareResultUrl("/Patient/1", resource);
}
/** Search/Query - Type */
/**
* Search/Query - Type
*/
@Test
public void testSearchUsingGenericClientBySearch() {
// Perform a search
@ -305,7 +296,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
compareResultUrl("/Patient/1", resource);
}
/** Search - Multi-valued Parameters (ANY/OR) */
/**
* Search - Multi-valued Parameters (ANY/OR)
*/
@Test
public void testSearchUsingGenericClientBySearchWithMultiValues() {
when(mock.search(any(StringParam.class), ArgumentMatchers.notNull()))
@ -320,7 +313,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
compareResultUrl("/Patient/1", resource);
}
/** Search - Paging */
/**
* Search - Paging
*/
@Test
public void testSearchWithPaging() {
// Perform a search
@ -348,7 +343,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
assertNull(nextPage.getLink(org.hl7.fhir.dstu3.model.Bundle.LINK_NEXT));
}
/** Search - Subsetting (_summary and _elements) */
/**
* Search - Subsetting (_summary and _elements)
*/
@Test
@Disabled
public void testSummary() {
@ -356,7 +353,9 @@ public class AbstractJaxRsResourceProviderDstu3Test {
.returnBundle(org.hl7.fhir.dstu3.model.Bundle.class).execute();
}
/** Transaction - Server */
/**
* Transaction - Server
*/
// @Disabled
// @Test
// public void testTransaction() {
@ -371,7 +370,6 @@ public class AbstractJaxRsResourceProviderDstu3Test {
// entry.setTransactionMethod(theTransactionOperation);
// ca.uhn.fhir.model.api.Bundle response = client.transaction().withBundle(bundle).execute();
// }
@Test
public void testUpdateById() throws Exception {
when(mock.update(idCaptor.capture(), patientCaptor.capture(), conditionalCaptor.capture())).thenReturn(new MethodOutcome());
@ -441,13 +439,33 @@ public class AbstractJaxRsResourceProviderDstu3Test {
assertNotNull(mO.getOperationOutcome());
}
class StringTypeMatcher implements ArgumentMatcher<StringType> {
private StringType myStringType;
public StringTypeMatcher(StringType stringType) {
myStringType = stringType;
}
@Override
public boolean matches(StringType argument) {
return myStringType.getValue().equals(argument.getValue());
}
}
@AfterAll
public static void afterClassClearContext() throws Exception {
JettyUtil.closeServer(jettyServer);
TestUtil.randomizeLocaleAndTimezone();
}
@BeforeAll
public static void setUpClass() throws Exception {
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
jettyServer = new Server(0);
jettyServer.setHandler(context);
ServletHolder jerseyServlet = context.addServlet(org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.class, "/*");
ServletHolder jerseyServlet = context.addServlet(HttpServletDispatcher.class, "/*");
jerseyServlet.setInitOrder(0);
//@formatter:off

View File

@ -439,7 +439,7 @@ public class AbstractJaxRsResourceProviderTest {
context.setContextPath("/");
jettyServer = new Server(0);
jettyServer.setHandler(context);
ServletHolder jerseyServlet = context.addServlet(org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.class, "/*");
ServletHolder jerseyServlet = context.addServlet(org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher.class, "/*");
jerseyServlet.setInitOrder(0);
//@formatter:off

View File

@ -1,22 +1,21 @@
package ca.uhn.fhir.jaxrs.server.test;
import java.util.concurrent.ConcurrentHashMap;
import javax.ejb.Stateless;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsConformanceProvider;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IResourceProvider;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ejb.Stateless;
import java.util.concurrent.ConcurrentHashMap;
/**
* A conformance provider exposes the mock patient and this provider
*/
@Path("")
@Stateless
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
@Produces({MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML})
public class TestJaxRsConformanceRestProvider extends AbstractJaxRsConformanceProvider {
public TestJaxRsConformanceRestProvider() {

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jaxrs.server.test;
import java.util.concurrent.ConcurrentHashMap;
import javax.ejb.Stateless;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

View File

@ -50,6 +50,7 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
import ca.uhn.fhir.test.BaseTest;
import ca.uhn.fhir.test.utilities.BatchJobHelper;
import ca.uhn.fhir.test.utilities.LoggingExtension;
import ca.uhn.fhir.test.utilities.ProxyUtil;
import ca.uhn.fhir.test.utilities.UnregisterScheduledProcessor;
@ -81,6 +82,10 @@ import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.batch.core.repository.dao.JobExecutionDao;
import org.springframework.batch.core.repository.dao.JobInstanceDao;
import org.springframework.batch.core.repository.dao.MapJobExecutionDao;
import org.springframework.batch.core.repository.dao.MapJobInstanceDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.jpa.JpaTransactionManager;
@ -195,6 +200,21 @@ public abstract class BaseJpaTest extends BaseTest {
private IForcedIdDao myForcedIdDao;
@Autowired(required = false)
protected IFulltextSearchSvc myFulltestSearchSvc;
@Autowired(required = false)
protected BatchJobHelper myBatchJobHelper;
@Autowired(required = false)
private JobExecutionDao myMapJobExecutionDao;
@Autowired(required = false)
private JobInstanceDao myMapJobInstanceDao;
@AfterEach
public void afterEnsureNoStaleBatchJobs() {
if (myMapJobInstanceDao != null) {
myBatchJobHelper.ensureNoRunningJobs();
ProxyUtil.getSingletonTarget(myMapJobExecutionDao, MapJobExecutionDao.class).clear();
ProxyUtil.getSingletonTarget(myMapJobInstanceDao, MapJobInstanceDao.class).clear();
}
}
@AfterEach
public void afterPerformCleanup() {

View File

@ -87,7 +87,9 @@ import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.BasePagingProvider;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
import ca.uhn.fhir.test.utilities.BatchJobHelper;
import ca.uhn.fhir.test.utilities.ITestDataBuilder;
import ca.uhn.fhir.test.utilities.ProxyUtil;
import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.UrlUtil;
import ca.uhn.fhir.validation.FhirValidator;
@ -171,6 +173,10 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.event.Level;
import org.springframework.batch.core.repository.dao.JobExecutionDao;
import org.springframework.batch.core.repository.dao.JobInstanceDao;
import org.springframework.batch.core.repository.dao.MapJobExecutionDao;
import org.springframework.batch.core.repository.dao.MapJobInstanceDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
@ -492,11 +498,6 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
@Autowired
protected DaoRegistry myDaoRegistry;
@Autowired
private IValidationSupport myJpaValidationSupportChainR4;
private PerformanceTracingLoggingInterceptor myPerformanceTracingLoggingInterceptor;
@Autowired
private IBulkDataExportSvc myBulkDataExportSvc;
@Autowired
protected IdHelperService myIdHelperService;
@Autowired
protected IBatchJobSubmitter myBatchJobSubmitter;
@ -504,6 +505,11 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
protected ValidationSettings myValidationSettings;
@Autowired
protected IMdmLinkDao myMdmLinkDao;
@Autowired
private IValidationSupport myJpaValidationSupportChainR4;
private PerformanceTracingLoggingInterceptor myPerformanceTracingLoggingInterceptor;
@Autowired
private IBulkDataExportSvc myBulkDataExportSvc;
@AfterEach()
public void afterCleanupDao() {
@ -564,7 +570,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
@AfterEach
public void afterPurgeDatabase() {
runInTransaction(()->{
runInTransaction(() -> {
myMdmLinkDao.deleteAll();
});
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry, myBulkDataExportSvc);
@ -623,23 +629,6 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
}
}
public class ValidationPolicyAdvisor implements IValidationPolicyAdvisor {
@Override
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) {
return ReferenceValidationPolicy.CHECK_VALID;
}
@Override
public CodedContentValidationPolicy policyForCodedContent(IResourceValidator iResourceValidator, Object o, String s, ElementDefinition elementDefinition, org.hl7.fhir.r5.model.StructureDefinition structureDefinition, BindingKind bindingKind, org.hl7.fhir.r5.model.ValueSet valueSet, List<String> list) {
return CodedContentValidationPolicy.CODE;
}
@Override
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator, Object appContext, String containerType, String containerId, Element.SpecialElement containingResourceType, String path, String url) {
return ContainedReferenceValidationPolicy.CHECK_VALID;
}
}
@SuppressWarnings("unchecked")
protected void upload(String theClasspath) throws IOException {
String resource = loadResource(theClasspath);
@ -649,7 +638,6 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
dao.update(resourceParsed);
}
protected void assertHierarchyContains(String... theStrings) {
List<String> hierarchy = runInTransaction(() -> {
List<String> hierarchyHolder = new ArrayList<>();
@ -667,6 +655,72 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
}
}
protected ValueSet.ConceptReferenceDesignationComponent assertConceptContainsDesignation(ValueSet.ValueSetExpansionContainsComponent theConcept, String theLanguage, String theUseSystem, String theUseCode, String theUseDisplay, String theDesignationValue) {
Stream<ValueSet.ConceptReferenceDesignationComponent> stream = theConcept.getDesignation().stream();
if (theLanguage != null) {
stream = stream.filter(designation -> theLanguage.equalsIgnoreCase(designation.getLanguage()));
}
if (theUseSystem != null) {
stream = stream.filter(designation -> theUseSystem.equalsIgnoreCase(designation.getUse().getSystem()));
}
if (theUseCode != null) {
stream = stream.filter(designation -> theUseCode.equalsIgnoreCase(designation.getUse().getCode()));
}
if (theUseDisplay != null) {
stream = stream.filter(designation -> theUseDisplay.equalsIgnoreCase(designation.getUse().getDisplay()));
}
if (theDesignationValue != null) {
stream = stream.filter(designation -> theDesignationValue.equalsIgnoreCase(designation.getValue()));
}
Optional<ValueSet.ConceptReferenceDesignationComponent> first = stream.findFirst();
if (!first.isPresent()) {
String failureMessage = String.format("Concept %s did not contain designation [%s|%s|%s|%s|%s] ", theConcept, theLanguage, theUseSystem, theUseCode, theUseDisplay, theDesignationValue);
fail(failureMessage);
return null;
} else {
return first.get();
}
}
protected ValueSet.ValueSetExpansionContainsComponent assertExpandedValueSetContainsConcept(ValueSet theValueSet, String theSystem, String theCode, String theDisplay, Integer theDesignationCount) {
List<ValueSet.ValueSetExpansionContainsComponent> contains = theValueSet.getExpansion().getContains();
Stream<ValueSet.ValueSetExpansionContainsComponent> stream = contains.stream();
if (theSystem != null) {
stream = stream.filter(concept -> theSystem.equalsIgnoreCase(concept.getSystem()));
}
if (theCode != null) {
stream = stream.filter(concept -> theCode.equalsIgnoreCase(concept.getCode()));
}
if (theDisplay != null) {
stream = stream.filter(concept -> theDisplay.equalsIgnoreCase(concept.getDisplay()));
}
if (theDesignationCount != null) {
stream = stream.filter(concept -> concept.getDesignation().size() == theDesignationCount);
}
Optional<ValueSet.ValueSetExpansionContainsComponent> first = stream.findFirst();
if (!first.isPresent()) {
String expandedValueSetString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(theValueSet);
String failureMessage = String.format("Expanded ValueSet %s did not contain concept [%s|%s|%s] with [%d] designations. Outcome:\n%s", theValueSet.getId(), theSystem, theCode, theDisplay, theDesignationCount, expandedValueSetString);
fail(failureMessage);
return null;
} else {
return first.get();
}
}
public List<String> getExpandedConceptsByValueSetUrl(String theValuesetUrl) {
return runInTransaction(() -> {
List<TermValueSet> valueSets = myTermValueSetDao.findTermValueSetByUrl(Pageable.unpaged(), theValuesetUrl);
assertEquals(1, valueSets.size());
TermValueSet valueSet = valueSets.get(0);
List<TermValueSetConcept> concepts = valueSet.getConcepts();
return concepts.stream().map(concept -> concept.getCode()).collect(Collectors.toList());
});
}
private static void flattenExpansionHierarchy(List<String> theFlattenedHierarchy, List<TermConcept> theCodes, String thePrefix) {
theCodes.sort((o1, o2) -> {
int s1 = o1.getSequence() != null ? o1.getSequence() : o1.getCode().hashCode();
@ -796,70 +850,20 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
return uuid;
}
protected ValueSet.ConceptReferenceDesignationComponent assertConceptContainsDesignation(ValueSet.ValueSetExpansionContainsComponent theConcept, String theLanguage, String theUseSystem, String theUseCode, String theUseDisplay, String theDesignationValue) {
Stream<ValueSet.ConceptReferenceDesignationComponent> stream = theConcept.getDesignation().stream();
if (theLanguage != null) {
stream = stream.filter(designation -> theLanguage.equalsIgnoreCase(designation.getLanguage()));
}
if (theUseSystem != null) {
stream = stream.filter(designation -> theUseSystem.equalsIgnoreCase(designation.getUse().getSystem()));
}
if (theUseCode != null) {
stream = stream.filter(designation -> theUseCode.equalsIgnoreCase(designation.getUse().getCode()));
}
if (theUseDisplay != null) {
stream = stream.filter(designation -> theUseDisplay.equalsIgnoreCase(designation.getUse().getDisplay()));
}
if (theDesignationValue != null) {
stream = stream.filter(designation -> theDesignationValue.equalsIgnoreCase(designation.getValue()));
public class ValidationPolicyAdvisor implements IValidationPolicyAdvisor {
@Override
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) {
return ReferenceValidationPolicy.CHECK_VALID;
}
Optional<ValueSet.ConceptReferenceDesignationComponent> first = stream.findFirst();
if (!first.isPresent()) {
String failureMessage = String.format("Concept %s did not contain designation [%s|%s|%s|%s|%s] ", theConcept, theLanguage, theUseSystem, theUseCode, theUseDisplay, theDesignationValue);
fail(failureMessage);
return null;
} else {
return first.get();
}
@Override
public CodedContentValidationPolicy policyForCodedContent(IResourceValidator iResourceValidator, Object o, String s, ElementDefinition elementDefinition, org.hl7.fhir.r5.model.StructureDefinition structureDefinition, BindingKind bindingKind, org.hl7.fhir.r5.model.ValueSet valueSet, List<String> list) {
return CodedContentValidationPolicy.CODE;
}
protected ValueSet.ValueSetExpansionContainsComponent assertExpandedValueSetContainsConcept(ValueSet theValueSet, String theSystem, String theCode, String theDisplay, Integer theDesignationCount) {
List<ValueSet.ValueSetExpansionContainsComponent> contains = theValueSet.getExpansion().getContains();
Stream<ValueSet.ValueSetExpansionContainsComponent> stream = contains.stream();
if (theSystem != null) {
stream = stream.filter(concept -> theSystem.equalsIgnoreCase(concept.getSystem()));
@Override
public ContainedReferenceValidationPolicy policyForContained(IResourceValidator validator, Object appContext, String containerType, String containerId, Element.SpecialElement containingResourceType, String path, String url) {
return ContainedReferenceValidationPolicy.CHECK_VALID;
}
if (theCode != null) {
stream = stream.filter(concept -> theCode.equalsIgnoreCase(concept.getCode()));
}
if (theDisplay != null) {
stream = stream.filter(concept -> theDisplay.equalsIgnoreCase(concept.getDisplay()));
}
if (theDesignationCount != null) {
stream = stream.filter(concept -> concept.getDesignation().size() == theDesignationCount);
}
Optional<ValueSet.ValueSetExpansionContainsComponent> first = stream.findFirst();
if (!first.isPresent()) {
String expandedValueSetString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(theValueSet);
String failureMessage = String.format("Expanded ValueSet %s did not contain concept [%s|%s|%s] with [%d] designations. Outcome:\n%s", theValueSet.getId(), theSystem, theCode, theDisplay, theDesignationCount, expandedValueSetString);
fail(failureMessage);
return null;
} else {
return first.get();
}
}
public List<String> getExpandedConceptsByValueSetUrl(String theValuesetUrl) {
return runInTransaction(() -> {
List<TermValueSet> valueSets = myTermValueSetDao.findTermValueSetByUrl(Pageable.unpaged(), theValuesetUrl);
assertEquals(1, valueSets.size());
TermValueSet valueSet = valueSets.get(0);
List<TermValueSetConcept> concepts = valueSet.getConcepts();
return concepts.stream().map(concept -> concept.getCode()).collect(Collectors.toList());
});
}
}

View File

@ -158,9 +158,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4Test.class);
@Autowired
private BatchJobHelper myBatchJobHelper;
@AfterEach
public final void after() {
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());

View File

@ -20,6 +20,9 @@ package ca.uhn.fhir.test.utilities;
* #L%
*/
import ca.uhn.fhir.util.StopWatch;
import org.awaitility.core.ConditionTimeoutException;
import org.hamcrest.Matchers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.BatchStatus;
@ -37,7 +40,11 @@ import java.util.stream.Collectors;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.oneOf;
import static org.junit.jupiter.api.Assertions.fail;
public class BatchJobHelper {
@ -55,6 +62,7 @@ public class BatchJobHelper {
/**
* Await and report for job completions
*
* @param theFailIfNotJobsFound indicate if must fail in case no matching jobs are found
* @param theJobNames The job names to match
* @return the matched JobExecution(s)
@ -63,7 +71,9 @@ public class BatchJobHelper {
assert theJobNames.length > 0;
if (theFailIfNotJobsFound) {
await().until(() -> !getJobInstances(theJobNames).isEmpty());
await()
.alias("Wait for jobs to exist named: " + Arrays.asList(theJobNames))
.until(() -> getJobInstances(theJobNames), not(empty()));
}
List<JobInstance> matchingJobInstances = getJobInstances(theJobNames);
@ -97,19 +107,43 @@ public class BatchJobHelper {
}
protected void awaitJobCompletions(Collection<JobExecution> theJobs) {
theJobs.forEach(jobExecution -> awaitJobCompletion(jobExecution));
// This intermittently fails for unknown reasons, so I've added a bunch
// of extra junk here to improve what we output when it fails
for (JobExecution jobExecution : theJobs) {
try {
awaitJobCompletion(jobExecution);
} catch (ConditionTimeoutException e) {
StringBuilder msg = new StringBuilder();
msg.append("Failed waiting for job to complete.\n");
msg.append("Error: ").append(e).append("\n");
msg.append("Statuses:");
for (JobExecution next : theJobs) {
JobExecution execution = myJobExplorer.getJobExecution(next.getId());
msg.append("\n * Execution ")
.append(execution.getId())
.append(" has status ")
.append(execution.getStatus());
}
fail(msg.toString());
}
}
}
public void awaitJobCompletion(JobExecution theJobExecution) {
await().atMost(120, TimeUnit.SECONDS).until(() -> {
await()
.atMost(120, TimeUnit.SECONDS).until(() -> {
JobExecution jobExecution = myJobExplorer.getJobExecution(theJobExecution.getId());
ourLog.info("JobExecution {} currently has status: {}- Failures if any: {}", theJobExecution.getId(), jobExecution.getStatus(), jobExecution.getFailureExceptions());
return jobExecution.getStatus();
}, Matchers.oneOf(
// JM: Adding ABANDONED status because given the description, it s similar to FAILURE, and we need to avoid tests failing because
// of wait timeouts caused by unmatched statuses. Also adding STOPPED because tests were found where this wait timed out
// with jobs keeping that status during the whole wait
return jobExecution.getStatus() == BatchStatus.COMPLETED || jobExecution.getStatus() == BatchStatus.FAILED
|| jobExecution.getStatus() == BatchStatus.ABANDONED || jobExecution.getStatus() == BatchStatus.STOPPED;
});
BatchStatus.COMPLETED,
BatchStatus.FAILED,
BatchStatus.ABANDONED,
BatchStatus.STOPPED
));
}
public int getReadCount(Long theJobExecutionId) {
@ -129,4 +163,24 @@ public class BatchJobHelper {
return stepExecutions.iterator().next();
}
public void ensureNoRunningJobs() {
for (String nextJobName : myJobExplorer.getJobNames()) {
List<JobInstance> instances = myJobExplorer.getJobInstances(nextJobName, 0, 10000);
for (JobInstance nextInstance : instances) {
List<JobExecution> executions = myJobExplorer.getJobExecutions(nextInstance);
for (JobExecution nextExecution : executions) {
ourLog.info("Have job execution {} in status: {}", nextExecution.getId(), nextExecution.getStatus());
try {
await().until(() -> myJobExplorer.getJobExecution(nextExecution.getId()).getStatus(), oneOf(BatchStatus.STOPPED, BatchStatus.ABANDONED, BatchStatus.FAILED, BatchStatus.COMPLETED));
} catch (ConditionTimeoutException e) {
JobExecution execution = myJobExplorer.getJobExecution(nextExecution.getId());
fail("Execution " + execution + "\n" +
"Instance: " + nextInstance + "\n" +
"Job: " + nextJobName);
}
}
}
}
}
}

13
pom.xml
View File

@ -825,7 +825,7 @@
<okhttp_version>3.8.1</okhttp_version>
<poi_version>4.1.2</poi_version>
<poi_ooxml_schemas_version>1.4</poi_ooxml_schemas_version>
<resteasy_version>4.0.0.Beta3</resteasy_version>
<resteasy_version>5.0.2.Final</resteasy_version>
<ph_schematron_version>5.6.5</ph_schematron_version>
<ph_commons_version>9.5.4</ph_commons_version>
<plexus_compiler_api_version>2.9.0</plexus_compiler_api_version>
@ -1156,11 +1156,6 @@
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<!--
We use JUnit 5 in HAPI FHIR, but some libraries still pull in / require JUnit 4
@ -1531,9 +1526,9 @@
<version>${jersey_version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>${resteasy_version}</version>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_2.1_spec</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>

View File

@ -71,10 +71,6 @@
<artifactId>jetty-servlet</artifactId>
<version>${jetty_version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>

View File

@ -8,7 +8,6 @@ import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.ServletContextHandler
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.MatcherAssert.assertThat
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
import org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
@ -19,7 +18,7 @@ class ExtendedOrganizationResourceTest {
@Test
fun makeSureSearchDoesNotThrowOnIncludeParam() {
val response = ResteasyClientBuilder()
val response = org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl()
.build()
.target("http://localhost:$ourPort/Organization?_id=1")
.request()