Skip to content

Commit d7c9e0b

Browse files
committed
feat: Mongock import to FlamingockCommunity(WIP: dynamodb test passing)
1 parent 7fc2306 commit d7c9e0b

File tree

5 files changed

+221
-268
lines changed

5 files changed

+221
-268
lines changed

legacy/mongock-importer-dynamodb/src/main/java/io/flamingock/importer/mongock/dynamodb/MongockAuditEntry.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,16 @@ public AuditEntry toAuditEntry() {
193193
LocalDateTime ts = LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault());
194194

195195
MongockChangeState stateEnum = MongockChangeState.valueOf(state);
196+
// Note: Mongock has BEFORE_EXECUTION and EXECUTION types, but Flamingock only has EXECUTION
197+
// Both Mongock types are mapped to Flamingock EXECUTION type
196198
return new AuditEntry(
197199
executionId,
198200
null,
199201
changeId,
200202
author,
201203
ts,
202204
stateEnum.toAuditStatus(),
203-
AuditEntry.ExecutionType.valueOf(type),
205+
AuditEntry.ExecutionType.EXECUTION,
204206
changeLogClass,
205207
changeSetMethod,
206208
executionMillis,

legacy/mongock-importer-dynamodb/src/test/java/io/flamingock/importer/mongock/dynamodb/DynamoDBImporterTest.java

Lines changed: 149 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 Flamingock (https://www.flamingock.io)
2+
* Copyright 2025 Flamingock (https://www.flamingock.io)
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,14 +18,15 @@
1818
import io.flamingock.api.annotations.EnableFlamingock;
1919
import io.flamingock.api.annotations.Stage;
2020
import io.flamingock.community.dynamodb.driver.DynamoDBAuditStore;
21-
import io.flamingock.importer.dynamodb.MongockDynamoDBAuditEntry;
22-
import io.flamingock.internal.common.core.audit.AuditEntry;
21+
import io.flamingock.core.kit.TestKit;
22+
import io.flamingock.core.kit.audit.AuditTestHelper;
23+
import io.flamingock.dynamodb.kit.DynamoDBTestKit;
2324
import io.flamingock.internal.common.core.error.FlamingockException;
24-
import io.flamingock.internal.core.builder.FlamingockFactory;
2525
import io.flamingock.internal.core.runner.Runner;
2626
import io.flamingock.support.mongock.annotations.MongockSupport;
27+
import io.flamingock.targetsystem.dynamodb.DynamoDBTargetSystem;
28+
import org.junit.jupiter.api.AfterEach;
2729
import org.junit.jupiter.api.Assertions;
28-
import org.junit.jupiter.api.BeforeAll;
2930
import org.junit.jupiter.api.BeforeEach;
3031
import org.junit.jupiter.api.Disabled;
3132
import org.junit.jupiter.api.Test;
@@ -36,16 +37,23 @@
3637
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
3738
import software.amazon.awssdk.regions.Region;
3839
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
39-
import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
40-
import software.amazon.awssdk.services.dynamodb.model.ScanResponse;
40+
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
41+
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
42+
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
43+
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
44+
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
45+
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
46+
import software.amazon.awssdk.services.dynamodb.model.KeyType;
47+
import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException;
48+
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
4149

4250
import java.net.URI;
43-
import java.time.Instant;
44-
import java.util.Arrays;
45-
import java.util.HashMap;
46-
import java.util.List;
4751

52+
import static io.flamingock.core.kit.audit.AuditEntryExpectation.APPLIED;
53+
import static io.flamingock.core.kit.audit.AuditEntryExpectation.STARTED;
54+
import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN;
4855
import static io.flamingock.internal.util.constants.CommunityPersistenceConstants.DEFAULT_AUDIT_STORE_NAME;
56+
import static io.flamingock.internal.util.constants.CommunityPersistenceConstants.DEFAULT_LOCK_STORE_NAME;
4957
import static org.junit.jupiter.api.Assertions.assertEquals;
5058
import static org.junit.jupiter.api.Assertions.assertTrue;
5159

@@ -58,16 +66,13 @@ public class DynamoDBImporterTest {
5866
public static final GenericContainer<?> dynamoDBContainer = new GenericContainer<>("amazon/dynamodb-local:latest")
5967
.withExposedPorts(8000);
6068

61-
public static final String MONGOCK_CHANGE_LOGS = "mongockChangeLogs";
62-
63-
6469
private static DynamoDbClient client;
65-
private DynamoDBTestHelper mongockChangeLogsHelper;
66-
67-
@BeforeAll
68-
static void beforeAll() {
69-
dynamoDBContainer.start();
70+
private DynamoDBMongockTestHelper mongockTestHelper;
71+
private TestKit testKit;
72+
private AuditTestHelper auditHelper;
7073

74+
@BeforeEach
75+
void setUp() {
7176
String endpoint = String.format("http://%s:%d",
7277
dynamoDBContainer.getHost(),
7378
dynamoDBContainer.getMappedPort(8000));
@@ -80,112 +85,152 @@ static void beforeAll() {
8085
)
8186
)
8287
.build();
88+
89+
// Create Mongock origin table for migration
90+
createMongockTable(DEFAULT_MONGOCK_ORIGIN);
91+
92+
// Create Flamingock audit and lock tables
93+
createAuditTable(DEFAULT_AUDIT_STORE_NAME);
94+
createLockTable(DEFAULT_LOCK_STORE_NAME);
95+
96+
mongockTestHelper = new DynamoDBMongockTestHelper(client, DEFAULT_MONGOCK_ORIGIN);
97+
98+
// Initialize TestKit for unified testing
99+
testKit = DynamoDBTestKit.create(client, new DynamoDBAuditStore(client));
100+
auditHelper = testKit.getAuditHelper();
83101
}
84102

85-
@BeforeEach
86-
void setUp() {
87-
mongockChangeLogsHelper = new DynamoDBTestHelper(client, MONGOCK_CHANGE_LOGS);
88-
mongockChangeLogsHelper.ensureTableExists();
89-
mongockChangeLogsHelper.resetTable();
103+
private void createMongockTable(String tableName) {
104+
try {
105+
client.createTable(CreateTableRequest.builder()
106+
.tableName(tableName)
107+
.keySchema(
108+
KeySchemaElement.builder()
109+
.attributeName("executionId")
110+
.keyType(KeyType.HASH)
111+
.build(),
112+
KeySchemaElement.builder()
113+
.attributeName("changeId")
114+
.keyType(KeyType.RANGE)
115+
.build()
116+
)
117+
.attributeDefinitions(
118+
AttributeDefinition.builder()
119+
.attributeName("executionId")
120+
.attributeType(ScalarAttributeType.S)
121+
.build(),
122+
AttributeDefinition.builder()
123+
.attributeName("changeId")
124+
.attributeType(ScalarAttributeType.S)
125+
.build()
126+
)
127+
.billingMode(BillingMode.PAY_PER_REQUEST)
128+
.build());
129+
} catch (ResourceInUseException ignored) {
130+
// Table already exists, ignore
131+
}
132+
}
90133

91-
new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).ensureTableExists();
92-
new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).resetTable();
134+
private void createAuditTable(String tableName) {
135+
try {
136+
client.createTable(CreateTableRequest.builder()
137+
.tableName(tableName)
138+
.keySchema(
139+
KeySchemaElement.builder()
140+
.attributeName("partitionKey")
141+
.keyType(KeyType.HASH)
142+
.build()
143+
)
144+
.attributeDefinitions(
145+
AttributeDefinition.builder()
146+
.attributeName("partitionKey")
147+
.attributeType(ScalarAttributeType.S)
148+
.build()
149+
)
150+
.billingMode(BillingMode.PAY_PER_REQUEST)
151+
.build());
152+
} catch (ResourceInUseException ignored) {
153+
// Table already exists, ignore
154+
}
155+
}
156+
157+
private void createLockTable(String tableName) {
158+
try {
159+
client.createTable(CreateTableRequest.builder()
160+
.tableName(tableName)
161+
.keySchema(
162+
KeySchemaElement.builder()
163+
.attributeName("partitionKey")
164+
.keyType(KeyType.HASH)
165+
.build()
166+
)
167+
.attributeDefinitions(
168+
AttributeDefinition.builder()
169+
.attributeName("partitionKey")
170+
.attributeType(ScalarAttributeType.S)
171+
.build()
172+
)
173+
.billingMode(BillingMode.PAY_PER_REQUEST)
174+
.build());
175+
} catch (ResourceInUseException ignored) {
176+
// Table already exists, ignore
177+
}
178+
}
179+
180+
@AfterEach
181+
void tearDown() {
182+
// DynamoDB local doesn't need explicit cleanup between tests
183+
// Tables are automatically cleaned by Testcontainers on restart
184+
client.close();
93185
}
94186

95187
@Test
96-
@Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done")
97188
void testImportDynamoDBChangeLogs() {
98-
List<MongockDynamoDBAuditEntry> entries = Arrays.asList(
99-
new MongockDynamoDBAuditEntry(
100-
"exec-1",
101-
"client-initializer",
102-
"author1",
103-
String.valueOf(Instant.now().toEpochMilli()),
104-
"EXECUTED",
105-
"EXECUTION",
106-
"io.flamingock.changelog.Class1",
107-
"method1",
108-
new HashMap<String, String>() {{
109-
put("meta1", "value1");
110-
}}.toString(),
111-
123L,
112-
"host1",
113-
null,
114-
true
115-
),
116-
new MongockDynamoDBAuditEntry(
117-
"exec-1",
118-
"client-updater",
119-
"author1",
120-
String.valueOf(Instant.now().toEpochMilli()),
121-
"EXECUTED",
122-
"EXECUTION",
123-
"io.flamingock.changelog.Class2",
124-
"method1",
125-
new HashMap<String, String>() {{
126-
put("meta1", "value1");
127-
}}.toString(),
128-
123L,
129-
"host1",
130-
null,
131-
true
132-
)
133-
);
189+
// Setup Mongock entries
190+
mongockTestHelper.setupBasicScenario();
134191

135-
mongockChangeLogsHelper.insertChangeEntries(entries);
192+
DynamoDBTargetSystem dynamodbTargetSystem = new DynamoDBTargetSystem("dynamodb-target-system", client);
136193

137-
Runner flamingock = FlamingockFactory.getCommunityBuilder()
138-
.setAuditStore(new DynamoDBAuditStore(client))
194+
Runner flamingock = testKit.createBuilder()
195+
.addTargetSystem(dynamodbTargetSystem)
139196
.build();
140197

141198
flamingock.run();
142199

143-
List<AuditEntry> auditLog = new DynamoDBTestHelper(client, DEFAULT_AUDIT_STORE_NAME).getAuditEntriesSorted();
144-
assertEquals(6, auditLog.size());
145-
146-
for (AuditEntry entry : auditLog) {
147-
System.out.println("executionId: " + entry.getExecutionId());
148-
System.out.println("stageId: " + entry.getStageId());
149-
System.out.println("taskId: " + entry.getTaskId());
150-
System.out.println("author: " + entry.getAuthor());
151-
System.out.println("createdAt: " + entry.getCreatedAt());
152-
System.out.println("state: " + entry.getState());
153-
System.out.println("type: " + entry.getType());
154-
System.out.println("className: " + entry.getClassName());
155-
System.out.println("methodName: " + entry.getMethodName());
156-
System.out.println("executionMillis: " + entry.getExecutionMillis());
157-
System.out.println("executionHostname: " + entry.getExecutionHostname());
158-
System.out.println("metadata: " + entry.getMetadata());
159-
System.out.println("systemChange: " + entry.getSystemChange());
160-
System.out.println("errorTrace: " + entry.getErrorTrace());
161-
System.out.println("txStrategy: " + entry.getTxType());
162-
System.out.println("targetSystemId: " + entry.getTargetSystemId());
163-
System.out.println("order: " + entry.getOrder());
164-
System.out.println("-----");
165-
}
166-
167-
AuditEntry entry1 = auditLog.stream()
168-
.filter(e -> "client-updater".equals(e.getTaskId()))
169-
.findFirst()
170-
.orElseThrow(() -> new AssertionError("Entry with changeId 'client-updater' not found"));
171-
200+
// Verify audit sequence: 9 total entries
201+
// Legacy imports only show APPLIED (imported from Mongock), new changes show STARTED+APPLIED
202+
auditHelper.verifyAuditSequenceStrict(
203+
// Legacy imports from Mongock (APPLIED only - no STARTED for imported changes)
204+
APPLIED("system-change-00001_before"),
205+
APPLIED("system-change-00001"),
206+
APPLIED("client-initializer_before"),
207+
APPLIED("client-initializer"),
208+
APPLIED("client-updater"),
209+
210+
// System stage - actual system importer change
211+
STARTED("migration-mongock-to-flamingock-community"),
212+
APPLIED("migration-mongock-to-flamingock-community"),
213+
214+
// Application stage - new change created by code
215+
STARTED("create-users-table"),
216+
APPLIED("create-users-table")
217+
);
172218

173-
assertEquals("client-updater", entry1.getTaskId());
174-
assertEquals("author1", entry1.getAuthor());
175-
assertEquals("exec-1", entry1.getExecutionId());
176-
assertTrue(entry1.getSystemChange());
219+
// Validate actual table creation
220+
assertTrue(client.listTables().tableNames().contains("users"), "Users table should exist");
177221

178-
ScanResponse scanResponse = client.scan(
179-
ScanRequest.builder().tableName(DEFAULT_AUDIT_STORE_NAME).build()
222+
// Verify table structure
223+
DescribeTableResponse tableDescription = client.describeTable(
224+
DescribeTableRequest.builder().tableName("users").build()
180225
);
181-
assertTrue(scanResponse.count() > 0, "Audit table should not be empty");
226+
assertEquals("email", tableDescription.table().keySchema().get(0).attributeName());
227+
assertEquals(KeyType.HASH, tableDescription.table().keySchema().get(0).keyType());
182228
}
183229

184230
@Test
185231
@Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done")
186232
void failIfEmptyOrigin() {
187-
Runner flamingock = FlamingockFactory.getCommunityBuilder()
188-
.setAuditStore(new DynamoDBAuditStore(client))
233+
Runner flamingock = testKit.createBuilder()
189234
.build();
190235

191236
Assertions.assertThrows(FlamingockException.class, flamingock::run);

0 commit comments

Comments
 (0)