17.1.1SmileCdrContainer and SmileHarness Usage

 

This document provides examples and common usage patterns for working with SmileCdrContainer and SmileHarness in your tests.

17.1.1.1Basic Setup with JUnit 5

The most common way to use SmileCdrContainer is with JUnit 5's @Testcontainers and @Container annotations:

import ca.cdr.test.extensions.SmileCdrContainer;
import ca.cdr.test.app.harness.api.SmileHarness;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;

@Testcontainers
class MyTest {

    // Define the Docker tag to use 
    static String smilecdrVersion = "2025.02.R02";

    // Create and configure the container
    @Container
    private static SmileCdrContainer container = new SmileCdrContainer(smilecdrVersion);

    // Store the harness for use in tests
    private static SmileHarness harness;

    @BeforeAll
    public static void setup() {
        // Get the harness from the container
        harness = container.getHarness();
    }

    @Test
    public void testSomething() {
        // Use the harness to interact with Smile CDR
    }
}

17.1.2SmileCdrContainer Configuration Options

 

17.1.2.1Using Different Smile CDR Versions

You can specify which version of Smile CDR to use, which remote docker registry to use, and which tag to use:


// Using a default version of Smile CDR that the SmileCdrContainer selects.
SmileCdrContainer container = new SmileCdrContainer();

// Using the default registry with a specific Smile CDR version
SmileCdrContainer container = new SmileCdrContainer("2025.02.R02");

// Using a fully custom Docker registry, image, and tag. This can be useful if you have customized 
// the base docker image and host it yourself.
DockerImageName customImage = DockerImageName.parse("my-registry.com/my-image:my-tag");
SmileCdrContainer container = new SmileCdrContainer(customImage);

17.1.2.2Using a Custom Properties File

You can provide a custom properties file to configure the Smile CDR instance:

SmileCdrContainer container = new SmileCdrContainer()
    .withPropertiesFile("my-custom-config.properties");

The properties file must be available on the classpath. Please see the tutorial for examples.

17.1.2.3Using a Custom Harness Context

By default, the SmileCdrContainer will assume several things to bootstrap connectivity to the Smile CDR container. Specifically it assumes:

  • The port for the Admin JSON module is accessible via HTTP on port 9000 (the default).
  • Basic authentication is enabled.
  • The default username and password are used.

If the configuration you are using does not match the above, you must provide the new information to the Harness Context before building a Smile Harness

You can provide a custom HarnessContext to configure how the harness connects to Smile CDR:

String baseUrl = "http://localhost";
Integer adminJsonPort = 19000;
String adminUsername = "my-admin";
String adminPassword = "my-random-password";

HarnessContext context = new HarnessContext(baseUrl, adminJsonPort, adminUsername, adminPassword);

SmileCdrContainer container = new SmileCdrContainer("2025.02.R02")
    .withCustomHarnessContext(context);

17.1.2.4Loading custom interceptors

17.1.3Working with SmileHarness

 

Once you have a SmileHarness instance, you can use it to interact with the Smile CDR instance in various ways.

17.1.3.1Using FHIR Clients

// Get a FHIR client
IGenericClient fhirClient = harness.getFhirClient();

// Add authentication if needed
BasicAuthInterceptor authInterceptor = new BasicAuthInterceptor("username", "password");

// Register the interceptor
fhirClient.registerInterceptor(authInterceptor);

// Use the client to interact with FHIR resources
Bundle bundle = fhirClient.search()
    .forResource("Patient")
    .returnBundle(Bundle.class)
    .execute();

17.1.3.2Using the Admin JSON Client

// Get an Admin JSON client
AdminJsonRestClient adminClient = harness.getAdminJsonClient();

// Use the client to interact with the Admin API
NodeConfigurations config = adminClient.getNodeConfigurations();

17.1.3.3Using the HL7v2 REST Client

The HL7V2RestClient allows you to send HL7v2 messages to Smile CDR and process the responses. There are several ways to obtain and use this client.

17.1.3.3.1Getting an HL7v2 Client

// Get an HL7v2 REST client using the default port (7000)
HL7V2RestClient hl7v2Client = harness.getHL7V2RestClient();

// Get an HL7v2 REST client for a specific port
HL7V2RestClient hl7v2ClientWithPort = harness.getHL7V2RestClient(7001);

// Get an HL7v2 REST client for a specific module ID
HL7V2RestClient hl7v2ClientWithModuleId = harness.getHL7V2RestClient("hl7_endpoint_two");

17.1.3.3.2Sending a String Message

You can send an HL7v2 message as a raw string:

// Create a raw HL7v2 message as a string
String rawMessage = "MSH|^~\\&|TestApp|TestFacility|SmileCDR|SmileCDR|20230101120000||ADT^A01^ADT_A01|123456|P|2.5\r" +
        "PID|||12345||Smith^John||19800101|M";

// Send the message to the server
Message response = hl7v2Client.sendMessage(rawMessage);

// Verify the response is an acknowledgment
assertThat(response.getName()).contains("ACK");

17.1.3.3.3Creating and Sending an ADT Message

ADT (Admission, Discharge, Transfer) messages are commonly used in healthcare systems. Here's how to create and send an ADT_A01 message:

// Create a sample ADT_A01 (admission) message
ADT_A01 adt = new ADT_A01();
MSH msh = adt.getMSH();

// Set required MSH fields
msh.getFieldSeparator().setValue("|");
msh.getEncodingCharacters().setValue("^~\\&");
msh.getSendingApplication().getNamespaceID().setValue("TestApp");
msh.getSendingFacility().getNamespaceID().setValue("TestFacility");
msh.getReceivingApplication().getNamespaceID().setValue("SmileCDR");
msh.getReceivingFacility().getNamespaceID().setValue("SmileCDR");
msh.getDateTimeOfMessage().getTime().setValue("20230101120000");
msh.getMessageType().getMessageCode().setValue("ADT");
msh.getMessageType().getTriggerEvent().setValue("A01");
msh.getMessageType().getMessageStructure().setValue("ADT_A01");
msh.getMessageControlID().setValue("123456");
msh.getProcessingID().getProcessingID().setValue("P");
msh.getVersionID().getVersionID().setValue("2.5");

// Set patient information
adt.getPID().getPatientID().getIDNumber().setValue("12345");
adt.getPID().getPatientName(0).getFamilyName().getSurname().setValue("Smith");
adt.getPID().getPatientName(0).getGivenName().setValue("John");
adt.getPID().getDateTimeOfBirth().getTime().setValue("19800101");
adt.getPID().getAdministrativeSex().setValue("M");

// Send the message to the server
Message response = hl7v2Client.sendMessage(adt);

// Process the response
if (response.getName().contains("ACK")) {
    // Handle acknowledgment
    System.out.println("Message acknowledged");
} else {
    // Handle other response types
    System.out.println("Received response: " + response.getName());
}

17.1.3.3.4Using the Test Data Helper

Smile CDR provides a test data helper class that can generate sample HL7v2 messages for you:

// Get the FHIR context from the harness
FhirContext fhirContext = harness.getFhirContext();

// Create a test data helper
Hl7V2TestDataHelper testDataHelper = Hl7V2TestDataHelper.buildDefault(fhirContext);

// Create a sample ADT_A01 message using the helper
ADT_A01 adtA01 = testDataHelper.createAdtA01();

// Send the message to the server
Message response = hl7v2Client.sendMessage(adtA01);

The Hl7V2TestDataHelper provides methods for creating various types of HL7v2 messages with realistic test data, saving you the effort of manually populating all the required fields.

17.1.4Working with FHIR Contexts

 
// Get the FHIR context from the first found persistence module
FhirContext fhirContext = harness.getFhirContext();

// Get the FHIR context from a named persistence module
String persistenceModuleId = "my_persistence_r4_module";
FhirContext fhirContext = harness.getFhirContext(persistenceModuleId);

17.1.4.1Port Mapping

When working with Docker containers, port mapping is important to understand. The SmileCdrContainer maps container ports to host ports, and the SmileHarness handles this mapping for you:

// Get a FHIR client for a specific port
IGenericClient fhirClient = harness.getFhirClient(8000);

// The harness automatically maps the container port to the host port
String serverBase = fhirClient.getServerBase();
// serverBase will be something like "http://localhost:32789"

You can also get the port mapping directly from the container:

Integer mappedFhirPort = container.getMappedPort(8000);

17.1.4.2Working with Multiple Modules

If your Smile CDR instance has multiple modules of the same type (e.g., multiple FHIR endpoints), you can specify which one to use:

// Get a FHIR client for a specific module by ID
IGenericClient fhirClient = harness.getFhirClient("my_endpoint_module");

// Get a FHIR client for a specific module by port
IGenericClient fhirClient = harness.getFhirClient(8010);

// Get a FHIR context for a specific module by ID
FhirContext fhirContext = harness.getFhirContext("my_persistence_module");

17.1.4.3Next Steps

For a step-by-step guide to writing tests with SmileCdrContainer and SmileHarness, see the tutorial.

For detailed information about the clients available through SmileHarness, see Available Clients.

For recommendations on effective testing with SmileCdrContainer and SmileHarness, see Best Practices.