From 95b34544b82cf56439954294e7342e1255969799 Mon Sep 17 00:00:00 2001 From: mherman22 Date: Tue, 19 Nov 2024 14:31:23 +0300 Subject: [PATCH] add state restoration of the db to the original state before test execution --- .../BaseWebContextSensitiveTest.java | 158 +++++++++++------- .../service/DictionaryServiceTest.java | 3 +- 2 files changed, 97 insertions(+), 64 deletions(-) diff --git a/src/test/java/org/openelisglobal/BaseWebContextSensitiveTest.java b/src/test/java/org/openelisglobal/BaseWebContextSensitiveTest.java index 7fd5ad192d..8516c80775 100644 --- a/src/test/java/org/openelisglobal/BaseWebContextSensitiveTest.java +++ b/src/test/java/org/openelisglobal/BaseWebContextSensitiveTest.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.InputStream; +import java.util.*; import javax.sql.DataSource; import org.dbunit.database.DatabaseConfig; import org.dbunit.database.DatabaseConnection; @@ -18,11 +19,15 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; +import org.springframework.test.context.transaction.AfterTransaction; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; +@Transactional(propagation = Propagation.NOT_SUPPORTED) @ContextConfiguration(classes = { BaseTestConfig.class, AppTestConfig.class }) @WebAppConfiguration @TestPropertySource("classpath:common.properties") @@ -37,6 +42,20 @@ public abstract class BaseWebContextSensitiveTest extends AbstractTransactionalJ protected MockMvc mockMvc; + private Map originalStateCache; + + private List tablesToRestore; + + protected BaseWebContextSensitiveTest() { + this.originalStateCache = new HashMap<>(); + this.tablesToRestore = new ArrayList<>(); + } + + protected BaseWebContextSensitiveTest(List tablesToRestore) { + this.originalStateCache = new HashMap<>(); + this.tablesToRestore = tablesToRestore != null ? tablesToRestore : new ArrayList<>(); + } + protected void setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build(); } @@ -55,59 +74,83 @@ public T mapFromJson(String json, Class clazz) throws IOException { } /** - * Executes a dataset from an XML file and inserts the data into the database. - * - *

- * This method loads the specified dataset file from the classpath, establishes - * a connection to the database, and performs a CLEAN_INSERT operation using the - * dataset. CLEAN_INSERT first clears the existing data in the tables referenced - * by the dataset and then inserts the new data. - *

- * - * @param datasetFilename the name of the XML dataset file to load from the - * classpath. - * @throws IllegalArgumentException if the specified dataset file cannot be - * found in the classpath. - * - * @throws Exception if any error occurs during database - * operations, including: Database connection - * failures, XML parsing errors, Data insertion - * failures, Resource cleanup issues - * - *

- * Usage: - *

- * - *
{@code
-     *     executeDataSet("test-dataset.xml");
-     * }
- * - *

- * The dataset file must be in a Flat XML - * format compatible with DBUnit. - *

- * - *

- * Example Dataset File: - *

- * - *
{@code
-     * 
-     *     
-     *     
-     * 
-     * }
- * - *

- * Note: - *

- *
    - *
  • The connection is configured to allow - * empty fields.
  • - *
  • Always closes the input stream and - * database connection to prevent resource - * leaks.
  • - *
+ * Executes a dataset with state management - preserves and restores the + * original state of affected tables after execution. + */ + protected void executeDataSetWithStateManagement(String datasetFilename) throws Exception { + if (datasetFilename == null) { + throw new NullPointerException("Please provide test dataset file to execute!"); + } + + IDatabaseConnection connection = null; + try { + connection = new DatabaseConnection(dataSource.getConnection()); + DatabaseConfig config = connection.getConfig(); + config.setProperty(DatabaseConfig.FEATURE_ALLOW_EMPTY_FIELDS, true); + + IDataSet newDataSet = loadDataSet(datasetFilename); + String[] tableNames = newDataSet.getTableNames(); + + // Backup current state of affected tables + IDataSet currentState = connection.createDataSet(tableNames); + originalStateCache.put(Arrays.toString(tableNames), currentState); + tablesToRestore.add(tableNames); + + executeDataSet(datasetFilename); + } finally { + if (connection != null) { + connection.close(); + } + } + } + + /** + * This method will be called after each transaction to restore the database + * state + */ + @AfterTransaction + @SuppressWarnings("unused") + protected void restoreDatabase() throws Exception { + try { + for (String[] tableNames : tablesToRestore) { + String key = Arrays.toString(tableNames); + IDataSet originalState = originalStateCache.get(key); + if (originalState != null) { + IDatabaseConnection connection = null; + try { + connection = new DatabaseConnection(dataSource.getConnection()); + DatabaseConfig config = connection.getConfig(); + config.setProperty(DatabaseConfig.FEATURE_ALLOW_EMPTY_FIELDS, true); + + DatabaseOperation.CLEAN_INSERT.execute(connection, originalState); + } finally { + if (connection != null) { + connection.close(); + } + } + originalStateCache.remove(key); + } + } + } finally { + originalStateCache.clear(); + tablesToRestore.clear(); + } + } + + /** + * Loads a dataset from an XML file. + */ + private IDataSet loadDataSet(String datasetFilename) throws Exception { + try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(datasetFilename)) { + if (inputStream == null) { + throw new IllegalArgumentException("Dataset file '" + datasetFilename + "' not found in classpath"); + } + return new FlatXmlDataSet(inputStream); + } + } + + /** + * Executes a dataset from an XML file. */ protected void executeDataSet(String datasetFilename) throws Exception { if (datasetFilename == null) { @@ -132,13 +175,4 @@ protected void executeDataSet(String datasetFilename) throws Exception { } } } - - /** - * Useful method to clear all data from specific tables - */ - protected void clearTable(String... tableNames) throws Exception { - for (String tableName : tableNames) { - jdbcTemplate.execute("DELETE FROM " + tableName); - } - } } diff --git a/src/test/java/org/openelisglobal/dictionary/service/DictionaryServiceTest.java b/src/test/java/org/openelisglobal/dictionary/service/DictionaryServiceTest.java index e4edd59b4d..c07eb500dd 100644 --- a/src/test/java/org/openelisglobal/dictionary/service/DictionaryServiceTest.java +++ b/src/test/java/org/openelisglobal/dictionary/service/DictionaryServiceTest.java @@ -20,7 +20,7 @@ public class DictionaryServiceTest extends BaseWebContextSensitiveTest { @Before public void setup() throws Exception { - executeDataSet("testdata/dictionary.xml"); + executeDataSetWithStateManagement("testdata/dictionary.xml"); } @Test @@ -188,5 +188,4 @@ public void update_shouldUpdateDictionaryWhenDictionaryFrozenCheckIsNotRequired( Assert.assertEquals("Y", dictionaryService.get("1").getIsActive()); Assert.assertEquals("INFLUENZA VIRUS A RNA DETECTEDetest", dictionaryService.get("1").getDictEntry()); } - }