diff --git a/pom.xml b/pom.xml
index 5a8b4bc8..bcedfd8c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,6 +41,7 @@
transactionoutbox-guice
transactionoutbox-testing
transactionoutbox-acceptance
+
@@ -90,6 +91,12 @@
${junit.jupiter.version}
test
+
+ junit
+ junit
+ 4.13
+ test
+
org.mockito
mockito-all
diff --git a/transactionoutbox-core/src/main/java/com/gruelbox/transactionoutbox/spi/AbstractThreadLocalTransactionManager.java b/transactionoutbox-core/src/main/java/com/gruelbox/transactionoutbox/spi/AbstractThreadLocalTransactionManager.java
index 4fb5437f..e6117bbc 100644
--- a/transactionoutbox-core/src/main/java/com/gruelbox/transactionoutbox/spi/AbstractThreadLocalTransactionManager.java
+++ b/transactionoutbox-core/src/main/java/com/gruelbox/transactionoutbox/spi/AbstractThreadLocalTransactionManager.java
@@ -1,21 +1,28 @@
package com.gruelbox.transactionoutbox.spi;
-import com.gruelbox.transactionoutbox.*;
-import java.util.Deque;
-import java.util.LinkedList;
-import java.util.Optional;
+import com.gruelbox.transactionoutbox.NoTransactionActiveException;
+import com.gruelbox.transactionoutbox.ThreadLocalContextTransactionManager;
+import com.gruelbox.transactionoutbox.ThrowingTransactionalSupplier;
+import com.gruelbox.transactionoutbox.ThrowingTransactionalWork;
+import com.gruelbox.transactionoutbox.TransactionalSupplier;
+import com.gruelbox.transactionoutbox.TransactionalWork;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import lombok.extern.slf4j.Slf4j;
+import java.util.Deque;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentLinkedDeque;
+
@Slf4j
@SuperBuilder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class AbstractThreadLocalTransactionManager
implements ThreadLocalContextTransactionManager {
- private final ThreadLocal> transactions = ThreadLocal.withInitial(LinkedList::new);
+ private final ThreadLocal> transactions =
+ ThreadLocal.withInitial(ConcurrentLinkedDeque::new);
@Override
public final void inTransaction(Runnable runnable) {
diff --git a/transactionoutbox-performance/pom.xml b/transactionoutbox-performance/pom.xml
new file mode 100644
index 00000000..95763f7a
--- /dev/null
+++ b/transactionoutbox-performance/pom.xml
@@ -0,0 +1,149 @@
+
+
+
+ com.gruelbox
+ transactionoutbox-parent
+ ${revision}
+
+ 4.0.0
+ Transaction Outbox Performance Tests
+ jar
+ transactionoutbox-performance
+ A collection of performance tests to make sure there are no performance regressions and to show ideas for how to performance test your own implementation.
+
+
+ com.gruelbox
+ transactionoutbox-core
+ ${project.version}
+ test
+
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+ com.gruelbox
+ transactionoutbox-testing
+ ${project.version}
+ test
+
+
+ org.testcontainers
+ testcontainers
+
+
+ org.testcontainers
+ junit-jupiter
+
+
+ org.testcontainers
+ postgresql
+
+
+ org.testcontainers
+ oracle-xe
+
+
+ org.testcontainers
+ mysql
+
+
+ org.postgresql
+ postgresql
+
+
+ com.oracle.database.jdbc
+ ojdbc11
+
+
+ com.mysql
+ mysql-connector-j
+
+
+ com.h2database
+ h2
+
+
+ org.testcontainers
+ mssqlserver
+
+
+ com.microsoft.sqlserver
+ mssql-jdbc
+
+
+ org.jsmart
+ zerocode-tdd-jupiter
+ 1.3.44
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.17.2
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ compile
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ compile
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 3.5.1
+
+
+ org.apache.maven.surefire
+ surefire-junit-platform
+ 3.2.5
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.5.1
+
+
+ org.apache.maven.surefire
+ surefire-junit-platform
+ 3.2.5
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-report-plugin
+ 3.5.1
+
+
+ org.apache.maven.surefire
+ surefire-junit-platform
+ 3.2.5
+
+
+
+
+ org.apache.maven.plugins
+ maven-project-info-reports-plugin
+ 3.1.1
+
+
+
+
\ No newline at end of file
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/AbstractPerformanceTest.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/AbstractPerformanceTest.java
new file mode 100644
index 00000000..c1426b68
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/AbstractPerformanceTest.java
@@ -0,0 +1,34 @@
+package com.gruelbox.transactionoutbox.performance;
+
+import com.gruelbox.transactionoutbox.DefaultPersistor;
+import com.gruelbox.transactionoutbox.Dialect;
+import com.gruelbox.transactionoutbox.Persistor;
+import com.gruelbox.transactionoutbox.TransactionManager;
+import com.gruelbox.transactionoutbox.TransactionOutbox;
+import java.util.UUID;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+
+@Slf4j
+public abstract class AbstractPerformanceTest {
+ protected abstract Dialect dialect();
+
+ protected Persistor persistor = DefaultPersistor.builder().dialect(dialect()).build();
+
+ Persistor persistor() {
+ return persistor;
+ }
+
+ protected abstract TransactionManager txManager();
+
+ @Test
+ public void testInsertAndSelect() {
+ // Given
+ TransactionOutbox outbox =
+ TransactionOutbox.builder().transactionManager(txManager()).persistor(persistor()).build();
+
+ // When
+ txManager()
+ .inTransaction(tx -> outbox.schedule(Widget.class).widgetize(UUID.randomUUID().toString()));
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceH2.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceH2.java
new file mode 100644
index 00000000..1bad1172
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceH2.java
@@ -0,0 +1,25 @@
+package com.gruelbox.transactionoutbox.performance;
+
+import com.gruelbox.transactionoutbox.Dialect;
+import com.gruelbox.transactionoutbox.TransactionManager;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers
+public class TestDefaultPerformanceH2 extends AbstractPerformanceTest {
+ private final TransactionManager txManager =
+ TransactionManager.fromConnectionDetails(
+ "org.h2.Driver",
+ "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DEFAULT_LOCK_TIMEOUT=2000;LOB_TIMEOUT=2000;MV_STORE=TRUE",
+ "test",
+ "test");
+
+ @Override
+ protected TransactionManager txManager() {
+ return txManager;
+ }
+
+ @Override
+ protected Dialect dialect() {
+ return Dialect.H2;
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceMSSqlServer2017.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceMSSqlServer2017.java
new file mode 100644
index 00000000..c63148dd
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceMSSqlServer2017.java
@@ -0,0 +1,36 @@
+package com.gruelbox.transactionoutbox.performance;
+
+import com.gruelbox.transactionoutbox.Dialect;
+import com.gruelbox.transactionoutbox.TransactionManager;
+import org.junit.jupiter.api.BeforeAll;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers
+public class TestDefaultPerformanceMSSqlServer2017 extends AbstractPerformanceTest {
+
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getMSSQL2017Container();
+
+ private final TransactionManager txManager =
+ TransactionManager.fromConnectionDetails(
+ "com.mysql.cj.jdbc.Driver",
+ container.getJdbcUrl(),
+ container.getUsername(),
+ container.getPassword());
+
+ @Override
+ protected TransactionManager txManager() {
+ return txManager;
+ }
+
+ @Override
+ protected Dialect dialect() {
+ return Dialect.MS_SQL_SERVER;
+ }
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceMySql5.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceMySql5.java
new file mode 100644
index 00000000..08f57307
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceMySql5.java
@@ -0,0 +1,42 @@
+package com.gruelbox.transactionoutbox.performance;
+
+import com.gruelbox.transactionoutbox.Dialect;
+import com.gruelbox.transactionoutbox.TransactionManager;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers
+public class TestDefaultPerformanceMySql5 extends AbstractPerformanceTest {
+
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getMySql5Container();
+
+ private final TransactionManager txManager =
+ TransactionManager.fromConnectionDetails(
+ "com.mysql.cj.jdbc.Driver",
+ container.getJdbcUrl(),
+ container.getUsername(),
+ container.getPassword());
+
+ @Override
+ protected TransactionManager txManager() {
+ return txManager;
+ }
+
+ @Override
+ protected Dialect dialect() {
+ return Dialect.MY_SQL_5;
+ }
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ container.stop();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceMySql8.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceMySql8.java
new file mode 100644
index 00000000..62591331
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceMySql8.java
@@ -0,0 +1,36 @@
+package com.gruelbox.transactionoutbox.performance;
+
+import com.gruelbox.transactionoutbox.Dialect;
+import com.gruelbox.transactionoutbox.TransactionManager;
+import org.junit.jupiter.api.BeforeAll;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers
+public class TestDefaultPerformanceMySql8 extends AbstractPerformanceTest {
+
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getMySql8Container();
+
+ private final TransactionManager txManager =
+ TransactionManager.fromConnectionDetails(
+ "com.mysql.cj.jdbc.Driver",
+ container.getJdbcUrl(),
+ container.getUsername(),
+ container.getPassword());
+
+ @Override
+ protected TransactionManager txManager() {
+ return txManager;
+ }
+
+ @Override
+ protected Dialect dialect() {
+ return Dialect.MY_SQL_8;
+ }
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceOracle18.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceOracle18.java
new file mode 100644
index 00000000..22ad7376
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformanceOracle18.java
@@ -0,0 +1,36 @@
+package com.gruelbox.transactionoutbox.performance;
+
+import com.gruelbox.transactionoutbox.Dialect;
+import com.gruelbox.transactionoutbox.TransactionManager;
+import org.junit.jupiter.api.BeforeAll;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers
+public class TestDefaultPerformanceOracle18 extends AbstractPerformanceTest {
+
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getOracle18Container();
+
+ private final TransactionManager txManager =
+ TransactionManager.fromConnectionDetails(
+ "com.mysql.cj.jdbc.Driver",
+ container.getJdbcUrl(),
+ container.getUsername(),
+ container.getPassword());
+
+ @Override
+ protected TransactionManager txManager() {
+ return txManager;
+ }
+
+ @Override
+ protected Dialect dialect() {
+ return Dialect.ORACLE;
+ }
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformancePostgresql16.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformancePostgresql16.java
new file mode 100644
index 00000000..15145582
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/TestDefaultPerformancePostgresql16.java
@@ -0,0 +1,42 @@
+package com.gruelbox.transactionoutbox.performance;
+
+import com.gruelbox.transactionoutbox.Dialect;
+import com.gruelbox.transactionoutbox.TransactionManager;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers
+public class TestDefaultPerformancePostgresql16 extends AbstractPerformanceTest {
+
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getPostgres16Container();
+
+ private final TransactionManager txManager =
+ TransactionManager.fromConnectionDetails(
+ "com.mysql.cj.jdbc.Driver",
+ container.getJdbcUrl(),
+ container.getUsername(),
+ container.getPassword());
+
+ @Override
+ protected TransactionManager txManager() {
+ return txManager;
+ }
+
+ @Override
+ protected Dialect dialect() {
+ return Dialect.POSTGRESQL_9;
+ }
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ container.stop();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/Widget.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/Widget.java
new file mode 100644
index 00000000..55e51485
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/Widget.java
@@ -0,0 +1,9 @@
+package com.gruelbox.transactionoutbox.performance;
+
+public class Widget {
+ private String value;
+
+ public void widgetize(String value) {
+ this.value = value;
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestH2Test.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestH2Test.java
new file mode 100644
index 00000000..3eb88619
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestH2Test.java
@@ -0,0 +1,21 @@
+package com.gruelbox.transactionoutbox.performance.load;
+
+import com.gruelbox.transactionoutbox.performance.TestDefaultPerformanceH2;
+import org.jsmart.zerocode.core.domain.LoadWith;
+import org.jsmart.zerocode.core.domain.TestMapping;
+import org.jsmart.zerocode.core.domain.TestMappings;
+import org.jsmart.zerocode.jupiter.extension.ParallelLoadExtension;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+@LoadWith("load_generation.properties")
+@ExtendWith({ParallelLoadExtension.class})
+public class LoadTestH2Test {
+ @Test
+ @DisplayName("Testing Parallel Load")
+ @TestMappings({
+ @TestMapping(testClass = TestDefaultPerformanceH2.class, testMethod = "testInsertAndSelect")
+ })
+ public void testLoad() {}
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestMSSqlServer2017Test.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestMSSqlServer2017Test.java
new file mode 100644
index 00000000..f9c687f6
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestMSSqlServer2017Test.java
@@ -0,0 +1,40 @@
+package com.gruelbox.transactionoutbox.performance.load;
+
+import com.gruelbox.transactionoutbox.performance.ContainerUtils;
+import com.gruelbox.transactionoutbox.performance.TestDefaultPerformanceMSSqlServer2017;
+import org.jsmart.zerocode.core.domain.LoadWith;
+import org.jsmart.zerocode.core.domain.TestMapping;
+import org.jsmart.zerocode.core.domain.TestMappings;
+import org.jsmart.zerocode.jupiter.extension.ParallelLoadExtension;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+
+@LoadWith("load_generation.properties")
+@ExtendWith({ParallelLoadExtension.class})
+public class LoadTestMSSqlServer2017Test {
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getMSSQL2017Container();
+
+ @Test
+ @DisplayName("Testing Parallel Load")
+ @TestMappings({
+ @TestMapping(
+ testClass = TestDefaultPerformanceMSSqlServer2017.class,
+ testMethod = "testInsertAndSelect")
+ })
+ public void testLoad() {}
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ container.stop();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestMySql5Test.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestMySql5Test.java
new file mode 100644
index 00000000..94f5127d
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestMySql5Test.java
@@ -0,0 +1,38 @@
+package com.gruelbox.transactionoutbox.performance.load;
+
+import com.gruelbox.transactionoutbox.performance.ContainerUtils;
+import com.gruelbox.transactionoutbox.performance.TestDefaultPerformanceMySql5;
+import org.jsmart.zerocode.core.domain.LoadWith;
+import org.jsmart.zerocode.core.domain.TestMapping;
+import org.jsmart.zerocode.core.domain.TestMappings;
+import org.jsmart.zerocode.jupiter.extension.ParallelLoadExtension;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+
+@LoadWith("load_generation.properties")
+@ExtendWith({ParallelLoadExtension.class})
+public class LoadTestMySql5Test {
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getMySql5Container();
+
+ @Test
+ @DisplayName("Testing Parallel Load")
+ @TestMappings({
+ @TestMapping(testClass = TestDefaultPerformanceMySql5.class, testMethod = "testInsertAndSelect")
+ })
+ public void testLoad() {}
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ container.stop();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestMySql8Test.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestMySql8Test.java
new file mode 100644
index 00000000..96bb7860
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestMySql8Test.java
@@ -0,0 +1,38 @@
+package com.gruelbox.transactionoutbox.performance.load;
+
+import com.gruelbox.transactionoutbox.performance.ContainerUtils;
+import com.gruelbox.transactionoutbox.performance.TestDefaultPerformanceMySql8;
+import org.jsmart.zerocode.core.domain.LoadWith;
+import org.jsmart.zerocode.core.domain.TestMapping;
+import org.jsmart.zerocode.core.domain.TestMappings;
+import org.jsmart.zerocode.jupiter.extension.ParallelLoadExtension;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+
+@LoadWith("load_generation.properties")
+@ExtendWith({ParallelLoadExtension.class})
+public class LoadTestMySql8Test {
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getMySql8Container();
+
+ @Test
+ @DisplayName("Testing Parallel Load")
+ @TestMappings({
+ @TestMapping(testClass = TestDefaultPerformanceMySql8.class, testMethod = "testInsertAndSelect")
+ })
+ public void testLoad() {}
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ container.stop();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestOracle18Test.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestOracle18Test.java
new file mode 100644
index 00000000..0c215356
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestOracle18Test.java
@@ -0,0 +1,40 @@
+package com.gruelbox.transactionoutbox.performance.load;
+
+import com.gruelbox.transactionoutbox.performance.ContainerUtils;
+import com.gruelbox.transactionoutbox.performance.TestDefaultPerformanceOracle18;
+import org.jsmart.zerocode.core.domain.LoadWith;
+import org.jsmart.zerocode.core.domain.TestMapping;
+import org.jsmart.zerocode.core.domain.TestMappings;
+import org.jsmart.zerocode.jupiter.extension.ParallelLoadExtension;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+
+@LoadWith("load_generation.properties")
+@ExtendWith({ParallelLoadExtension.class})
+public class LoadTestOracle18Test {
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getOracle18Container();
+
+ @Test
+ @DisplayName("Testing Parallel Load")
+ @TestMappings({
+ @TestMapping(
+ testClass = TestDefaultPerformanceOracle18.class,
+ testMethod = "testInsertAndSelect")
+ })
+ public void testLoad() {}
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ container.stop();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestPostgresql16Test.java b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestPostgresql16Test.java
new file mode 100644
index 00000000..c05ba66e
--- /dev/null
+++ b/transactionoutbox-performance/src/test/java/com/gruelbox/transactionoutbox/performance/load/LoadTestPostgresql16Test.java
@@ -0,0 +1,40 @@
+package com.gruelbox.transactionoutbox.performance.load;
+
+import com.gruelbox.transactionoutbox.performance.ContainerUtils;
+import com.gruelbox.transactionoutbox.performance.TestDefaultPerformancePostgresql16;
+import org.jsmart.zerocode.core.domain.LoadWith;
+import org.jsmart.zerocode.core.domain.TestMapping;
+import org.jsmart.zerocode.core.domain.TestMappings;
+import org.jsmart.zerocode.jupiter.extension.ParallelLoadExtension;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+
+@LoadWith("load_generation.properties")
+@ExtendWith({ParallelLoadExtension.class})
+public class LoadTestPostgresql16Test {
+ @SuppressWarnings({"rawtypes"})
+ private static final JdbcDatabaseContainer container = ContainerUtils.getPostgres16Container();
+
+ @Test
+ @DisplayName("Testing Parallel Load")
+ @TestMappings({
+ @TestMapping(
+ testClass = TestDefaultPerformancePostgresql16.class,
+ testMethod = "testInsertAndSelect")
+ })
+ public void testLoad() {}
+
+ @BeforeAll
+ public static void beforeAll() {
+ container.start();
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ container.stop();
+ }
+}
diff --git a/transactionoutbox-performance/src/test/resources/load_generation.properties b/transactionoutbox-performance/src/test/resources/load_generation.properties
new file mode 100644
index 00000000..2c7311d9
--- /dev/null
+++ b/transactionoutbox-performance/src/test/resources/load_generation.properties
@@ -0,0 +1,4 @@
+number.of.threads=50
+ramp.up.period.in.seconds=50
+loop.count=2
+interactive.html.report.disabled=false
\ No newline at end of file
diff --git a/transactionoutbox-testing/src/main/java/com/gruelbox/transactionoutbox/testing/TestContainerUtils.java b/transactionoutbox-testing/src/main/java/com/gruelbox/transactionoutbox/testing/TestContainerUtils.java
new file mode 100644
index 00000000..15769963
--- /dev/null
+++ b/transactionoutbox-testing/src/main/java/com/gruelbox/transactionoutbox/testing/TestContainerUtils.java
@@ -0,0 +1,52 @@
+package com.gruelbox.transactionoutbox.testing;
+
+import java.time.Duration;
+import java.util.Map;
+import org.testcontainers.containers.JdbcDatabaseContainer;
+import org.testcontainers.containers.MSSQLServerContainer;
+import org.testcontainers.containers.MySQLContainer;
+import org.testcontainers.containers.OracleContainer;
+import org.testcontainers.containers.PostgreSQLContainer;
+
+public class TestContainerUtils {
+ private TestContainerUtils() {}
+
+ @SuppressWarnings({"rawtypes", "resource"})
+ public static JdbcDatabaseContainer getMySql5Container() {
+ return new MySQLContainer<>("mysql:5")
+ .withStartupTimeout(Duration.ofMinutes(5))
+ .withReuse(true)
+ .withTmpFs(Map.of("/var/lib/mysql", "rw"));
+ }
+
+ @SuppressWarnings({"rawtypes", "resource"})
+ public static JdbcDatabaseContainer getMySql8Container() {
+ return new MySQLContainer<>("mysql:8")
+ .withStartupTimeout(Duration.ofMinutes(5))
+ .withReuse(true)
+ .withTmpFs(Map.of("/var/lib/mysql", "rw"));
+ }
+
+ @SuppressWarnings({"rawtypes", "resource"})
+ public static JdbcDatabaseContainer getPostgres16Container() {
+ return (JdbcDatabaseContainer)
+ new PostgreSQLContainer("postgres:16")
+ .withStartupTimeout(Duration.ofHours(1))
+ .withReuse(true);
+ }
+
+ @SuppressWarnings({"rawtypes", "resource"})
+ public static JdbcDatabaseContainer getOracle18Container() {
+ return new OracleContainer("gvenzl/oracle-xe:18-slim-faststart")
+ .withStartupTimeout(Duration.ofHours(1))
+ .withReuse(true);
+ }
+
+ @SuppressWarnings({"rawtypes", "resource"})
+ public static JdbcDatabaseContainer getMSSQL2017Container() {
+ return new MSSQLServerContainer<>("mcr.microsoft.com/mssql/server:2017-latest")
+ .acceptLicense()
+ .withStartupTimeout(Duration.ofMinutes(5))
+ .withReuse(true);
+ }
+}