package nl.ipo.cds.etl.process;
import java.net.URL;
import java.sql.Timestamp;
import java.util.Map;
import java.util.Properties;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import junit.framework.Assert;
import nl.idgis.commons.jobexecutor.AbstractJob;
import nl.idgis.commons.jobexecutor.Job;
import nl.idgis.commons.jobexecutor.JobDao;
import nl.idgis.commons.jobexecutor.JobLogger;
import nl.ipo.cds.categories.IntegrationTests;
import nl.ipo.cds.dao.ManagerDao;
import nl.ipo.cds.dao.attributemapping.AttributeMappingDao;
import nl.ipo.cds.domain.Bronhouder;
import nl.ipo.cds.domain.Dataset;
import nl.ipo.cds.domain.DatasetType;
import nl.ipo.cds.domain.EtlJob;
import nl.ipo.cds.domain.ImportJob;
import nl.ipo.cds.domain.RemoveJob;
import nl.ipo.cds.domain.Thema;
import nl.ipo.cds.etl.DatasetHandlers;
import nl.ipo.cds.etl.FeatureProcessor;
import nl.ipo.cds.etl.PersistableFeature;
import nl.ipo.cds.etl.featurecollection.FeatureCollection;
import nl.ipo.cds.executor.ConfigDir;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@ContextConfiguration(classes = ProcessTransactionTest.Config.class)
@Category(IntegrationTests.class)
/**
* NOT extending AbstractTransactionalJUnit4SpringContextTests to be able to test transactionality
*/
public class ProcessTransactionTest extends AbstractTransactionalJUnit4SpringContextTests {
protected static final String ABORT_MESSAGE = "Abort this Job";
private EntityManager entityManager;
private Long jobId;
private Long themaId;
@Configuration
@ComponentScan (basePackageClasses = { nl.ipo.cds.etl.config.Package.class })
@ImportResource ({
"classpath:/nl/ipo/cds/dao/dataSource-applicationContext.xml",
"classpath:/nl/ipo/cds/dao/dao-applicationContext.xml",
"classpath:/nl/ipo/cds/context/propertyConfigurer-test.xml" // Override ConfigDirPropertyPlaceholderConfigurer
})
public static class Config {
@Bean
public ConfigDir configDir () {
return new ConfigDir ("classpath:");
}
}
@PersistenceContext(unitName = "cds")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Autowired
private ManagerDao managerDao;
@Autowired
private HarvesterFactory harvesterFactory;
@Inject
private JobDao jobDao;
private FeatureProcessor featureProcessor;
private Properties logProperties;
private JobLogger logger;
@Before
public void testInitialization(){
Assert.assertNotNull(this.entityManager);
Assert.assertNotNull(this.managerDao);
logProperties = new Properties ();
featureProcessor = new FeatureProcessor() {
@Override
public boolean requiresFeatureProcessing(EtlJob job) {
return false;
}
@Override
public URL processUrl(EtlJob job) {
return null;
}
@Override
public int processFeatures(EtlJob job,
DatasetHandlers<PersistableFeature> datasetHandlers,
FeatureCollection features, JobLogger logger)
throws ValidationException {
return 0;
}
};
logger = new JobLogger () {
@Override
public void logString(Job job, String key, LogLevel logLevel, String message) {
}
@Override
public void logString(Job job, String key, LogLevel logLevel, String message, Map<String,Object> context) {
}
};
}
@Test
/**
* Make sure that the process runs within an transaction and that when a RuntimeException
* is raised, the transaction is rolled back
*/
public void testProcessJobAbortion() throws Exception {
ImportJob job = createJob();
this.jobId = job.getId();
ImportProcess process = new ImportProcess(managerDao, featureProcessor, logProperties) {
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean process(ImportJob job, final JobLogger logger) throws Exception {
// Simulate here the process is writing stuff to the database by inserting an Thema.
themaId = createThema();
// Simulate a RuntimeException
throw new RuntimeException(ABORT_MESSAGE);
}
};
try {
process.process(job, logger);
} catch (RuntimeException re) {
// Assert the Job is not rolled-back
AbstractJob reFoundJob = this.managerDao.getJob(this.jobId);
Assert.assertNotNull("Job could not be found again.", reFoundJob);
// Assert that insertion of the Thema is rolled-back
Thema refoundThema = managerDao.getThema(this.themaId);
Assert.assertNull("It's not correct that the Thema could be found again", refoundThema);
return;
}
// If we get here there was no RuntimeException
Assert.fail();
}
@Test
/**
* Make sure that the process runs within an transaction. If not,
* an javax.persistence.TransactionRequiredException is raised: "no transaction is in progress"
*/
public void testProcessJobSuccess() throws Exception {
ImportJob job = createJob();
this.jobId = job.getId();
ImportProcess process = new ImportProcess(managerDao, featureProcessor, logProperties) {
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean process(ImportJob job, final JobLogger logger) {
// Simulate here the process is writing stuff to the database by inserting a Thema.
themaId = createThema();
// Do NOT Simulate a RuntimeException
return false;
}
};
process.process(job, logger);
// Assert the Job is succesfull
Job reFoundJob = this.jobDao.getJob (this.jobId);
Assert.assertNotNull("Job could not be found again.", reFoundJob);
// Assert that insertion of the Thema is succeeded
Thema refoundThema = managerDao.getThema(this.themaId);
Assert.assertNotNull("The Thema could NOT be found again", refoundThema);
}
private ImportJob createJob() {
ImportJob job = new ImportJob();
job.setCreateTime(new Timestamp(System.currentTimeMillis()));
managerDao.create(job);
// entityManager.persist(job);
Assert.assertNotNull(job.getId());
Job reFoundJob = managerDao.getJob (job.getId());
Assert.assertNotNull("Job could not be found again.", reFoundJob);
// this.entityManager.flush();
return job;
}
private Long createThema() {
Thema thema = new Thema();
thema.setNaam("dummy");
managerDao.create(thema);
// entityManager.persist(thema);
// Assert the Thema is saved
Assert.assertNotNull(thema.getId());
// make sure Thema.naam stays unique
thema.setNaam(""+thema.getId());
// Make sure the Thema is committed to the database before it's reread again
managerDao.update(thema);
Thema reFoundthema = managerDao.getThema (thema.getId());
Assert.assertNotNull("Thema could not be found again.", reFoundthema);
// this.entityManager.flush();
return thema.getId();
}
}