diff --git a/core/flamingock-test-support/src/main/java/io/flamingock/support/context/TestContext.java b/core/flamingock-test-support/src/main/java/io/flamingock/support/context/TestContext.java
new file mode 100644
index 000000000..2c21f3e6d
--- /dev/null
+++ b/core/flamingock-test-support/src/main/java/io/flamingock/support/context/TestContext.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2025 Flamingock (https://www.flamingock.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.flamingock.support.context;
+
+import io.flamingock.internal.common.core.audit.AuditReader;
+import io.flamingock.internal.common.core.audit.AuditWriter;
+import io.flamingock.internal.core.builder.BuilderAccessor;
+import io.flamingock.support.domain.AuditEntryDefinition;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Context object that carries test execution data through the BDD stages.
+ *
+ *
This class encapsulates the builder accessor and preconditions, providing
+ * controlled access to only what each stage needs. It follows the principle of
+ * exposing behavior, not implementation details.
+ *
+ * Key design decisions:
+ *
+ * - No getter for {@code BuilderAccessor} - exposes only what's needed
+ * - Separate {@code getAuditReader()} and {@code getAuditWriter()} methods
+ * - Immutable preconditions list (defensive copy)
+ *
+ */
+public class TestContext {
+
+ private final BuilderAccessor builderAccessor;
+ private final List preconditions;
+
+ /**
+ * Creates a new test context with the given builder accessor and preconditions.
+ *
+ * @param builderAccessor the builder accessor for running and accessing audit store
+ * @param preconditions the list of audit entry definitions to insert as preconditions
+ */
+ public TestContext(BuilderAccessor builderAccessor, List preconditions) {
+ this.builderAccessor = builderAccessor;
+ this.preconditions = preconditions != null
+ ? new ArrayList<>(preconditions)
+ : new ArrayList<>();
+ }
+
+ /**
+ * Returns the audit reader for reading audit entries.
+ *
+ * @return the audit reader
+ */
+ public AuditReader getAuditReader() {
+ return builderAccessor.getAuditStore().getPersistence();
+ }
+
+ /**
+ * Returns the audit writer for writing audit entries.
+ *
+ * @return the audit writer
+ */
+ public AuditWriter getAuditWriter() {
+ return builderAccessor.getAuditStore().getPersistence();
+ }
+
+ /**
+ * Runs the change runner by building and executing it.
+ */
+ public void run() {
+ builderAccessor.run();
+ }
+
+ /**
+ * Returns an unmodifiable view of the preconditions.
+ *
+ * @return the preconditions list
+ */
+ public List getPreconditions() {
+ return Collections.unmodifiableList(preconditions);
+ }
+}
diff --git a/core/flamingock-test-support/src/main/java/io/flamingock/support/domain/AuditEntryDefinition.java b/core/flamingock-test-support/src/main/java/io/flamingock/support/domain/AuditEntryDefinition.java
index 6dfa0950d..0ec6816f7 100644
--- a/core/flamingock-test-support/src/main/java/io/flamingock/support/domain/AuditEntryDefinition.java
+++ b/core/flamingock-test-support/src/main/java/io/flamingock/support/domain/AuditEntryDefinition.java
@@ -22,8 +22,10 @@
import io.flamingock.api.annotations.Rollback;
import io.flamingock.api.annotations.TargetSystem;
import io.flamingock.internal.common.core.audit.AuditEntry;
+import io.flamingock.internal.common.core.audit.AuditTxType;
import java.lang.annotation.Annotation;
+import java.util.UUID;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
@@ -505,4 +507,48 @@ public String getOrder() {
public Boolean getTransactional() {
return transactional;
}
+
+ // ========== Conversion Methods ==========
+
+ /**
+ * Converts this definition to an {@link AuditEntry} for insertion into the audit store.
+ *
+ * Fields that are not set will use sensible defaults:
+ *
+ * - {@code executionId} - UUID-based if not specified
+ * - {@code stageId} - UUID-based if not specified
+ * - {@code createdAt} - current time if not specified
+ * - {@code executionMillis} - 0 if not specified
+ * - {@code executionHostname} - "test-host" if not specified
+ * - {@code type} - {@code ExecutionType.EXECUTION}
+ * - {@code txStrategy} - {@code AuditTxType.NON_TX}
+ * - {@code systemChange} - false
+ * - {@code recoveryStrategy} - {@code RecoveryStrategy.MANUAL_INTERVENTION} if not specified
+ *
+ *
+ * @return an {@link AuditEntry} instance representing this definition
+ */
+ public AuditEntry toAuditEntry() {
+ return new AuditEntry(
+ executionId != null ? executionId : "precondition-" + UUID.randomUUID().toString(),
+ stageId != null ? stageId : "precondition-stage-" + UUID.randomUUID().toString(),
+ changeId,
+ author,
+ createdAt != null ? createdAt : LocalDateTime.now(),
+ state,
+ AuditEntry.ExecutionType.EXECUTION,
+ className,
+ methodName,
+ executionMillis != null ? executionMillis : 0L,
+ executionHostname != null ? executionHostname : "test-host",
+ metadata,
+ false, // systemChange
+ errorTrace,
+ AuditTxType.NON_TX,
+ targetSystemId,
+ order,
+ recoveryStrategy != null ? recoveryStrategy : RecoveryStrategy.MANUAL_INTERVENTION,
+ transactional
+ );
+ }
}
diff --git a/core/flamingock-test-support/src/main/java/io/flamingock/support/precondition/PreconditionInserter.java b/core/flamingock-test-support/src/main/java/io/flamingock/support/precondition/PreconditionInserter.java
new file mode 100644
index 000000000..b00c86b05
--- /dev/null
+++ b/core/flamingock-test-support/src/main/java/io/flamingock/support/precondition/PreconditionInserter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2025 Flamingock (https://www.flamingock.io)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.flamingock.support.precondition;
+
+import io.flamingock.internal.common.core.audit.AuditWriter;
+import io.flamingock.support.domain.AuditEntryDefinition;
+
+import java.util.List;
+
+/**
+ * Inserts audit entry preconditions into the audit store before test execution.
+ *
+ * This class is responsible for converting {@link AuditEntryDefinition} instances
+ * to actual audit entries and inserting them into the audit store. It follows the
+ * dependency injection pattern by receiving the {@link AuditWriter} via constructor.
+ */
+public class PreconditionInserter {
+
+ private final AuditWriter auditWriter;
+
+ /**
+ * Creates a new precondition inserter with the given audit writer.
+ *
+ * @param auditWriter the audit writer to use for inserting entries
+ */
+ public PreconditionInserter(AuditWriter auditWriter) {
+ this.auditWriter = auditWriter;
+ }
+
+ /**
+ * Inserts the given preconditions into the audit store.
+ *
+ * Each {@link AuditEntryDefinition} is converted to an {@code AuditEntry}
+ * and written to the audit store. If the preconditions list is null or empty,
+ * this method does nothing.
+ *
+ * @param preconditions the list of audit entry definitions to insert
+ */
+ public void insert(List preconditions) {
+ if (preconditions == null || preconditions.isEmpty()) {
+ return;
+ }
+ for (AuditEntryDefinition definition : preconditions) {
+ auditWriter.writeEntry(definition.toAuditEntry());
+ }
+ }
+}
diff --git a/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/GivenStageImpl.java b/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/GivenStageImpl.java
index af772b6cc..cf7606896 100644
--- a/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/GivenStageImpl.java
+++ b/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/GivenStageImpl.java
@@ -16,6 +16,7 @@
package io.flamingock.support.stages;
import io.flamingock.internal.core.builder.BuilderAccessor;
+import io.flamingock.support.context.TestContext;
import io.flamingock.support.domain.AuditEntryDefinition;
import java.util.ArrayList;
@@ -41,7 +42,8 @@ public GivenStage andExistingAudit(AuditEntryDefinition... definitions) {
@Override
public WhenStage whenRun() {
- return new WhenStageImpl(builderAccessor);
+ TestContext testContext = new TestContext(builderAccessor, existingAudit);
+ return new WhenStageImpl(testContext);
}
/**
diff --git a/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/ThenStageImpl.java b/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/ThenStageImpl.java
index 0412e6f7c..f8f810ecb 100644
--- a/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/ThenStageImpl.java
+++ b/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/ThenStageImpl.java
@@ -15,8 +15,9 @@
*/
package io.flamingock.support.stages;
-import io.flamingock.internal.core.builder.BuilderAccessor;
+import io.flamingock.support.context.TestContext;
import io.flamingock.support.domain.AuditEntryDefinition;
+import io.flamingock.support.precondition.PreconditionInserter;
import io.flamingock.support.validation.ValidationHandler;
import io.flamingock.support.validation.Validator;
import io.flamingock.support.validation.ValidatorFactory;
@@ -29,11 +30,11 @@ final class ThenStageImpl implements ThenStage {
private final List validators = new ArrayList<>();
private final ValidatorFactory validatorFactory;
- private final BuilderAccessor builderAccessor;
+ private final TestContext testContext;
- ThenStageImpl(BuilderAccessor builderAccessor) {
- this.builderAccessor = builderAccessor;
- validatorFactory = new ValidatorFactory(builderAccessor);
+ ThenStageImpl(TestContext testContext) {
+ this.testContext = testContext;
+ validatorFactory = new ValidatorFactory(testContext.getAuditReader());
}
@Override
@@ -50,10 +51,13 @@ public ThenStage andExpectException(Class extends Throwable> exceptionClass, C
@Override
public void verify() throws AssertionError {
+ // Insert preconditions first
+ PreconditionInserter preconditionInserter = new PreconditionInserter(testContext.getAuditWriter());
+ preconditionInserter.insert(testContext.getPreconditions());
ValidationHandler validationHandler;
try {
- builderAccessor.run();
+ testContext.run();
validationHandler = new ValidationHandler(validators);
} catch (Throwable actualException) {
diff --git a/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/WhenStageImpl.java b/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/WhenStageImpl.java
index 5de71b4ab..69cb67bfa 100644
--- a/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/WhenStageImpl.java
+++ b/core/flamingock-test-support/src/main/java/io/flamingock/support/stages/WhenStageImpl.java
@@ -15,27 +15,27 @@
*/
package io.flamingock.support.stages;
-import io.flamingock.internal.core.builder.BuilderAccessor;
+import io.flamingock.support.context.TestContext;
import io.flamingock.support.domain.AuditEntryDefinition;
import java.util.function.Consumer;
public class WhenStageImpl implements WhenStage {
- private final BuilderAccessor builderAccessor;
+ private final TestContext testContext;
- WhenStageImpl(BuilderAccessor builderAccessor) {
- this.builderAccessor = builderAccessor;
+ WhenStageImpl(TestContext testContext) {
+ this.testContext = testContext;
}
@Override
public ThenStage thenExpectAuditSequenceStrict(AuditEntryDefinition... definitions) {
- return new ThenStageImpl(builderAccessor).andExpectAuditSequenceStrict(definitions);
+ return new ThenStageImpl(testContext).andExpectAuditSequenceStrict(definitions);
}
@Override
public ThenStage thenExpectException(Class extends Throwable> exceptionClass, Consumer validator) {
- return new ThenStageImpl(builderAccessor).andExpectException(exceptionClass, validator);
+ return new ThenStageImpl(testContext).andExpectException(exceptionClass, validator);
}
}
diff --git a/core/flamingock-test-support/src/main/java/io/flamingock/support/validation/ValidatorFactory.java b/core/flamingock-test-support/src/main/java/io/flamingock/support/validation/ValidatorFactory.java
index 475daa18e..bd226c436 100644
--- a/core/flamingock-test-support/src/main/java/io/flamingock/support/validation/ValidatorFactory.java
+++ b/core/flamingock-test-support/src/main/java/io/flamingock/support/validation/ValidatorFactory.java
@@ -15,7 +15,7 @@
*/
package io.flamingock.support.validation;
-import io.flamingock.internal.core.builder.BuilderAccessor;
+import io.flamingock.internal.common.core.audit.AuditReader;
import io.flamingock.support.domain.AuditEntryDefinition;
import io.flamingock.support.validation.impl.AuditSequenceStrictValidator;
import io.flamingock.support.validation.impl.DefaultExceptionValidator;
@@ -24,14 +24,14 @@
public class ValidatorFactory {
- private final BuilderAccessor builderAccessor;
+ private final AuditReader auditReader;
- public ValidatorFactory(BuilderAccessor builderAccessor) {
- this.builderAccessor = builderAccessor;
+ public ValidatorFactory(AuditReader auditReader) {
+ this.auditReader = auditReader;
}
public Validator getAuditSeqStrictValidator(AuditEntryDefinition... definitions) {
- return new AuditSequenceStrictValidator(builderAccessor.getAuditStore(), definitions);
+ return new AuditSequenceStrictValidator(auditReader, definitions);
}
public Validator getExceptionValidator(Class extends Throwable> exceptionClass, Consumer exceptionConsumer) {
diff --git a/core/flamingock-test-support/src/main/java/io/flamingock/support/validation/impl/AuditSequenceStrictValidator.java b/core/flamingock-test-support/src/main/java/io/flamingock/support/validation/impl/AuditSequenceStrictValidator.java
index 972418599..d8d89b853 100644
--- a/core/flamingock-test-support/src/main/java/io/flamingock/support/validation/impl/AuditSequenceStrictValidator.java
+++ b/core/flamingock-test-support/src/main/java/io/flamingock/support/validation/impl/AuditSequenceStrictValidator.java
@@ -15,7 +15,7 @@
*/
package io.flamingock.support.validation.impl;
-import io.flamingock.internal.core.store.AuditStore;
+import io.flamingock.internal.common.core.audit.AuditReader;
import io.flamingock.support.domain.AuditEntryDefinition;
import io.flamingock.support.validation.SimpleValidator;
import io.flamingock.support.validation.error.ValidationResult;
@@ -28,12 +28,12 @@ public class AuditSequenceStrictValidator implements SimpleValidator {
private static final String VALIDATOR_NAME = "Audit Sequence (Strict)";
- private final AuditStore> auditStore;
+ private final AuditReader auditReader;
private final List expectations;
- public AuditSequenceStrictValidator(AuditStore> auditStore, AuditEntryDefinition... definitions) {
- this.auditStore = auditStore;
+ public AuditSequenceStrictValidator(AuditReader auditReader, AuditEntryDefinition... definitions) {
+ this.auditReader = auditReader;
this.expectations = Arrays.stream(definitions)
.map(AuditEntryExpectation::new)
.collect(Collectors.toList());