Skip to content

Commit a606e53

Browse files
committed
refactor(test-support): add predonctions insertion
1 parent 6e5db25 commit a606e53

File tree

8 files changed

+226
-22
lines changed

8 files changed

+226
-22
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2025 Flamingock (https://www.flamingock.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.flamingock.support.context;
17+
18+
import io.flamingock.internal.common.core.audit.AuditReader;
19+
import io.flamingock.internal.common.core.audit.AuditWriter;
20+
import io.flamingock.internal.core.builder.BuilderAccessor;
21+
import io.flamingock.support.domain.AuditEntryDefinition;
22+
23+
import java.util.ArrayList;
24+
import java.util.Collections;
25+
import java.util.List;
26+
27+
/**
28+
* Context object that carries test execution data through the BDD stages.
29+
*
30+
* <p>This class encapsulates the builder accessor and preconditions, providing
31+
* controlled access to only what each stage needs. It follows the principle of
32+
* exposing behavior, not implementation details.</p>
33+
*
34+
* <p>Key design decisions:</p>
35+
* <ul>
36+
* <li>No getter for {@code BuilderAccessor} - exposes only what's needed</li>
37+
* <li>Separate {@code getAuditReader()} and {@code getAuditWriter()} methods</li>
38+
* <li>Immutable preconditions list (defensive copy)</li>
39+
* </ul>
40+
*/
41+
public class TestContext {
42+
43+
private final BuilderAccessor builderAccessor;
44+
private final List<AuditEntryDefinition> preconditions;
45+
46+
/**
47+
* Creates a new test context with the given builder accessor and preconditions.
48+
*
49+
* @param builderAccessor the builder accessor for running and accessing audit store
50+
* @param preconditions the list of audit entry definitions to insert as preconditions
51+
*/
52+
public TestContext(BuilderAccessor builderAccessor, List<AuditEntryDefinition> preconditions) {
53+
this.builderAccessor = builderAccessor;
54+
this.preconditions = preconditions != null
55+
? new ArrayList<>(preconditions)
56+
: new ArrayList<>();
57+
}
58+
59+
/**
60+
* Returns the audit reader for reading audit entries.
61+
*
62+
* @return the audit reader
63+
*/
64+
public AuditReader getAuditReader() {
65+
return builderAccessor.getAuditStore().getPersistence();
66+
}
67+
68+
/**
69+
* Returns the audit writer for writing audit entries.
70+
*
71+
* @return the audit writer
72+
*/
73+
public AuditWriter getAuditWriter() {
74+
return builderAccessor.getAuditStore().getPersistence();
75+
}
76+
77+
/**
78+
* Runs the change runner by building and executing it.
79+
*/
80+
public void run() {
81+
builderAccessor.run();
82+
}
83+
84+
/**
85+
* Returns an unmodifiable view of the preconditions.
86+
*
87+
* @return the preconditions list
88+
*/
89+
public List<AuditEntryDefinition> getPreconditions() {
90+
return Collections.unmodifiableList(preconditions);
91+
}
92+
}

core/flamingock-test-support/src/main/java/io/flamingock/support/domain/AuditEntryDefinition.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
import io.flamingock.api.annotations.Rollback;
2323
import io.flamingock.api.annotations.TargetSystem;
2424
import io.flamingock.internal.common.core.audit.AuditEntry;
25+
import io.flamingock.internal.common.core.audit.AuditTxType;
2526

2627
import java.lang.annotation.Annotation;
28+
import java.util.UUID;
2729
import java.lang.reflect.Method;
2830
import java.time.LocalDateTime;
2931

@@ -505,4 +507,48 @@ public String getOrder() {
505507
public Boolean getTransactional() {
506508
return transactional;
507509
}
510+
511+
// ========== Conversion Methods ==========
512+
513+
/**
514+
* Converts this definition to an {@link AuditEntry} for insertion into the audit store.
515+
*
516+
* <p>Fields that are not set will use sensible defaults:</p>
517+
* <ul>
518+
* <li>{@code executionId} - UUID-based if not specified</li>
519+
* <li>{@code stageId} - UUID-based if not specified</li>
520+
* <li>{@code createdAt} - current time if not specified</li>
521+
* <li>{@code executionMillis} - 0 if not specified</li>
522+
* <li>{@code executionHostname} - "test-host" if not specified</li>
523+
* <li>{@code type} - {@code ExecutionType.EXECUTION}</li>
524+
* <li>{@code txStrategy} - {@code AuditTxType.NON_TX}</li>
525+
* <li>{@code systemChange} - false</li>
526+
* <li>{@code recoveryStrategy} - {@code RecoveryStrategy.MANUAL_INTERVENTION} if not specified</li>
527+
* </ul>
528+
*
529+
* @return an {@link AuditEntry} instance representing this definition
530+
*/
531+
public AuditEntry toAuditEntry() {
532+
return new AuditEntry(
533+
executionId != null ? executionId : "precondition-" + UUID.randomUUID().toString(),
534+
stageId != null ? stageId : "precondition-stage-" + UUID.randomUUID().toString(),
535+
changeId,
536+
author,
537+
createdAt != null ? createdAt : LocalDateTime.now(),
538+
state,
539+
AuditEntry.ExecutionType.EXECUTION,
540+
className,
541+
methodName,
542+
executionMillis != null ? executionMillis : 0L,
543+
executionHostname != null ? executionHostname : "test-host",
544+
metadata,
545+
false, // systemChange
546+
errorTrace,
547+
AuditTxType.NON_TX,
548+
targetSystemId,
549+
order,
550+
recoveryStrategy != null ? recoveryStrategy : RecoveryStrategy.MANUAL_INTERVENTION,
551+
transactional
552+
);
553+
}
508554
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2025 Flamingock (https://www.flamingock.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.flamingock.support.precondition;
17+
18+
import io.flamingock.internal.common.core.audit.AuditWriter;
19+
import io.flamingock.support.domain.AuditEntryDefinition;
20+
21+
import java.util.List;
22+
23+
/**
24+
* Inserts audit entry preconditions into the audit store before test execution.
25+
*
26+
* <p>This class is responsible for converting {@link AuditEntryDefinition} instances
27+
* to actual audit entries and inserting them into the audit store. It follows the
28+
* dependency injection pattern by receiving the {@link AuditWriter} via constructor.</p>
29+
*/
30+
public class PreconditionInserter {
31+
32+
private final AuditWriter auditWriter;
33+
34+
/**
35+
* Creates a new precondition inserter with the given audit writer.
36+
*
37+
* @param auditWriter the audit writer to use for inserting entries
38+
*/
39+
public PreconditionInserter(AuditWriter auditWriter) {
40+
this.auditWriter = auditWriter;
41+
}
42+
43+
/**
44+
* Inserts the given preconditions into the audit store.
45+
*
46+
* <p>Each {@link AuditEntryDefinition} is converted to an {@code AuditEntry}
47+
* and written to the audit store. If the preconditions list is null or empty,
48+
* this method does nothing.</p>
49+
*
50+
* @param preconditions the list of audit entry definitions to insert
51+
*/
52+
public void insert(List<AuditEntryDefinition> preconditions) {
53+
if (preconditions == null || preconditions.isEmpty()) {
54+
return;
55+
}
56+
for (AuditEntryDefinition definition : preconditions) {
57+
auditWriter.writeEntry(definition.toAuditEntry());
58+
}
59+
}
60+
}

core/flamingock-test-support/src/main/java/io/flamingock/support/stages/GivenStageImpl.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package io.flamingock.support.stages;
1717

1818
import io.flamingock.internal.core.builder.BuilderAccessor;
19+
import io.flamingock.support.context.TestContext;
1920
import io.flamingock.support.domain.AuditEntryDefinition;
2021

2122
import java.util.ArrayList;
@@ -41,7 +42,8 @@ public GivenStage andExistingAudit(AuditEntryDefinition... definitions) {
4142

4243
@Override
4344
public WhenStage whenRun() {
44-
return new WhenStageImpl(builderAccessor);
45+
TestContext testContext = new TestContext(builderAccessor, existingAudit);
46+
return new WhenStageImpl(testContext);
4547
}
4648

4749
/**

core/flamingock-test-support/src/main/java/io/flamingock/support/stages/ThenStageImpl.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
*/
1616
package io.flamingock.support.stages;
1717

18-
import io.flamingock.internal.core.builder.BuilderAccessor;
18+
import io.flamingock.support.context.TestContext;
1919
import io.flamingock.support.domain.AuditEntryDefinition;
20+
import io.flamingock.support.precondition.PreconditionInserter;
2021
import io.flamingock.support.validation.ValidationHandler;
2122
import io.flamingock.support.validation.Validator;
2223
import io.flamingock.support.validation.ValidatorFactory;
@@ -29,11 +30,11 @@ final class ThenStageImpl implements ThenStage {
2930

3031
private final List<Validator> validators = new ArrayList<>();
3132
private final ValidatorFactory validatorFactory;
32-
private final BuilderAccessor builderAccessor;
33+
private final TestContext testContext;
3334

34-
ThenStageImpl(BuilderAccessor builderAccessor) {
35-
this.builderAccessor = builderAccessor;
36-
validatorFactory = new ValidatorFactory(builderAccessor);
35+
ThenStageImpl(TestContext testContext) {
36+
this.testContext = testContext;
37+
validatorFactory = new ValidatorFactory(testContext.getAuditReader());
3738
}
3839

3940
@Override
@@ -50,10 +51,13 @@ public ThenStage andExpectException(Class<? extends Throwable> exceptionClass, C
5051

5152
@Override
5253
public void verify() throws AssertionError {
54+
// Insert preconditions first
55+
PreconditionInserter preconditionInserter = new PreconditionInserter(testContext.getAuditWriter());
56+
preconditionInserter.insert(testContext.getPreconditions());
5357

5458
ValidationHandler validationHandler;
5559
try {
56-
builderAccessor.run();
60+
testContext.run();
5761
validationHandler = new ValidationHandler(validators);
5862

5963
} catch (Throwable actualException) {

core/flamingock-test-support/src/main/java/io/flamingock/support/stages/WhenStageImpl.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,27 @@
1515
*/
1616
package io.flamingock.support.stages;
1717

18-
import io.flamingock.internal.core.builder.BuilderAccessor;
18+
import io.flamingock.support.context.TestContext;
1919
import io.flamingock.support.domain.AuditEntryDefinition;
2020

2121
import java.util.function.Consumer;
2222

2323
public class WhenStageImpl implements WhenStage {
2424

25-
private final BuilderAccessor builderAccessor;
25+
private final TestContext testContext;
2626

27-
WhenStageImpl(BuilderAccessor builderAccessor) {
28-
this.builderAccessor = builderAccessor;
27+
WhenStageImpl(TestContext testContext) {
28+
this.testContext = testContext;
2929
}
3030

3131
@Override
3232
public ThenStage thenExpectAuditSequenceStrict(AuditEntryDefinition... definitions) {
33-
return new ThenStageImpl(builderAccessor).andExpectAuditSequenceStrict(definitions);
33+
return new ThenStageImpl(testContext).andExpectAuditSequenceStrict(definitions);
3434
}
3535

3636
@Override
3737
public ThenStage thenExpectException(Class<? extends Throwable> exceptionClass, Consumer<Throwable> validator) {
38-
return new ThenStageImpl(builderAccessor).andExpectException(exceptionClass, validator);
38+
return new ThenStageImpl(testContext).andExpectException(exceptionClass, validator);
3939
}
4040

4141
}

core/flamingock-test-support/src/main/java/io/flamingock/support/validation/ValidatorFactory.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package io.flamingock.support.validation;
1717

18-
import io.flamingock.internal.core.builder.BuilderAccessor;
18+
import io.flamingock.internal.common.core.audit.AuditReader;
1919
import io.flamingock.support.domain.AuditEntryDefinition;
2020
import io.flamingock.support.validation.impl.AuditSequenceStrictValidator;
2121
import io.flamingock.support.validation.impl.DefaultExceptionValidator;
@@ -24,14 +24,14 @@
2424

2525
public class ValidatorFactory {
2626

27-
private final BuilderAccessor builderAccessor;
27+
private final AuditReader auditReader;
2828

29-
public ValidatorFactory(BuilderAccessor builderAccessor) {
30-
this.builderAccessor = builderAccessor;
29+
public ValidatorFactory(AuditReader auditReader) {
30+
this.auditReader = auditReader;
3131
}
3232

3333
public Validator getAuditSeqStrictValidator(AuditEntryDefinition... definitions) {
34-
return new AuditSequenceStrictValidator(builderAccessor.getAuditStore(), definitions);
34+
return new AuditSequenceStrictValidator(auditReader, definitions);
3535
}
3636

3737
public Validator getExceptionValidator(Class<? extends Throwable> exceptionClass, Consumer<Throwable> exceptionConsumer) {

core/flamingock-test-support/src/main/java/io/flamingock/support/validation/impl/AuditSequenceStrictValidator.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package io.flamingock.support.validation.impl;
1717

18-
import io.flamingock.internal.core.store.AuditStore;
18+
import io.flamingock.internal.common.core.audit.AuditReader;
1919
import io.flamingock.support.domain.AuditEntryDefinition;
2020
import io.flamingock.support.validation.SimpleValidator;
2121
import io.flamingock.support.validation.error.ValidationResult;
@@ -28,12 +28,12 @@ public class AuditSequenceStrictValidator implements SimpleValidator {
2828

2929
private static final String VALIDATOR_NAME = "Audit Sequence (Strict)";
3030

31-
private final AuditStore<?> auditStore;
31+
private final AuditReader auditReader;
3232
private final List<AuditEntryExpectation> expectations;
3333

3434

35-
public AuditSequenceStrictValidator(AuditStore<?> auditStore, AuditEntryDefinition... definitions) {
36-
this.auditStore = auditStore;
35+
public AuditSequenceStrictValidator(AuditReader auditReader, AuditEntryDefinition... definitions) {
36+
this.auditReader = auditReader;
3737
this.expectations = Arrays.stream(definitions)
3838
.map(AuditEntryExpectation::new)
3939
.collect(Collectors.toList());

0 commit comments

Comments
 (0)