diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TestUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TestUtil.java index 3e1347dafcb..be799f19e6e 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TestUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/TestUtil.java @@ -30,8 +30,10 @@ import org.slf4j.LoggerFactory; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Arrays; +import java.util.List; import java.util.Locale; import java.util.TimeZone; +import java.util.concurrent.atomic.AtomicInteger; import static org.apache.commons.lang3.StringUtils.defaultString; @@ -123,6 +125,27 @@ public class TestUtil { ourLog.info("Tests are using time zone: {}", TimeZone.getDefault().getID()); } + + /** + * THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE + *

+ * Strip \r chars from a string to account for line ending platform differences + */ + public static void waitForSize(int theTarget, AtomicInteger theInteger) { + long start = System.currentTimeMillis(); + while (theInteger.get() != theTarget && (System.currentTimeMillis() - start) <= 15000) { + try { + Thread.sleep(50); + } catch (InterruptedException theE) { + throw new Error(theE); + } + } + if ((System.currentTimeMillis() - start) >= 15000) { + throw new IllegalStateException("Size " + theInteger.get() + " is != target " + theTarget); + } + } + + /** * THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE *

diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/FhirContextDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/FhirContextDstu3Test.java index 7f7ed60152e..abf39e1c0df 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/FhirContextDstu3Test.java +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/context/FhirContextDstu3Test.java @@ -1,13 +1,8 @@ package ca.uhn.fhir.context; -import static org.junit.Assert.*; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import ca.uhn.fhir.rest.client.MyPatientWithExtensions; +import ca.uhn.fhir.util.OperationOutcomeUtil; +import ca.uhn.fhir.util.TestUtil; import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Reference; @@ -15,19 +10,21 @@ import org.hl7.fhir.dstu3.model.StructureDefinition; import org.junit.AfterClass; import org.junit.Test; -import ca.uhn.fhir.rest.client.MyPatientWithExtensions; -import ca.uhn.fhir.util.TestUtil; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.Assert.*; public class FhirContextDstu3Test { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirContextDstu3Test.class); private static FhirContext ourCtx = FhirContext.forDstu3(); - - @AfterClass - public static void afterClassClearContext() { - TestUtil.clearAllStaticFieldsForUnitTest(); - } - + @SuppressWarnings("deprecation") @Test public void testAutoDetectVersion() { @@ -35,6 +32,17 @@ public class FhirContextDstu3Test { assertEquals(FhirVersionEnum.DSTU3, ctx.getVersion().getVersion()); } + @Test + public void testCustomTypeDoesntBecomeDefault() { + FhirContext ctx = FhirContext.forDstu3(); + + MyPatientWithExtensions pt = new MyPatientWithExtensions(); + pt.addName().addGiven("FOO"); + ctx.newXmlParser().encodeResourceToString(pt); + + assertEquals(Patient.class, ctx.getResourceDefinition("Patient").getImplementingClass()); + } + /** * See #344 */ @@ -44,7 +52,7 @@ public class FhirContextDstu3Test { assertEquals(Reference.class, ourCtx.getElementDefinition("Reference").getImplementingClass()); assertEquals(Reference.class, ourCtx.getElementDefinition("REFerence").getImplementingClass()); } - + /** * See #344 */ @@ -57,73 +65,92 @@ public class FhirContextDstu3Test { } @Test - public void testCustomTypeDoesntBecomeDefault() { - FhirContext ctx = FhirContext.forDstu3(); - - MyPatientWithExtensions pt = new MyPatientWithExtensions(); - pt.addName().addGiven("FOO"); - ctx.newXmlParser().encodeResourceToString(pt); - - assertEquals(Patient.class, ctx.getResourceDefinition("Patient").getImplementingClass()); + public void testInitialisationThreadSafety() { + final FhirContext ctx = FhirContext.forDstu3(); + + final int numThreads = 40; + final List exceptions = Collections.synchronizedList(new ArrayList()); + final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads); + try { + final CountDownLatch threadsReady = new CountDownLatch(numThreads); + final CountDownLatch threadsFinished = new CountDownLatch(numThreads); + + for (int i = 0; i < numThreads; i++) { + threadPool.submit( + new Runnable() { + public void run() { + threadsReady.countDown(); + try { + threadsReady.await(); + RuntimeResourceDefinition def = ctx.getResourceDefinition("patient"); + ourLog.info(def.toString()); + assertNotNull(def); + } catch (final Exception e) { + exceptions.add(e); + } + threadsFinished.countDown(); + } + } + ); + } + + threadsFinished.await(); + } catch (final InterruptedException e) { + exceptions.add(e); + } finally { + threadPool.shutdownNow(); + } + + assertTrue("failed with exception(s): " + exceptions, exceptions.isEmpty()); } - + + /** + * See #794 + */ + @Test + public void testInitializeThreadSafety2() throws InterruptedException { + final FhirContext dstu3FhirContext = FhirContext.forDstu3(); + + final AtomicInteger count = new AtomicInteger(); + + for (int i = 0; i < 10; i++) { + new Thread(new Runnable() { + @Override + public void run() { + OperationOutcomeUtil.newInstance(dstu3FhirContext); + ourLog.info("Have finished {}", count.incrementAndGet()); + } + }).start(); + } + + TestUtil.waitForSize(10, count); + + } + @Test public void testQueryBoundCode() { RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class); String childName = "gender"; BaseRuntimeChildDatatypeDefinition genderChild = (BaseRuntimeChildDatatypeDefinition) patientType.getChildByName(childName); ourLog.trace(genderChild.getClass().getName()); - + assertEquals(AdministrativeGender.class, genderChild.getBoundEnumType()); } - + @Test public void testQueryNonBoundCode() { RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class); String childName = "name"; BaseRuntimeChildDatatypeDefinition genderChild = (BaseRuntimeChildDatatypeDefinition) patientType.getChildByName(childName); ourLog.trace(genderChild.getClass().getName()); - + assertEquals(null, genderChild.getBoundEnumType()); } - @Test - public void testInitialisationThreadSafety() { - final FhirContext ctx = FhirContext.forDstu3(); + @AfterClass + public static void afterClassClearContext() { + TestUtil.clearAllStaticFieldsForUnitTest(); + } - final int numThreads = 40; - final List exceptions = Collections.synchronizedList(new ArrayList()); - final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads); - try { - final CountDownLatch threadsReady = new CountDownLatch(numThreads); - final CountDownLatch threadsFinished = new CountDownLatch(numThreads); - for (int i = 0; i < numThreads; i++) { - threadPool.submit( - new Runnable() { - public void run() { - threadsReady.countDown(); - try { - threadsReady.await(); - RuntimeResourceDefinition def = ctx.getResourceDefinition("patient"); - ourLog.info(def.toString()); - assertNotNull(def); - } catch(final Exception e) { - exceptions.add(e); - } - threadsFinished.countDown(); - } - } - ); - } - - threadsFinished.await(); - } catch(final InterruptedException e) { - exceptions.add(e); - } finally { - threadPool.shutdownNow(); - } - - assertTrue("failed with exception(s): " + exceptions, exceptions.isEmpty()); - } }