Skip to content

Commit 5b546ed

Browse files
committed
feat: flamingock test support foundation WIP
1 parent b4b36b8 commit 5b546ed

File tree

11 files changed

+653
-0
lines changed

11 files changed

+653
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
dependencies {
2+
api(project(":core:flamingock-core"))
3+
4+
testImplementation(platform("org.junit:junit-bom:5.10.0"))
5+
testImplementation("org.junit.jupiter:junit-jupiter")
6+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
7+
}
8+
9+
description = "Test support module for Flamingock framework"
10+
11+
12+
tasks.withType<JavaCompile>().configureEach {
13+
if (name.contains("Test", ignoreCase = true)) {
14+
options.compilerArgs.addAll(listOf(
15+
"-Asources=${projectDir}/src/test/java",
16+
"-Aresources=${projectDir}/src/test/resources"
17+
))
18+
}
19+
}
20+
21+
java {
22+
toolchain {
23+
languageVersion.set(JavaLanguageVersion.of(8))
24+
}
25+
}
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
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.internal.core.builder;
17+
18+
import io.flamingock.api.annotations.Apply;
19+
import io.flamingock.internal.common.core.audit.AuditEntry;
20+
import io.flamingock.internal.common.core.audit.AuditTxType;
21+
22+
import java.time.LocalDateTime;
23+
24+
/**
25+
* Builder pattern for creating expected audit entry values in tests.
26+
* Relocated into flamingock-test-support module.
27+
*/
28+
public class AuditEntryExpectation {
29+
30+
private String expectedExecutionId;
31+
private String expectedStageId;
32+
private String expectedTaskId;
33+
private String expectedAuthor;
34+
private LocalDateTime expectedCreatedAt;
35+
private AuditEntry.Status expectedState;
36+
private AuditEntry.ExecutionType expectedType;
37+
private String expectedClassName;
38+
private String expectedMethodName;
39+
private Object expectedMetadata;
40+
private Long expectedExecutionMillis;
41+
private String expectedExecutionHostname;
42+
private String expectedErrorTrace;
43+
private Boolean expectedSystemChange;
44+
private AuditTxType expectedTxType;
45+
private String expectedTargetSystemId;
46+
47+
// Time range for flexible timestamp verification
48+
private LocalDateTime timestampAfter;
49+
private LocalDateTime timestampBefore;
50+
51+
// Flags for optional field verification
52+
private boolean shouldVerifyExecutionId = false;
53+
private boolean shouldVerifyStageId = false;
54+
private boolean shouldVerifyTimestamp = false;
55+
private boolean shouldVerifyExecutionMillis = false;
56+
private boolean shouldVerifyExecutionHostname = false;
57+
58+
AuditEntryExpectation() {}
59+
60+
public static AuditEntryExpectation auditEntry() {
61+
return new AuditEntryExpectation();
62+
}
63+
64+
public static AuditEntryExpectation STARTED(String taskId) {
65+
return new AuditEntryExpectation().withTaskId(taskId).withState(AuditEntry.Status.STARTED);
66+
}
67+
68+
public static AuditEntryExpectation APPLIED(String taskId) {
69+
return new AuditEntryExpectation().withTaskId(taskId).withState(AuditEntry.Status.APPLIED);
70+
}
71+
72+
public static AuditEntryExpectation FAILED(String taskId) {
73+
return new AuditEntryExpectation().withTaskId(taskId).withState(AuditEntry.Status.FAILED);
74+
}
75+
76+
public static AuditEntryExpectation ROLLED_BACK(String taskId) {
77+
return new AuditEntryExpectation().withTaskId(taskId).withState(AuditEntry.Status.ROLLED_BACK);
78+
}
79+
80+
public static AuditEntryExpectation ROLLBACK_FAILED(String taskId) {
81+
return new AuditEntryExpectation().withTaskId(taskId).withState(AuditEntry.Status.ROLLBACK_FAILED);
82+
}
83+
84+
@Deprecated
85+
public static AuditEntryExpectation started(String changeId) {
86+
return STARTED(changeId);
87+
}
88+
89+
@Deprecated
90+
public static AuditEntryExpectation applied(String changeId) {
91+
return APPLIED(changeId);
92+
}
93+
94+
@Deprecated
95+
public static AuditEntryExpectation failed(String changeId) {
96+
return FAILED(changeId);
97+
}
98+
99+
@Deprecated
100+
public static AuditEntryExpectation rolledBack(String changeId) {
101+
return ROLLED_BACK(changeId);
102+
}
103+
104+
// Identity fields
105+
public AuditEntryExpectation withExecutionId(String executionId) {
106+
this.expectedExecutionId = executionId;
107+
this.shouldVerifyExecutionId = true;
108+
return this;
109+
}
110+
111+
public AuditEntryExpectation withStageId(String stageId) {
112+
this.expectedStageId = stageId;
113+
this.shouldVerifyStageId = true;
114+
return this;
115+
}
116+
117+
public AuditEntryExpectation withTaskId(String taskId) {
118+
this.expectedTaskId = taskId;
119+
return this;
120+
}
121+
122+
// Metadata fields
123+
public AuditEntryExpectation withAuthor(String author) {
124+
this.expectedAuthor = author;
125+
return this;
126+
}
127+
128+
public AuditEntryExpectation withCreatedAt(LocalDateTime createdAt) {
129+
this.expectedCreatedAt = createdAt;
130+
this.shouldVerifyTimestamp = true;
131+
return this;
132+
}
133+
134+
public AuditEntryExpectation withTimestampBetween(LocalDateTime after, LocalDateTime before) {
135+
this.timestampAfter = after;
136+
this.timestampBefore = before;
137+
this.shouldVerifyTimestamp = true;
138+
return this;
139+
}
140+
141+
// State fields
142+
public AuditEntryExpectation withState(AuditEntry.Status state) {
143+
this.expectedState = state;
144+
return this;
145+
}
146+
147+
public AuditEntryExpectation withType(AuditEntry.ExecutionType type) {
148+
this.expectedType = type;
149+
return this;
150+
}
151+
152+
// Execution fields
153+
public AuditEntryExpectation withClassName(String className) {
154+
this.expectedClassName = className;
155+
return this;
156+
}
157+
158+
public AuditEntryExpectation withMethodName(String methodName) {
159+
this.expectedMethodName = methodName;
160+
return this;
161+
}
162+
163+
/**
164+
* Sets both className and methodName from a change class.
165+
* Finds method annotated with @Apply; if missing, throws RuntimeException.
166+
*/
167+
public AuditEntryExpectation withClass(Class<?> clazz) {
168+
this.expectedClassName = clazz.getName();
169+
170+
java.lang.reflect.Method[] methods = clazz.getDeclaredMethods();
171+
for (java.lang.reflect.Method method : methods) {
172+
if (method.isAnnotationPresent(Apply.class)) {
173+
this.expectedMethodName = method.getName();
174+
return this;
175+
}
176+
}
177+
178+
throw new RuntimeException(String.format("Class[%s] should contain a method annotated with @Apply", expectedClassName));
179+
}
180+
181+
public AuditEntryExpectation withMetadata(Object metadata) {
182+
this.expectedMetadata = metadata;
183+
return this;
184+
}
185+
186+
// Performance fields
187+
public AuditEntryExpectation withExecutionMillis(Long executionMillis) {
188+
this.expectedExecutionMillis = executionMillis;
189+
this.shouldVerifyExecutionMillis = true;
190+
return this;
191+
}
192+
193+
public AuditEntryExpectation withExecutionHostname(String hostname) {
194+
this.expectedExecutionHostname = hostname;
195+
this.shouldVerifyExecutionHostname = true;
196+
return this;
197+
}
198+
199+
// Error fields
200+
public AuditEntryExpectation withErrorTrace(String errorTrace) {
201+
this.expectedErrorTrace = errorTrace;
202+
return this;
203+
}
204+
205+
// System fields
206+
public AuditEntryExpectation withSystemChange(Boolean systemChange) {
207+
this.expectedSystemChange = systemChange;
208+
return this;
209+
}
210+
211+
// Transaction fields
212+
public AuditEntryExpectation withTxType(AuditTxType txStrategy) {
213+
this.expectedTxType = txStrategy;
214+
return this;
215+
}
216+
217+
public AuditEntryExpectation withTargetSystemId(String targetSystemId) {
218+
this.expectedTargetSystemId = targetSystemId;
219+
return this;
220+
}
221+
222+
// Getters for verification code
223+
public String getExpectedExecutionId() { return expectedExecutionId; }
224+
public String getExpectedStageId() { return expectedStageId; }
225+
public String getExpectedTaskId() { return expectedTaskId; }
226+
public String getExpectedAuthor() { return expectedAuthor; }
227+
public LocalDateTime getExpectedCreatedAt() { return expectedCreatedAt; }
228+
public AuditEntry.Status getExpectedState() { return expectedState; }
229+
public AuditEntry.ExecutionType getExpectedType() { return expectedType; }
230+
public String getExpectedClassName() { return expectedClassName; }
231+
public String getExpectedMethodName() { return expectedMethodName; }
232+
public Object getExpectedMetadata() { return expectedMetadata; }
233+
public Long getExpectedExecutionMillis() { return expectedExecutionMillis; }
234+
public String getExpectedExecutionHostname() { return expectedExecutionHostname; }
235+
public String getExpectedErrorTrace() { return expectedErrorTrace; }
236+
public Boolean getExpectedSystemChange() { return expectedSystemChange; }
237+
public AuditTxType getExpectedTxType() { return expectedTxType; }
238+
public String getExpectedTargetSystemId() { return expectedTargetSystemId; }
239+
240+
public LocalDateTime getTimestampAfter() { return timestampAfter; }
241+
public LocalDateTime getTimestampBefore() { return timestampBefore; }
242+
243+
public boolean shouldVerifyExecutionId() { return shouldVerifyExecutionId; }
244+
public boolean shouldVerifyStageId() { return shouldVerifyStageId; }
245+
public boolean shouldVerifyTimestamp() { return shouldVerifyTimestamp; }
246+
public boolean shouldVerifyExecutionMillis() { return shouldVerifyExecutionMillis; }
247+
public boolean shouldVerifyExecutionHostname() { return shouldVerifyExecutionHostname; }
248+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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.internal.core.builder;
17+
18+
import io.flamingock.internal.common.core.audit.AuditEntry;
19+
20+
public final class AuditExpectations {
21+
22+
private AuditExpectations() {}
23+
24+
public static AuditEntryExpectation applied(Class<?> changeClass) {
25+
return AuditEntryExpectation
26+
.auditEntry()
27+
.withClass(changeClass)
28+
.withState(AuditEntry.Status.APPLIED);
29+
}
30+
31+
public static AuditEntryExpectation failed(Class<?> changeClass) {
32+
return AuditEntryExpectation
33+
.auditEntry()
34+
.withClass(changeClass)
35+
.withState(AuditEntry.Status.FAILED);
36+
}
37+
38+
public static AuditEntryExpectation started(Class<?> changeClass) {
39+
return AuditEntryExpectation
40+
.auditEntry()
41+
.withClass(changeClass)
42+
.withState(AuditEntry.Status.STARTED);
43+
}
44+
45+
public static AuditEntryExpectation rolledBack(Class<?> changeClass) {
46+
return AuditEntryExpectation
47+
.auditEntry()
48+
.withClass(changeClass)
49+
.withState(AuditEntry.Status.ROLLED_BACK);
50+
}
51+
52+
public static AuditEntryExpectation rollbackFailed(Class<?> changeClass) {
53+
return AuditEntryExpectation
54+
.auditEntry()
55+
.withClass(changeClass)
56+
.withState(AuditEntry.Status.ROLLBACK_FAILED);
57+
}
58+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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.internal.core.builder;
17+
18+
import io.flamingock.internal.core.builder.change.AbstractChangeRunnerBuilder;
19+
20+
/**
21+
* Public entry point for the BDD-style test support.
22+
* Usage:
23+
* FlamingockTestSupport.given(builder).andAppliedChanges(...).whenRun()...
24+
*/
25+
public final class FlamingockTestSupport {
26+
27+
private FlamingockTestSupport() {
28+
}
29+
30+
/**
31+
* Starts the Given stage with the provided builder.
32+
* Returns the GivenStage interface (implementation present in the module).
33+
*
34+
* @param builder the change runner builder under test (must not be null)
35+
* @return GivenStage entry for fluent BDD flow
36+
* @throws NullPointerException if builder is null
37+
*/
38+
public static GivenStage given(AbstractChangeRunnerBuilder<?, ?> builder) {
39+
if (builder == null) {
40+
throw new NullPointerException("builder must not be null");
41+
}
42+
return new GivenStageImpl(builder);
43+
}
44+
}

0 commit comments

Comments
 (0)