package uk.nhs.kch.rassyeyanie.common.testing.unit;
import java.io.IOException;
import java.util.List;
import junit.framework.Assert;
import org.apache.camel.EndpointInject;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.hl7.HL7Constants;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.mockito.Mockito;
import uk.nhs.kch.rassyeyanie.framework.AbstractProcessor;
import uk.nhs.kch.rassyeyanie.framework.HL7VersionedDataFormat;
import uk.nhs.kch.rassyeyanie.framework.HapiUtil;
import uk.nhs.kch.rassyeyanie.framework.configuration.ConfigurationService;
import uk.nhs.kch.rassyeyanie.framework.dto.KeyValuePairItem;
import uk.nhs.kch.rassyeyanie.framework.repository.KeyValueItemRepository;
import uk.nhs.kch.rassyeyanie.framework.repository.RepositoryFactoryInterface;
import uk.nhs.kch.rassyeyanie.framework.repository.RepositoryInterface;
import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.AbstractGroup;
import ca.uhn.hl7v2.model.AbstractMessage;
import ca.uhn.hl7v2.model.AbstractSegment;
import ca.uhn.hl7v2.model.Structure;
import ca.uhn.hl7v2.parser.EncodingNotSupportedException;
import ca.uhn.hl7v2.parser.PipeParser;
public class AbstractHl7Test
extends CamelTestSupport
{
@EndpointInject(uri = "mock:result")
protected MockEndpoint endpoint;
@Produce(uri = "direct:start")
protected ProducerTemplate template;
protected String actualSource;
protected String expected;
protected AbstractProcessor[] processors;
protected PipeParser pipeParser;
final String actualSourcePath;
final String expectedPath;
protected static RepositoryFactoryInterface repositoryFactory;
protected static RepositoryInterface<KeyValuePairItem> keyValueRepository;
protected static ConfigurationService configurationService;
protected AbstractMessage expectedMessage;
protected AbstractMessage actualMessage;
private String sendingApplication;
private String sendingFacility;
private String receivingApplication;
private String receivingFacility;
private String timestamp;
private String security;
private String messageType;
private String triggerEvent;
private String messageControl;
private String processingId;
private String versionId;
private String patientInternalId;
private String patientExternalId;
protected String getSendingApplication()
{
return this.sendingApplication;
}
protected void setSendingApplication(String sendingApplication)
{
this.sendingApplication = sendingApplication;
}
protected String getSendingFacility()
{
return this.sendingFacility;
}
protected void setSendingFacility(String sendingFacility)
{
this.sendingFacility = sendingFacility;
}
protected String getReceivingApplication()
{
return this.receivingApplication;
}
protected void setReceivingApplication(String receivingApplication)
{
this.receivingApplication = receivingApplication;
}
protected String getReceivingFacility()
{
return this.receivingFacility;
}
protected void setReceivingFacility(String receivingFacility)
{
this.receivingFacility = receivingFacility;
}
protected String getTimestamp()
{
return this.timestamp;
}
protected void setTimestamp(String timestamp)
{
this.timestamp = timestamp;
}
protected String getSecurity()
{
return this.security;
}
protected void setSecurity(String security)
{
this.security = security;
}
protected String getMessageType()
{
return this.messageType;
}
protected void setMessageType(String messageType)
{
this.messageType = messageType;
}
protected String getTriggerEvent()
{
return this.triggerEvent;
}
protected void setTriggerEvent(String triggerEvent)
{
this.triggerEvent = triggerEvent;
}
protected String getMessageControl()
{
return this.messageControl;
}
protected void setMessageControl(String messageControl)
{
this.messageControl = messageControl;
}
protected String getProcessingId()
{
return this.processingId;
}
protected void setProcessingId(String processingId)
{
this.processingId = processingId;
}
protected String getVersionId()
{
return this.versionId;
}
protected void setVersionId(String versionId)
{
this.versionId = versionId;
}
protected String getPatientInternalId()
{
return this.patientInternalId;
}
protected void setPatientInternalId(String patientInternalId)
{
this.patientInternalId = patientInternalId;
}
protected String getPatientExternalId()
{
return this.patientExternalId;
}
protected void setPatientExternalId(String patientExternalId)
{
this.patientExternalId = patientExternalId;
}
public AbstractHl7Test(String actualSourcePath, String expectedPath)
{
this.actualSourcePath = actualSourcePath;
this.expectedPath = expectedPath;
repositoryFactory = Mockito.mock(RepositoryFactoryInterface.class);
keyValueRepository = Mockito.mock(KeyValueItemRepository.class);
Mockito
.stub(repositoryFactory.getKeyValuePairItemRepository())
.toReturn(keyValueRepository);
}
public static RouteBuilder
createRouteBuilder(final AbstractProcessor... processors)
{
return new RouteBuilder() {
@Override
public void configure()
{
HL7VersionedDataFormat hl7 = new HL7VersionedDataFormat();
hl7.setValidate(false);
hl7.setVersion("2.4");
RouteDefinition routeDefinition =
this.from("direct:start").unmarshal(hl7);
for (AbstractProcessor processor : processors)
{
processor.setRepositoryFactory(repositoryFactory);
routeDefinition.process(processor);
}
routeDefinition.to("mock:result");
}
};
}
public static String getClassResourceStream(Class<?> streamClass,
String string)
throws IOException
{
return IOUtils.toString(
streamClass.getClassLoader().getResourceAsStream(string)).replace(
'\n',
'\r');
}
public void setProcessors(AbstractProcessor... processors)
{
for (AbstractProcessor processor : processors)
this.pipeParser = processor.getParser();
this.processors = processors;
}
protected <T extends AbstractSegment> void
assertEqualFields(AbstractMessage expected,
AbstractMessage actual,
Class<T> clazz)
throws HL7Exception
{
Assert.assertEquals(
HapiUtil.getWithTerser(expected, clazz).encode(),
HapiUtil.getWithTerser(actual, clazz).encode());
}
@Override
protected RouteBuilder createRouteBuilder()
{
return createRouteBuilder(this.processors);
}
private AbstractMessage getExpectedMessage()
throws HL7Exception, EncodingNotSupportedException
{
return (AbstractMessage) this.pipeParser.parse(this.expected);
}
@Override
public void setUp()
throws Exception
{
super.setUp();
this.actualSource =
getClassResourceStream(this.getClass(), this.actualSourcePath);
this.expected =
getClassResourceStream(this.getClass(), this.expectedPath);
this.expectedMessage = this.getExpectedMessage();
this.endpoint.expectedBodiesReceived(this.expectedMessage.encode());
this.template.sendBody(this.actualSource);
this.actualMessage =
this.endpoint
.getExchanges()
.get(0)
.getIn()
.getBody(AbstractMessage.class);
}
public <T extends AbstractSegment> void segment_tester(Class<T> clazz)
throws Exception
{
this.assertEqualFields(this.expectedMessage, this.actualMessage, clazz);
}
protected <T extends Structure> void testStructureByIndex(int index,
Class<T> clazz)
throws HL7Exception
{
List<T> exepectedSegments =
HapiUtil.getAll(this.expectedMessage, clazz);
// re-eval to remove cleared segments
List<T> actualSegments =
HapiUtil.getAll((AbstractMessage) this.pipeParser
.parse(this.actualMessage.encode()), clazz);
if (exepectedSegments.size() < index + 1 ||
actualSegments.size() < index + 1)
return;
assertEquals(
((AbstractSegment) exepectedSegments.get(index)).encode(),
((AbstractSegment) actualSegments.get(index)).encode());
}
protected <T extends Structure> void
testStructureByIndex(String groupName,
int groupIndex,
Class<T> segmentClass,
int segmentIndex)
throws HL7Exception
{
Structure expectedSegment =
getGroupSegment(
groupIndex,
segmentIndex,
segmentClass,
groupName,
this.expectedMessage);
Structure actualSegment =
getGroupSegment(
groupIndex,
segmentIndex,
segmentClass,
groupName,
this.actualMessage);
assertEquals(
((AbstractSegment) expectedSegment).encode(),
((AbstractSegment) actualSegment).encode());
}
private static <T> Structure
getGroupSegment(int groupIndex,
int segmentInfex,
Class<T> clazz,
String string,
AbstractMessage expectedMessage)
throws HL7Exception
{
return ((AbstractGroup) expectedMessage.get(string, groupIndex)).get(
clazz.getSimpleName(),
segmentInfex);
}
private void header_tester(String headerId, String expectedHeaderValue)
{
assertEquals(expectedHeaderValue, this.endpoint
.getExchanges()
.get(0)
.getOut()
.getHeader(headerId));
}
@Test
public void test_message_to_message()
throws Exception
{
this.assertMockEndpointsSatisfied();
}
@Test
public void test_message_jms_header_msh_sending_application()
{
this.header_tester(
HL7Constants.HL7_SENDING_APPLICATION,
this.getSendingApplication());
}
@Test
public void test_message_jms_header_msh_sending_facility()
{
this.header_tester(
HL7Constants.HL7_SENDING_FACILITY,
this.getSendingFacility());
}
@Test
public void test_message_jms_header_msh_receiving_application()
{
this.header_tester(
HL7Constants.HL7_RECEIVING_APPLICATION,
this.getReceivingApplication());
}
@Test
public void test_message_jms_header_msh_receiving_facility()
{
this.header_tester(
HL7Constants.HL7_RECEIVING_FACILITY,
this.getReceivingFacility());
}
@Test
public void test_message_jms_header_msh_timestamp()
{
this.header_tester(HL7Constants.HL7_TIMESTAMP, this.getTimestamp());
}
@Test
public void test_message_jms_header_msh_security()
{
this.header_tester(HL7Constants.HL7_SECURITY, this.getSecurity());
}
@Test
public void test_message_jms_header_msh_messageType()
{
this
.header_tester(HL7Constants.HL7_MESSAGE_TYPE, this.getMessageType());
}
@Test
public void test_message_jms_header_msh_triggerEvent()
{
this.header_tester(
HL7Constants.HL7_TRIGGER_EVENT,
this.getTriggerEvent());
}
@Test
public void test_message_jms_header_msh_messageControl()
{
this.header_tester(
HL7Constants.HL7_MESSAGE_CONTROL,
this.getMessageControl());
}
@Test
public void test_message_jms_header_msh_processingId()
{
this.header_tester(
HL7Constants.HL7_PROCESSING_ID,
this.getProcessingId());
}
@Test
public void test_message_jms_header_msh_versionId()
{
this.header_tester(HL7Constants.HL7_VERSION_ID, this.getVersionId());
}
@Test
public void test_message_jms_header_pid_internal_Id()
{
this.header_tester(
"CamelHL7PatientInternalId",
this.getPatientInternalId());
}
@Test
public void test_message_jms_header_pid_external_Id()
{
this.header_tester(
"CamelHL7PatientExternalId",
this.getPatientExternalId());
}
protected WrappedMessage getExpected()
{
return new WrappedMessage(this.expectedMessage);
}
protected WrappedMessage getActual()
{
return new WrappedMessage(this.actualMessage);
}
protected void assertEquals(Structure expectedSegment,
Structure actualSegment)
throws HL7Exception
{
assertEquals(
((AbstractSegment) expectedSegment).encode(),
((AbstractSegment) actualSegment).encode());
}
}