From e8c0d473db398c11bcafb69fb8b510103572fe07 Mon Sep 17 00:00:00 2001 From: Benjamin Eckstein <13351939+benjamineckstein@users.noreply.github.com> Date: Mon, 9 Dec 2019 13:56:51 +0100 Subject: [PATCH] TSK-967: Refactor Taskana-Data module to merge SampleDataGenerator and TestDataGenerator --- .../test/java/acceptance/AbstractAccTest.java | 5 +- .../report/AbstractReportAccTest.java | 5 +- .../taskana/database/TestDataGenerator.java | 196 ------------------ .../pro/taskana/sampledata/SQLReplacer.java | 123 +++++++++++ .../sampledata/SampleDataGenerator.java | 123 +++++------ .../sampledata/SampleDataProvider.java | 56 +++-- .../sql/monitor-data}/monitor-sample-data.sql | 0 .../resources/sql/test-data}/attachment.sql | 0 .../sql/test-data}/classification.sql | 0 .../sql/test-data}/distribution-targets.sql | 0 .../sql/test-data}/object-reference.sql | 0 .../main/resources/sql/test-data}/task.sql | 0 .../sql/test-data}/workbasket-access-list.sql | 0 .../resources/sql/test-data}/workbasket.sql | 0 .../sampledata/SampleDataGeneratorTest.java | 18 +- .../taskana/jobs/AsyncUpdateJobIntTest.java | 8 +- 16 files changed, 231 insertions(+), 303 deletions(-) delete mode 100644 lib/taskana-core/src/test/java/pro/taskana/database/TestDataGenerator.java create mode 100644 lib/taskana-data/src/main/java/pro/taskana/sampledata/SQLReplacer.java rename lib/{taskana-core/src/test/resources/sql => taskana-data/src/main/resources/sql/monitor-data}/monitor-sample-data.sql (100%) rename lib/{taskana-core/src/test/resources/sql => taskana-data/src/main/resources/sql/test-data}/attachment.sql (100%) rename lib/{taskana-core/src/test/resources/sql => taskana-data/src/main/resources/sql/test-data}/classification.sql (100%) rename lib/{taskana-core/src/test/resources/sql => taskana-data/src/main/resources/sql/test-data}/distribution-targets.sql (100%) rename lib/{taskana-core/src/test/resources/sql => taskana-data/src/main/resources/sql/test-data}/object-reference.sql (100%) rename lib/{taskana-core/src/test/resources/sql => taskana-data/src/main/resources/sql/test-data}/task.sql (100%) rename lib/{taskana-core/src/test/resources/sql => taskana-data/src/main/resources/sql/test-data}/workbasket-access-list.sql (100%) rename lib/{taskana-core/src/test/resources/sql => taskana-data/src/main/resources/sql/test-data}/workbasket.sql (100%) diff --git a/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java b/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java index 7a8a3881b..f2d7640b0 100644 --- a/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java @@ -22,10 +22,10 @@ import pro.taskana.TaskanaEngine; import pro.taskana.TaskanaEngine.ConnectionManagementMode; import pro.taskana.TimeInterval; import pro.taskana.configuration.TaskanaEngineConfiguration; -import pro.taskana.database.TestDataGenerator; import pro.taskana.exceptions.ClassificationNotFoundException; import pro.taskana.impl.configuration.TaskanaEngineConfigurationTest; import pro.taskana.sampledata.DBCleaner; +import pro.taskana.sampledata.SampleDataGenerator; /** * Base class for all acceptance tests. @@ -34,7 +34,6 @@ public abstract class AbstractAccTest { protected static TaskanaEngineConfiguration taskanaEngineConfiguration; protected static TaskanaEngine taskanaEngine; - protected static TestDataGenerator testDataGenerator = new TestDataGenerator(); @BeforeAll @BeforeClass @@ -55,7 +54,7 @@ public abstract class AbstractAccTest { taskanaEngine = taskanaEngineConfiguration.buildTaskanaEngine(); taskanaEngine.setConnectionManagementMode(ConnectionManagementMode.AUTOCOMMIT); dbCleaner.clearDb(dataSource, schemaName); - testDataGenerator.generateTestData(dataSource, schemaName); + new SampleDataGenerator(dataSource, schemaName).generateTestData(); } protected ObjectReference createObjectReference(String company, String system, String systemInstance, String type, diff --git a/lib/taskana-core/src/test/java/acceptance/report/AbstractReportAccTest.java b/lib/taskana-core/src/test/java/acceptance/report/AbstractReportAccTest.java index d84d1ec2c..5a821da03 100644 --- a/lib/taskana-core/src/test/java/acceptance/report/AbstractReportAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/report/AbstractReportAccTest.java @@ -10,9 +10,9 @@ import org.junit.jupiter.api.BeforeAll; import pro.taskana.TaskanaEngine; import pro.taskana.configuration.TaskanaEngineConfiguration; -import pro.taskana.database.TestDataGenerator; import pro.taskana.impl.configuration.TaskanaEngineConfigurationTest; import pro.taskana.sampledata.DBCleaner; +import pro.taskana.sampledata.SampleDataGenerator; /** * Abstract test class for all report building tests. @@ -42,7 +42,6 @@ public class AbstractReportAccTest { taskanaEngine = taskanaEngineConfiguration.buildTaskanaEngine(); taskanaEngine.setConnectionManagementMode(TaskanaEngine.ConnectionManagementMode.AUTOCOMMIT); cleaner.clearDb(dataSource, schemaName); - TestDataGenerator testDataGenerator = new TestDataGenerator(); - testDataGenerator.generateMonitoringTestData(dataSource); + new SampleDataGenerator(dataSource, schemaName).generateMonitorData(); } } diff --git a/lib/taskana-core/src/test/java/pro/taskana/database/TestDataGenerator.java b/lib/taskana-core/src/test/java/pro/taskana/database/TestDataGenerator.java deleted file mode 100644 index e4fbfb612..000000000 --- a/lib/taskana-core/src/test/java/pro/taskana/database/TestDataGenerator.java +++ /dev/null @@ -1,196 +0,0 @@ -package pro.taskana.database; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.sql.Connection; -import java.sql.SQLException; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.sql.DataSource; - -import org.apache.ibatis.jdbc.ScriptRunner; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import pro.taskana.impl.TaskanaEngineImpl; - -/** - * Generates the test data for integration and acceptance tests. - */ -public class TestDataGenerator { - - private static final Logger LOGGER = LoggerFactory.getLogger(TestDataGenerator.class); - private static final String SQL = "/sql"; - private static final String TASK = SQL + "/task.sql"; - private static final String WORKBASKET = SQL + "/workbasket.sql"; - private static final String DISTRIBUTION_TARGETS = SQL + "/distribution-targets.sql"; - private static final String WORKBASKET_ACCESS_LIST = SQL + "/workbasket-access-list.sql"; - private static final String CLASSIFICATION = SQL + "/classification.sql"; - private static final String OBJECT_REFERENCE = SQL + "/object-reference.sql"; - private static final String ATTACHMENT = SQL + "/attachment.sql"; - private static final String MONITOR_SAMPLE_DATA = SQL + "/monitor-sample-data.sql"; - private static SQLReplacer sqlReplacer; - - private StringWriter outWriter = new StringWriter(); - private PrintWriter logWriter; - private StringWriter errorWriter; - private PrintWriter errorLogWriter; - - public TestDataGenerator() { - this.logWriter = new PrintWriter(this.outWriter); - this.errorWriter = new StringWriter(); - this.errorLogWriter = new PrintWriter(this.errorWriter); - } - - public void generateTestData(DataSource dataSource, String schema) throws SQLException, IOException { - ScriptRunner runner = null; - try { - Connection connection = dataSource.getConnection(); - LOGGER.debug(connection.getMetaData().toString()); - connection.setSchema(schema); - runner = new ScriptRunner(connection); - runner.setStopOnError(true); - runner.setLogWriter(this.logWriter); - runner.setErrorLogWriter(this.errorLogWriter); - runner.setStopOnError(true); - runner.setLogWriter(this.logWriter); - runner.setErrorLogWriter(this.errorLogWriter); - - if (sqlReplacer == null) { - sqlReplacer = new SQLReplacer(connection.getMetaData().getDatabaseProductName()); - } - - Stream.of(sqlReplacer.classificationSql, sqlReplacer.workbasketSql, sqlReplacer.taskSql, - sqlReplacer.workbasketAccessListSql, sqlReplacer.distributionTargetSql, sqlReplacer.objectReferenceSql, - sqlReplacer.attachmentSql) - .map(s -> s.getBytes(StandardCharsets.UTF_8)) - .map(ByteArrayInputStream::new) - .map(InputStreamReader::new) - .forEach(runner::runScript); - - } finally { - if (runner != null) { - runner.closeConnection(); - } - LOGGER.debug(outWriter.toString()); - if (!errorWriter.toString().trim().isEmpty()) { - LOGGER.error(errorWriter.toString()); - } - } - } - - public void generateMonitoringTestData(DataSource dataSource) throws IOException, SQLException { - ScriptRunner runner = null; - try { - Connection connection = dataSource.getConnection(); - LOGGER.debug(connection.getMetaData().toString()); - runner = new ScriptRunner(connection); - runner.setStopOnError(true); - runner.setLogWriter(this.logWriter); - runner.setErrorLogWriter(this.errorLogWriter); - runner.setStopOnError(true); - runner.setLogWriter(this.logWriter); - runner.setErrorLogWriter(this.errorLogWriter); - - if (sqlReplacer == null) { - sqlReplacer = new SQLReplacer(connection.getMetaData().getDatabaseProductName()); - } - - runner.runScript( - new InputStreamReader( - new ByteArrayInputStream( - sqlReplacer.monitoringTestDataSql.getBytes(StandardCharsets.UTF_8)))); - } finally { - if (runner != null) { - runner.closeConnection(); - } - LOGGER.debug(outWriter.toString()); - if (!errorWriter.toString().trim().isEmpty()) { - LOGGER.error(errorWriter.toString()); - } - } - } - - /** - * This class replaces boolean values with int values if the database is db2. - */ - private static final class SQLReplacer { - - private static final String RELATIVE_DATE_REGEX = "RELATIVE_DATE\\((-?\\d+)\\)"; - private static final Pattern RELATIVE_DATE_PATTERN = Pattern.compile(RELATIVE_DATE_REGEX); - private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - - private String classificationSql; - private String workbasketSql; - private String taskSql; - private String workbasketAccessListSql; - private String distributionTargetSql; - private String objectReferenceSql; - private String attachmentSql; - private String monitoringTestDataSql; - - private SQLReplacer(String dbProductName) throws IOException { - boolean isDb2 = TaskanaEngineImpl.isDb2(dbProductName); - LocalDateTime now = LocalDateTime.now(); - classificationSql = parseAndReplace(getClass().getResourceAsStream(CLASSIFICATION), now, isDb2); - workbasketSql = parseAndReplace(getClass().getResourceAsStream(WORKBASKET), now, isDb2); - taskSql = parseAndReplace(getClass().getResourceAsStream(TASK), now, isDb2); - workbasketAccessListSql = parseAndReplace(getClass().getResourceAsStream(WORKBASKET_ACCESS_LIST), now, - isDb2); - distributionTargetSql = parseAndReplace(getClass().getResourceAsStream(DISTRIBUTION_TARGETS), now, isDb2); - objectReferenceSql = parseAndReplace(getClass().getResourceAsStream(OBJECT_REFERENCE), now, isDb2); - attachmentSql = parseAndReplace(getClass().getResourceAsStream(ATTACHMENT), now, isDb2); - monitoringTestDataSql = parseAndReplace(getClass().getResourceAsStream(MONITOR_SAMPLE_DATA), now, isDb2); - } - - /** - * This method resolves the custom sql function defined through this regex: {@value RELATIVE_DATE_REGEX}. - * Its parameter is a digit representing the relative offset of a given starting point date. - *
- * Yes, this can be done as an actual sql function, but that'd lead to a little more complexity - * (and thus we'd have to maintain the code for db compatibility ...) - * Since we're already replacing the boolean attributes of sql files this addition is not a huge computational cost. - * - * @param now anchor for relative date conversion. - * @param sql sql statement which may contain the above declared custom function. - * @return sql statement with the given function resolved, if the 'sql' parameter contained any. - */ - private static String replaceRelativeTimeFunction(LocalDateTime now, String sql) { - Matcher m = RELATIVE_DATE_PATTERN.matcher(sql); - StringBuffer sb = new StringBuffer(sql.length()); - while (m.find()) { - m.appendReplacement(sb, - "'" + now.plusDays(Long.parseLong(m.group(1))).format(DATE_TIME_FORMATTER) + "'"); - } - m.appendTail(sb); - return sb.toString(); - } - - private static String replaceBooleanWithInteger(String sql) { - return sql.replaceAll("(?i)true", "1").replaceAll("(?i)false", "0"); - } - - private static String parseAndReplace(InputStream stream, LocalDateTime now, boolean isDb2) throws IOException { - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream))) { - String sql = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator())); - if (isDb2) { - sql = replaceBooleanWithInteger(sql); - } - return replaceRelativeTimeFunction(now, sql); - } - } - - } - -} diff --git a/lib/taskana-data/src/main/java/pro/taskana/sampledata/SQLReplacer.java b/lib/taskana-data/src/main/java/pro/taskana/sampledata/SQLReplacer.java new file mode 100644 index 000000000..56ac4d7a4 --- /dev/null +++ b/lib/taskana-data/src/main/java/pro/taskana/sampledata/SQLReplacer.java @@ -0,0 +1,123 @@ +package pro.taskana.sampledata; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * This class replaces boolean values with int values if the database is db2. + */ +final class SQLReplacer { + + static final String RELATIVE_DATE_REGEX = "RELATIVE_DATE\\((-?\\d+)\\)"; + static final Pattern RELATIVE_DATE_PATTERN = Pattern.compile(RELATIVE_DATE_REGEX); + static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + + static String getScriptAsSql(String dbProductName, LocalDateTime now, String scriptPath) { + return parseAndReplace(SQLReplacer.class.getResourceAsStream(scriptPath), now, dbProductName); + } + + private SQLReplacer() { + } + + /** + * This method resolves the custom sql function defined through this regex: {@value RELATIVE_DATE_REGEX}. + * Its parameter is a digit representing the relative offset of a given starting point date. + * + * Yes, this can be done as an actual sql function, but that'd lead to a little more complexity + * (and thus we'd have to maintain the code for db compatibility ...) + * Since we're already replacing the boolean attributes of sql files this addition is not a huge computational cost. + * + * @param now anchor for relative date conversion. + * @param sql sql statement which may contain the above declared custom function. + * @return sql statement with the given function resolved, if the 'sql' parameter contained any. + */ + private static String replaceRelativeTimeFunction(LocalDateTime now, String sql) { + Matcher m = RELATIVE_DATE_PATTERN.matcher(sql); + StringBuffer sb = new StringBuffer(sql.length()); + while (m.find()) { + m.appendReplacement(sb, + "'" + now.plusDays(Long.parseLong(m.group(1))).format(DATE_TIME_FORMATTER) + "'"); + } + m.appendTail(sb); + return sb.toString(); + } + + private static String replaceBooleanWithInteger(String sql) { + return sql.replaceAll("(?i)true", "1").replaceAll("(?i)false", "0"); + } + + private static String parseAndReplace(InputStream stream, LocalDateTime now, String dbProductname) { + boolean isDb2 = isDb2(dbProductname); + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream))) { + String sql = bufferedReader.lines().collect(Collectors.joining(System.lineSeparator())); + if (isDb2) { + sql = replaceBooleanWithInteger(sql); + } + return replaceRelativeTimeFunction(now, sql); + } catch (IOException e) { + throw new RuntimeException("Scriptfile not found", e); + } + } + + static boolean isPostgreSQL(String databaseProductName) { + return "PostgreSQL".equals(databaseProductName); + } + + static boolean isDb2(String dbProductName) { + return dbProductName.contains("DB2"); + } + + /** + * This method resolves the custom sql function defined through this regex: {@value RELATIVE_DATE_REGEX}. Its + * parameter is a digit representing the relative offset of a given starting point date. + * + * Yes, this can be done as an actual sql function, but that'd lead to a little more complexity (and thus we'd have + * to maintain the code for db compatibility ...) Since we're already replacing the boolean attributes of sql files + * this addition is not a huge computational cost. + * + * @param now + * anchor for relative date conversion. + * @param sql + * sql statement which may contain the above declared custom function. + * @return sql statement with the given function resolved, if the 'sql' parameter contained any. + */ + static String replaceDatePlaceholder(LocalDateTime now, String sql) { + Matcher m = RELATIVE_DATE_PATTERN.matcher(sql); + StringBuffer sb = new StringBuffer(sql.length()); + while (m.find()) { + long daysToShift = Long.parseLong(m.group(1)); + String daysAsStringDate = formatToSqlDate(now, daysToShift); + m.appendReplacement(sb, daysAsStringDate); + } + m.appendTail(sb); + return sb.toString(); + } + + private static String formatToSqlDate(LocalDateTime now, long days) { + return "'" + now.plusDays(days).format(DATE_TIME_FORMATTER) + "'"; + } + + static String parseAndReplace(LocalDateTime now, String script) { + return replaceDatePlaceholder(now, + getScriptAsString(script)); + } + + private static String getScriptAsString(String script) { + return getScriptBufferedStream(script).lines().collect(Collectors.joining(System.lineSeparator())); + } + + static BufferedReader getScriptBufferedStream(String script) { + return Optional.ofNullable(SampleDataGenerator.class.getResourceAsStream(script)).map( + inputStream -> new BufferedReader( + new InputStreamReader(inputStream, StandardCharsets.UTF_8))).orElse(null); + } +} diff --git a/lib/taskana-data/src/main/java/pro/taskana/sampledata/SampleDataGenerator.java b/lib/taskana-data/src/main/java/pro/taskana/sampledata/SampleDataGenerator.java index 4071ecf0f..ca77b4b71 100644 --- a/lib/taskana-data/src/main/java/pro/taskana/sampledata/SampleDataGenerator.java +++ b/lib/taskana-data/src/main/java/pro/taskana/sampledata/SampleDataGenerator.java @@ -1,19 +1,16 @@ package pro.taskana.sampledata; -import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.InputStreamReader; import java.io.PrintWriter; -import java.io.StringReader; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.SQLException; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Optional; +import java.util.HashMap; +import java.util.List; import java.util.function.Consumer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -32,10 +29,11 @@ public class SampleDataGenerator { private static final String DB_CLEAR_TABLES_SCRIPT = "/sql/clear/clear-db.sql"; private static final String DB_DROP_TABLES_SCRIPT = "/sql/clear/drop-tables.sql"; - - static final String RELATIVE_DATE_REGEX = "RELATIVE_DATE\\((-?\\d+)\\)"; - static final Pattern RELATIVE_DATE_PATTERN = Pattern.compile(RELATIVE_DATE_REGEX); - static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + private static final String CHECK_HISTORY_EVENT_EXIST = "/sql/sample-data/check-history-event-exist.sql"; + public static final String CACHED_TEST = "TEST"; + public static final String CACHED_SAMPLE = "SAMPLE"; + public static final String CACHED_EVENTSAMPLE = "EVENTSAMPLE"; + public static final String CACHED_MONITOR = "MONITOR"; private final DataSource dataSource; private final LocalDateTime now; @@ -46,6 +44,8 @@ public class SampleDataGenerator { */ private final String schema; + private static HashMap