Skip to content

Commit 3e8491e

Browse files
authored
test: validates non-executed Mongock changeUnits are executed in flamingock(#744)
1 parent e56935d commit 3e8491e

File tree

15 files changed

+387
-82
lines changed

15 files changed

+387
-82
lines changed

core/flamingock-core/src/main/java/io/flamingock/internal/core/task/loaded/AbstractLoadedChange.java

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,19 @@
1515
*/
1616
package io.flamingock.internal.core.task.loaded;
1717

18-
import io.flamingock.api.annotations.Categories;
19-
import io.flamingock.api.task.ChangeCategory;
2018
import io.flamingock.internal.common.core.error.validation.ValidationError;
21-
import io.flamingock.internal.core.pipeline.loaded.stage.StageValidationContext;
22-
import io.flamingock.internal.util.ReflectionUtil;
2319
import io.flamingock.internal.common.core.task.RecoveryDescriptor;
2420
import io.flamingock.internal.common.core.task.TargetSystemDescriptor;
25-
import org.jetbrains.annotations.NotNull;
21+
import io.flamingock.internal.core.pipeline.loaded.stage.StageValidationContext;
2622
import io.flamingock.internal.util.log.FlamingockLoggerFactory;
23+
import org.jetbrains.annotations.NotNull;
2724
import org.slf4j.Logger;
2825

2926
import java.lang.reflect.Constructor;
3027
import java.util.ArrayList;
31-
import java.util.Arrays;
3228
import java.util.List;
3329
import java.util.Optional;
34-
import java.util.Set;
3530
import java.util.regex.Pattern;
36-
import java.util.stream.Collectors;
3731

3832
public abstract class AbstractLoadedChange extends AbstractReflectionLoadedTask {
3933

@@ -97,19 +91,19 @@ public List<ValidationError> getValidationErrors(StageValidationContext context)
9791
@NotNull
9892
private Optional<ValidationError> getOrderError(StageValidationContext context) {
9993
String order = getOrder().orElse(null);
100-
if(context.getSortType().isSorted()) {
94+
if (context.getSortType().isSorted()) {
10195
if (order == null || order.isEmpty()) {
10296
return Optional.of(new ValidationError("Change in a sorted stage but no order value was provided", id, "change"));
10397
}
10498

105-
if(context.getSortType() == StageValidationContext.SortType.SEQUENTIAL_FORMATTED) {
99+
if (context.getSortType() == StageValidationContext.SortType.SEQUENTIAL_FORMATTED) {
106100
if (!ORDER_PATTERN.matcher(order).matches()) {
107101
String message = String.format("Invalid order field format in change[%s]. Order must match pattern: %s", id, ORDER_REG_EXP);
108102
return Optional.of(new ValidationError(message, id, "task"));
109103
}
110104
}
111105

112-
} else if(order != null) {
106+
} else if (order != null) {
113107
logger.warn("Change[{}] is in an auto-sorted stage but order value was provided - order will be ignored and managed automatically by Flamingock", id);
114108

115109
}

legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/CouchbaseImporterTest.java

Lines changed: 101 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.flamingock.api.annotations.EnableFlamingock;
2525
import io.flamingock.api.annotations.Stage;
2626
import io.flamingock.community.couchbase.driver.CouchbaseAuditStore;
27+
import io.flamingock.internal.common.core.error.FlamingockException;
2728
import io.flamingock.internal.common.couchbase.CouchbaseCollectionHelper;
2829
import io.flamingock.internal.core.builder.FlamingockFactory;
2930
import io.flamingock.internal.core.runner.Runner;
@@ -33,6 +34,7 @@
3334
import org.junit.jupiter.api.AfterEach;
3435
import org.junit.jupiter.api.BeforeAll;
3536
import org.junit.jupiter.api.Disabled;
37+
import org.junit.jupiter.api.DisplayName;
3638
import org.junit.jupiter.api.Test;
3739
import org.testcontainers.couchbase.CouchbaseContainer;
3840
import org.testcontainers.junit.jupiter.Container;
@@ -41,10 +43,14 @@
4143
import java.time.Duration;
4244
import java.time.Instant;
4345
import java.util.List;
46+
import java.util.Map;
47+
import java.util.stream.Collectors;
4448

4549
import static io.flamingock.internal.common.core.metadata.Constants.DEFAULT_MONGOCK_ORIGIN;
4650
import static org.junit.jupiter.api.Assertions.assertEquals;
4751
import static org.junit.jupiter.api.Assertions.assertFalse;
52+
import static org.junit.jupiter.api.Assertions.assertNotNull;
53+
import static org.junit.jupiter.api.Assertions.assertThrows;
4854
import static org.junit.jupiter.api.Assertions.assertTrue;
4955

5056
@Testcontainers
@@ -99,24 +105,15 @@ void cleanUp() {
99105
}
100106

101107
@Test
102-
void testImporterIntegration() {
108+
@DisplayName("GIVEN all Mongock changeUnits already executed" +
109+
"WHEN migrating to Flamingock Community " +
110+
"THEN should import the entire history " +
111+
"AND execute the pending flamingock changes")
112+
void GIVEN_allMongockChangeUnitsAlreadyExecuted_WHEN_migratingToFlamingockCommunity_THEN_shouldImportEntireHistory() {
103113
Collection originCollection = cluster.bucket(MONGOCK_BUCKET_NAME).scope(MONGOCK_SCOPE_NAME).collection(MONGOCK_COLLECTION_NAME);
104-
JsonObject doc = JsonObject.create()
105-
.put("executionId", "exec-1")
106-
.put("changeId", "change-1")
107-
.put("author", "author1")
108-
.put("timestamp", String.valueOf(Instant.now().toEpochMilli()))
109-
.put("state", "EXECUTED")
110-
.put("type", "EXECUTION")
111-
.put("changeLogClass", "io.flamingock.changelog.Class1")
112-
.put("changeSetMethod", "method1")
113-
.putNull("metadata")
114-
.put("executionMillis", 123L)
115-
.put("executionHostName", "host1")
116-
.putNull("errorTrace")
117-
.put("systemChange", true)
118-
.put("_doctype", "mongockChangeEntry");
119-
originCollection.upsert("change-1", doc);
114+
115+
originCollection.upsert("mongock-change-1", createAuditObject("mongock-change-1"));
116+
originCollection.upsert("mongock-change-2", createAuditObject("mongock-change-2"));
120117

121118
CouchbaseTargetSystem targetSystem = new CouchbaseTargetSystem("couchbase-target-system", cluster, FLAMINGOCK_BUCKET_NAME);
122119

@@ -129,34 +126,104 @@ void testImporterIntegration() {
129126

130127
flamingock.run();
131128

132-
List<JsonObject> auditLog = CouchbaseCollectionHelper.selectAllDocuments(cluster, FLAMINGOCK_BUCKET_NAME, FLAMINGOCK_SCOPE_NAME, FLAMINGOCK_COLLECTION_NAME);
129+
validateFlamingockAuditOutput();
133130

134-
assertFalse(auditLog.isEmpty(), "Audit log should not be empty");
131+
}
135132

136-
JsonObject entry = auditLog.stream()
137-
.filter(e -> "change-1".equals(e.getString("changeId")))
138-
.findFirst()
139-
.orElseThrow(() -> new AssertionError("Entry with changeId 'change-1' not found"));
133+
@Test
134+
@DisplayName("GIVEN some Mongock changeUnits already executed " +
135+
"AND some other Mongock changeUnits pending for execution" +
136+
"WHEN migrating to Flamingock Community" +
137+
"THEN migrates the history with the executed changeUnits " +
138+
"AND executes the pending Mongock changeUnits " +
139+
"AND executes the pending Flamingock changes")
140+
void GIVEN_someChangeUnitsAlreadyExecuted_WHEN_migratingToFlamingockCommunity_THEN_shouldImportEntireHistory() {
141+
Collection originCollection = cluster.bucket(MONGOCK_BUCKET_NAME).scope(MONGOCK_SCOPE_NAME).collection(MONGOCK_COLLECTION_NAME);
142+
143+
originCollection.upsert("mongock-change-1", createAuditObject("mongock-change-1"));
144+
145+
CouchbaseTargetSystem targetSystem = new CouchbaseTargetSystem("couchbase-target-system", cluster, FLAMINGOCK_BUCKET_NAME);
146+
147+
Runner flamingock = FlamingockFactory.getCommunityBuilder()
148+
.setAuditStore(new CouchbaseAuditStore(cluster, FLAMINGOCK_BUCKET_NAME)
149+
.withScopeName(FLAMINGOCK_SCOPE_NAME)
150+
.withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME))
151+
.addTargetSystem(targetSystem)
152+
.build();
140153

141-
assertEquals("change-1", entry.getString("changeId"));
142-
assertEquals("author1", entry.getString("author"));
143-
assertEquals("exec-1", entry.getString("executionId"));
144-
assertEquals("APPLIED", entry.getString("state"));
145-
assertTrue(entry.getBoolean("systemChange"));
154+
flamingock.run();
155+
156+
validateFlamingockAuditOutput();
146157
}
147158

148159
@Test
149-
@Disabled("restore when https://trello.com/c/4gEQ8Wb4/458-mongock-legacy-targetsystem done")
150-
void failIfEmptyOrigin() {
160+
@DisplayName("GIVEN mongock audit history empty " +
161+
"WHEN migrating to Flamingock Community" +
162+
"THEN should throw exception")
163+
void GIVEN_mongockAuditHistoryEmpty_WHEN_migratingToFlamingockCommunity_THEN_shouldThrowException() {
164+
// Setup Mongock entries
165+
166+
CouchbaseTargetSystem targetSystem = new CouchbaseTargetSystem("couchbase-target-system", cluster, FLAMINGOCK_BUCKET_NAME);
167+
151168
Runner flamingock = FlamingockFactory.getCommunityBuilder()
152169
.setAuditStore(new CouchbaseAuditStore(cluster, FLAMINGOCK_BUCKET_NAME)
153170
.withScopeName(FLAMINGOCK_SCOPE_NAME)
154171
.withAuditRepositoryName(FLAMINGOCK_COLLECTION_NAME))
172+
.addTargetSystem(targetSystem)
155173
.build();
156174

157-
org.junit.jupiter.api.Assertions.assertThrows(
158-
io.flamingock.internal.common.core.error.FlamingockException.class,
159-
flamingock::run
160-
);
175+
FlamingockException ex = assertThrows(FlamingockException.class, flamingock::run);
176+
assertEquals("No audit entries found when importing from 'couchbase-target-system'.", ex.getMessage());
177+
178+
}
179+
180+
181+
private static void validateFlamingockAuditOutput() {
182+
List<JsonObject> auditLog = CouchbaseCollectionHelper.selectAllDocuments(cluster, FLAMINGOCK_BUCKET_NAME, FLAMINGOCK_SCOPE_NAME, FLAMINGOCK_COLLECTION_NAME);
183+
184+
185+
Map<String, JsonObject> byChangeId = auditLog.stream()
186+
.collect(Collectors.toMap(
187+
e -> e.getString("changeId"),
188+
e -> e
189+
));
190+
191+
192+
assertEquals(4, auditLog.size());
193+
JsonObject importAudit = byChangeId.get("migration-mongock-to-flamingock-community");
194+
JsonObject mongockAudit1 = byChangeId.get("mongock-change-1");
195+
JsonObject mongockAudit2 = byChangeId.get("mongock-change-2");
196+
JsonObject flamingockAudit = byChangeId.get("flamingock-change");
197+
assertNotNull(importAudit);
198+
assertEquals("APPLIED", importAudit.getString("state"));
199+
200+
assertNotNull(mongockAudit1);
201+
assertEquals("APPLIED", mongockAudit1.getString("state"));
202+
203+
assertNotNull(mongockAudit2);
204+
assertEquals("APPLIED", mongockAudit2.getString("state"));
205+
206+
assertNotNull(flamingockAudit);
207+
assertEquals("APPLIED", flamingockAudit.getString("state"));
208+
}
209+
210+
private static JsonObject createAuditObject(String value) {
211+
JsonObject doc = JsonObject.create()
212+
.put("executionId", "exec-1")
213+
.put("changeId", value)
214+
.put("author", "author1")
215+
.put("timestamp", String.valueOf(Instant.now().toEpochMilli()))
216+
.put("state", "EXECUTED")
217+
.put("type", "EXECUTION")
218+
.put("changeLogClass", "io.flamingock.changelog.Class1")
219+
.put("changeSetMethod", "method1")
220+
.putNull("metadata")
221+
.put("executionMillis", 123L)
222+
.put("executionHostName", "host1")
223+
.putNull("errorTrace")
224+
.put("systemChange", true)
225+
.put("_doctype", "mongockChangeEntry");
226+
return doc;
161227
}
228+
162229
}

legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange1.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import io.mongock.api.annotations.ChangeUnit;
1919
import io.mongock.api.annotations.Execution;
2020

21-
@ChangeUnit(id = "client-initializer", order = "1", author = "flamingock-team", transactional = false)
21+
@ChangeUnit(id = "mongock-change-1", order = "1", author = "flamingock-team", transactional = false)
2222
public class MongockChange1 {
2323

2424
@Execution

legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/MongockChange2.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import io.mongock.api.annotations.ChangeUnit;
1919
import io.mongock.api.annotations.Execution;
2020

21-
@ChangeUnit(id = "client-updater", order = "2", author = "flamingock-team", transactional = false)
21+
@ChangeUnit(id = "mongock-change-2", order = "2", author = "flamingock-team", transactional = false)
2222
public class MongockChange2 {
2323

2424
@Execution

legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0001__CreateUsersCollectionChange.java renamed to legacy/mongock-importer-couchbase/src/test/java/io/flamingock/importer/mongock/couchbase/changes/_0003__Flamingock_change.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
import java.util.Collections;
2626

2727
@TargetSystem(id = "couchbase-target-system")
28-
@Change(id = "create-users-collection", author = "importer", transactional = false)
29-
public class _0001__CreateUsersCollectionChange {
28+
@Change(id = "flamingock-change", author = "importer", transactional = false)
29+
public class _0003__Flamingock_change {
3030

3131
@Apply
3232
public void apply(Bucket bucket) {

0 commit comments

Comments
 (0)