Unit testing simple JPA route

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Unit testing simple JPA route

jpcook01
Hello,

I've spent a long time with this so this request is a bit of a last
resort.

I have a very simple route:
@Component
public class IngestRouteBuilder extends RouteBuilder {

     @Override
     public void configure() throws Exception {

         
from("seda:ingest_database_queue?concurrentConsumers={{seda.ingest.concurrent.consumers}}")
             .routeId("ingest-database-persisting")
             .to("jpa:esac.archive.p2sa.ingest.entity.ingest.IngestLog")
             .log(LoggingLevel.INFO, "Finished Inserting IngestLog")
             .bean(MessageBodySetterBean.class)
             
.recipientList(simple("file://${headers.FileDestination}/?fileName=${headers.Filename}"))
             .log(LoggingLevel.INFO, "Finished Ingesting File:
${headers.Filename}}");

     }

}

Which persists an entity to the database and moves a file somewhere.

My idea was to make use of @DataJpaTest which loads up all the in memory
database etc for unit tests and it nearly works.

This is my test (sorry to paste large code):
@RunWith(SpringRunner.class)
@DataJpaTest
//@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class IngestRouteBuilderTest extends CamelTestSupport {

     @Autowired
     private TestEntityManager entityManager;

     private static final String TARGET_DIR = "target/repository";
     @Override
     public void setUp() throws Exception {
         deleteDirectory(TARGET_DIR);
         super.setUp();
     }

     @Override
     public void tearDown() throws Exception {
         deleteDirectory(TARGET_DIR);
         super.tearDown();
     }

     @Override
     public String isMockEndpoints() {
         // override this method and return the pattern for which
endpoints to mock.
         return "file:" + TARGET_DIR + "*";
     }

     @Test
     public void testDeadLetterChannel() throws Exception {


         // This is a notify wait condition
         NotifyBuilder notify = new
NotifyBuilder(context).from("seda:*").whenDone(1).create();

         // notice we have automatic mocked all endpoints and the name of
the endpoints is "mock:uri"
         MockEndpoint mock = getMockEndpoint("mock:file:" + TARGET_DIR +
"/");
         mock.expectedMessageCount(1);

         // Mock the headers
         Map<String, Object> headers = new HashMap<>();
         headers.put(Constants.FILE_NAME_HEADER,
"lyra_20160708-000000_lev1_met.fits");
         headers.put(Constants.FILE_CONTENT_HEADER,
                     
TestUtils.getFile("/data/lyra/level1/lyra_20160708-000000_lev1_met.fits"));

         // Setup the exchange
         Exchange exchange = new DefaultExchange(context);
         exchange.getOut().setHeaders(headers);

         exchange.getIn().setBody(createIngestLog());

         // Send the message
         template.send("seda:ingest_database_queue", exchange);

         //unwrap.getSession().beginTransaction().begin();

         // Verify the outcome
         assertMockEndpointsSatisfied(5, TimeUnit.SECONDS);
         boolean done = notify.matches(5, TimeUnit.SECONDS);
         assertTrue("Should be done", done);
         assertTrue("File should exist", new
File("target/failed-test/lyra_20160708-000000_lev1_met.fits").exists());
     }

     @Override
     protected Properties useOverridePropertiesWithPropertiesComponent()
{
         Properties extra = new Properties();
         extra.put("seda.ingest.concurrent.consumers", "1");
         return extra;
     }

     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         JpaComponent component =
(JpaComponent)context.getComponent("jpa");
         
component.setEntityManagerFactory(entityManager.getEntityManager().getEntityManagerFactory());

         //Map<String, Object> properties =
entityManager.getEntityManager().getProperties();
         //EntityManagerFactory createEntityManagerFactory =
javax.persistence.Persistence.createEntityManagerFactory("camel",
properties);
         //component.setEntityManagerFactory(createEntityManagerFactory);


         IngestRouteBuilder route = new IngestRouteBuilder();
         //ReflectionTestUtils.setField(route, "failed",
"file:target/failed-test");
         return route;
     }

     private IngestLog createIngestLog() {
         IngestLog ingestLog = new IngestLog();
         ingestLog.setStatus(IngestStatus.INGEST_DONE.name());
         ingestLog.setDataType(DataType.SCIENCE.name());

         Instant ingested =
Instant.from(Instant.now().atOffset(ZoneOffset.UTC));
         ingestLog.setDateIngested(Date.from(ingested));
         ingestLog.setFileFormat(FileExtension.FITS.name());

         ingestLog.setFileName("filename");
         ingestLog.setFileSize(500);
         ingestLog.setPathStage("/stage/path");
         ingestLog.setPathRepository("/final/path");
         return ingestLog;
     }
}

It fails with the following error:
2018-04-10 17:37:19 WARN  o.a.c.component.seda.SedaConsumer - Error
processing exchange. Exchange[]. Caused by:
[javax.persistence.TransactionRequiredException - no transaction is in
progress]
javax.persistence.TransactionRequiredException: no transaction is in
progress
        at
org.hibernate.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3430)
        at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1397)
        at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1393)
        at
org.apache.camel.component.jpa.JpaProducer$2.doInTransaction(JpaProducer.java:247)
        at
org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
        at
org.apache.camel.component.jpa.JpaProducer.processEntity(JpaProducer.java:210)
        at
org.apache.camel.component.jpa.JpaProducer.process(JpaProducer.java:162)
        at
org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
...

I'm not really interested in transactions, however if I uncomment this
at the top //@Transactional(propagation = Propagation.NOT_SUPPORTED)
then I get a different failure - java.lang.IllegalStateException: No
transactional EntityManager found.

If I remove the test entity manager then I get the following error:\
endpoint: jpa://esac.archive.p2sa.ingest.entity.ingest.IngestLog.
Reason: javax.persistence.PersistenceException: No Persistence provider
for EntityManager named camel

I looked at some of the tests in the component and I don't see what I'm
doing differently really.

Thanks
Jonathan