SuperX-Kernmodul
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

341 lines
13 KiB

package de.superx;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.JDBCType;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.junit.Ignore;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.logging.KettleLogStore;
import org.postgresql.ds.common.PGObjectFactory;
import org.postgresql.util.PGobject;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions;
import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.dialect.PostgresDialect;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.zaxxer.hikari.HikariDataSource;
import de.superx.bianalysis.metadata.Identifier;
import de.superx.servlet.LogInit;
import de.superx.servlet.SuperXManager;
import de.superx.servlet.SxPools;
import de.superx.spring.TestUserServiceImpl;
import de.superx.spring.batch.His1DataSources;
import de.superx.spring.service.UserService;
import de.superx.util.PathAndFileUtils;
@Ignore
@Configuration
@EnableJdbcRepositories(basePackages = {"de.superx.jdbc.repository","de.superx.bianalysis.repository"} )
@ComponentScan(basePackages = "de.superx.spring.service,de.superx.rest,de.superx.bianalysis.service,de.superx.bianalysis.rest")
@Import(TestAppConfig.class)
public class TestApplicationConfigH2 extends AbstractJdbcConfiguration implements InitializingBean, DisposableBean{
protected static Logger logger;
public static final String TEST_MANDANTEN_ID = "test";
private static String dbPath = String.join(File.separator, "test", "resources", "db") + File.separator;
private static String DB_SUFFIX = ".mv.db";
private static String DB_TRACE_SUFFIX = ".trace.db";
private static String DB_TEMPLATE = "head_eduetl";
private long startThreadId;
@Bean
public UserService userService() {
return new TestUserServiceImpl();
}
@Bean
DataSource dataSource() throws Exception {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:h2:./test/resources/db/" + getDbName() + ";MODE=POSTGRESQL;DATABASE_TO_LOWER=TRUE;NON_KEYWORDS=KEY,VALUE,YEAR;BUILTIN_ALIAS_OVERRIDE=TRUE");
ds.setUsername("sa");
ds.setPassword("");
if (!batchSchemaExists(ds)) {
createBatchSchema(ds);
}
return ds;
}
@Bean
His1DataSources dataSources() throws Exception {
Map<String, DataSource> dataSources = new HashMap<>();
dataSources.put("eduetl", dataSource());
His1DataSources h1d = new His1DataSources(dataSources);
return h1d;
}
@Bean
NamedParameterJdbcOperations operations() throws Exception {
return new NamedParameterJdbcTemplate(dataSource());
}
@Bean
PlatformTransactionManager transactionManager() throws Exception {
return new DataSourceTransactionManager(dataSource());
}
@Override
@Bean
public Dialect jdbcDialect(NamedParameterJdbcOperations operations) {
return PostgresDialect.INSTANCE;
}
@Override
public JdbcCustomConversions jdbcCustomConversions() {
return new JdbcCustomConversions(Arrays.asList(IntegerToBooleanConverter.INSTANCE,
BooleanToIntegerConverter.INSTANCE,
ShortToBooleanConverter.INSTANCE,
BooleanToShortConverter.INSTANCE,
IdentifierToString.INSTANCE,
StringToIdentifier.INSTANCE,
ArrayNodeToPGobjectConverter.INSTANCE,
PGobjectToArrayNodeConverter.INSTANCE
));
}
@ReadingConverter
enum IntegerToBooleanConverter implements Converter<Integer, Boolean> {
INSTANCE;
@Override
public Boolean convert(Integer source) {
if (source.equals(Integer.valueOf(1))) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
}
@WritingConverter
public enum BooleanToIntegerConverter implements Converter<Boolean, Integer> {
INSTANCE;
@Override
public Integer convert(Boolean source) {
Integer value =source != null && source.booleanValue() ? Integer.valueOf(1) : Integer.valueOf(0);
return value;
}
}
@ReadingConverter
enum ShortToBooleanConverter implements Converter<Short, Boolean> {
INSTANCE;
@Override
public Boolean convert(Short source) {
if (source.equals(Short.valueOf("1"))) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
}
@WritingConverter
public enum BooleanToShortConverter implements Converter<Boolean, Short> {
INSTANCE;
@Override
public Short convert(Boolean source) {
return (source != null && source.booleanValue()) ? Short.valueOf((short)1) : Short.valueOf((short)0);
}
}
@WritingConverter
enum IdentifierToString implements Converter<Identifier, String> {
INSTANCE;
@Override
public String convert(Identifier id) {
return id.composedId;
}
}
@ReadingConverter
enum StringToIdentifier implements Converter<String, Identifier> {
INSTANCE;
@Override
public Identifier convert(String source) {
return new Identifier(source);
}
}
protected static boolean batchSchemaExists(DataSource dataSource) {
boolean exists = false;
try(Connection con = dataSource.getConnection()) {
DatabaseMetaData meta = con.getMetaData();
ResultSet resultSet = meta.getTables(null, null, "batch_job_execution" , new String[] {"TABLE"});
exists = resultSet.next();
} catch (SQLException e) {
throw new RuntimeException("Couldn't check for table batch_job_execution", e);
}
return exists;
}
protected static void createBatchSchema(DataSource dataSource) {
try (Connection con = dataSource.getConnection()){
ScriptUtils.executeSqlScript(con, new ClassPathResource("/org/springframework/batch/core/schema-postgresql.sql"));
} catch (Exception e) {
e.printStackTrace();
}
}
protected void setupTestDb() throws IOException {
FileUtils.deleteQuietly(new File(dbPath + getDbName() + DB_TRACE_SUFFIX));
FileUtils.deleteQuietly(new File(dbPath + getDbName() + DB_SUFFIX));
Path from = FileSystems.getDefault().getPath(dbPath, DB_TEMPLATE + DB_SUFFIX);
Path to = FileSystems.getDefault().getPath(dbPath, getDbName() + DB_SUFFIX);
Files.copy(from, to);
}
private String getDbName() {
return DB_TEMPLATE + startThreadId;
}
@Override
public void afterPropertiesSet() throws Exception {
this.startThreadId = Thread.currentThread().getId();
System.setProperty("SX_LOG_TO_TMP", "true");
File webInfPath = new File(String.join(File.separator, "superx", "WEB-INF"));
File modulePath = new File(String.join(File.separator, "superx", "WEB-INF") + File.separator + PathAndFileUtils.MODULE_PATH);
SuperXManager.setWEB_INFPfad(webInfPath.getAbsolutePath());
SuperXManager.setModuleDir(modulePath.getAbsolutePath());
System.setProperty("log4j.configuration", "log4j_unittests.properties");
System.setProperty("log4j.debug", "true");
initLogging();
setupTestDb();
DataSource eduetl = dataSource();
SxPools.initTesting(eduetl);
initKettleEnv();
}
@Override
public void destroy() throws Exception {
logger.debug("Context Stop Event received.");
SxPools.closeAll();
FileUtils.deleteQuietly(new File(dbPath + getDbName() + DB_TRACE_SUFFIX));
FileUtils.deleteQuietly(new File(dbPath + getDbName() + DB_SUFFIX));
System.setProperty("SX_LOG_TO_TMP", "false");
if (KettleEnvironment.isInitialized()) {
KettleEnvironment.shutdown();
}
}
private final static void initKettleEnv() {
// init kettle environment
try {
System.setProperty("BI_KETTLE_PLUGIN_BASE_FOLDERS",
SuperXManager.getWEB_INFPfad() + File.separator + "kettle-plugins");
KettleEnvironment.init();
// init KettleLogStore
KettleLogStore.init();
logger.debug("Kettle environment sucessfully initialized.");
} catch (Exception e) {
logger.error("Couldn't initialize KettleEnvironment!", e);
}
}
private static void initLogging() {
File propertiesFile = new File("test/conf/log4j_unittests.properties");
LogInit.initLog4J(propertiesFile, System.getProperty("java.io.tmpdir"));
logger = Logger.getLogger(TestApplicationConfigH2.class);
logger.info("Log4J Init complete");
}
@ReadingConverter
enum PGobjectToArrayNodeConverter implements Converter<PGobject, ArrayNode> {
INSTANCE;
ObjectMapper mapper = new ObjectMapper();
@Override
public ArrayNode convert(PGobject source) {
if (source != null) {
PGobject pgObject = source;
String value = pgObject.getValue();
if (value == null || value.trim().isEmpty()) {
return mapper.createArrayNode(); // Empty array instead of null
}
try {
JsonNode node = mapper.readTree(value);
// Ensure it's always an ArrayNode
return node.isArray() ? (ArrayNode) node : mapper.createArrayNode();
} catch (IOException e) {
throw new RuntimeException("Failed to parse JSON", e);
}
}
return mapper.createArrayNode(); // Default empty array
}
}
@WritingConverter
enum ArrayNodeToPGobjectConverter implements Converter<ArrayNode, PGobject> {
INSTANCE;
@Override
public PGobject convert(ArrayNode source) {
if (source == null) return null;
PGobject pgObject = new PGobject();
pgObject.setType("jsonb");
try {
pgObject.setValue(new ObjectMapper().writeValueAsString(source));
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return pgObject;
}
}
}