Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,22 @@
import io.flamingock.internal.common.core.audit.AuditEntry;
import io.flamingock.internal.common.core.audit.AuditHistoryReader;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class MongockImporterMongoDB implements AuditHistoryReader {

private static final Logger logger = LoggerFactory.getLogger("MongockImporter");

private final MongoCollection<Document> sourceCollection;

public MongockImporterMongoDB(MongoDatabase mongoDatabase, String collectionName) {
Expand All @@ -44,6 +49,7 @@ public List<AuditEntry> getAuditHistory() {
.into(new ArrayList<>())
.stream()
.map(MongockImporterMongoDB::toAuditEntry)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

Expand All @@ -55,6 +61,8 @@ private static AuditEntry toAuditEntry(Document document) {
.toLocalDateTime();

if (changeEntry.shouldBeIgnored()) {
logger.info("Skipping Mongock audit entry with changeId[{}]: state=IGNORED (Mongock never executed this change; nothing to import).",
Comment thread
davidfrigolet marked this conversation as resolved.
Outdated
changeEntry.getChangeId());
return null;
}
return new AuditEntry(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,65 @@ void GIVEN_unknownAuditEntriesAndRelaxedMode_WHEN_migratingToFlamingockCommunity
);
}

@Test
@DisplayName("GIVEN Mongock audit history contains an IGNORED entry " +
"WHEN migrating to Flamingock Community " +
"THEN should skip the IGNORED entry without crashing " +
"AND import the rest of the history normally")
void GIVEN_ignoredAuditEntry_WHEN_migratingToFlamingockCommunity_THEN_shouldSkipIgnoredAndImportRest() throws java.text.ParseException {
// Regression test for IGNORED-state null leak in MongockImporterMongoDB.toAuditEntry().
// Before the fix, the importer returned null for IGNORED entries and the caller
// (MongockImportChange.importHistory) crashed with:
// NullPointerException: Cannot invoke "AuditEntry.getSystemChange()"
// because "auditEntryFromOrigin" is null
// The fix filters nulls at both layers and logs the skipped entry.

mongockTestHelper.setupBasicScenario();
mongockTestHelper.write(new MongockChangeEntry(
"ignored-execution-1",
"ignored-change",
"mongock",
MongockTestHelper.DEFAULT_DATE_FORMAT.parse("2025-06-19T05:43:57.200Z"),
MongockChangeState.IGNORED,
io.flamingock.common.test.mongock.MongockChangeType.EXECUTION,
"io.example.IgnoredChangeUnit",
"apply",
null,
0L,
MongockTestHelper.DEFAULT_HOSTNAME,
null,
false,
null
));

MongoDBSyncTargetSystem mongodbTargetSystem = new MongoDBSyncTargetSystem("mongodb-target-system", mongoClient, DATABASE_NAME);

Runner flamingock = testKit.createBuilder()
.addTargetSystem(mongodbTargetSystem)
.build();

flamingock.run();

// IGNORED entry must NOT appear in the Flamingock audit store.
assertNull(getAuditEntryByChangeId("ignored-change"),
"IGNORED Mongock entry must not be imported into the Flamingock audit store");

// Remaining basic-scenario entries imported as normal, plus native changes executed.
auditHelper.verifyAuditSequenceStrict(
APPLIED("system-change-00001_before"),
APPLIED("system-change-00001"),
APPLIED("mongock-change-1_before"),
APPLIED("mongock-change-1"),
APPLIED("mongock-change-2"),
STARTED("migration-mongock-to-flamingock-community"),
APPLIED("migration-mongock-to-flamingock-community"),
STARTED("create-users-collection-with-index"),
APPLIED("create-users-collection-with-index"),
STARTED("seed-users"),
APPLIED("seed-users")
);
}

@Test
@DisplayName("GIVEN relaxed import flag with invalid value " +
"WHEN migrating to Flamingock Community " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@

import javax.inject.Named;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static io.flamingock.internal.common.core.audit.AuditReaderType.MONGOCK;
import static io.flamingock.internal.common.core.metadata.Constants.MONGOCK_IMPORT_EMPTY_ORIGIN_ALLOWED_PROPERTY_KEY;
Expand Down Expand Up @@ -61,7 +63,10 @@ public void importHistory(@Named("change.targetSystem.id") String targetSystemId
logger.info("Starting audit log migration from Mongock to Flamingock community audit store");
AuditHistoryReader legacyHistoryReader = getAuditHistoryReader(targetSystemId, targetSystemManager);
PipelineHelper pipelineHelper = new PipelineHelper(pipelineDescriptor);
List<AuditEntry> legacyHistory = legacyHistoryReader.getAuditHistory();
List<AuditEntry> legacyHistory = legacyHistoryReader.getAuditHistory()
Comment thread
davidfrigolet marked this conversation as resolved.
Outdated
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
boolean ignoreUnknownEntries = resolveIgnoreUnknownEntries(ignoreUnknownEntriesPropertyValue);
validate(legacyHistory, targetSystemId, emptyOriginAllowedPropertyValue);
legacyHistory.forEach(auditEntryFromOrigin -> {
Expand Down
Loading