Skip to content

Commit 175e422

Browse files
authored
Merge branch 'develop' into fix/graalvm-add-missing-class
2 parents 9840a8b + 23aa255 commit 175e422

File tree

22 files changed

+424
-106
lines changed

22 files changed

+424
-106
lines changed

cli/flamingock-cli/src/main/java/io/flamingock/cli/config/DatabaseConfig.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.flamingock.internal.common.sql.SqlDialect;
1919

2020
import java.util.Map;
21+
import java.util.Optional;
2122

2223
public class DatabaseConfig {
2324
private MongoDBConfig mongodb;
@@ -269,16 +270,27 @@ public void setPassword(String password) {
269270
this.password = password;
270271
}
271272

272-
public SqlDialect getSqlDialect() {
273-
return sqlDialect;
273+
public Optional<SqlDialect> getSqlDialect() {
274+
return Optional.ofNullable(sqlDialect);
274275
}
275276

276277
public void setSqlDialect(String sqlDialect) {
277278
this.sqlDialect = SqlDialect.valueOf(sqlDialect.toUpperCase());
278279
}
279280

281+
public SqlDialect getEffectiveSqlDialect() {
282+
if (this.sqlDialect != null) {
283+
return this.sqlDialect;
284+
}
285+
String[] parts = this.endpoint.split(":", 3);
286+
if (parts.length < 2 || parts[1].isEmpty()) {
287+
throw new IllegalStateException("Cannot determine SQL dialect from endpoint: " + this.endpoint);
288+
}
289+
return SqlDialect.fromString(parts[1].toLowerCase());
290+
}
291+
280292
public String getDriverClassName() {
281-
switch (sqlDialect) {
293+
switch (this.getEffectiveSqlDialect()) {
282294
case MYSQL:
283295
return "com.mysql.cj.jdbc.Driver";
284296
case MARIADB:
@@ -302,7 +314,7 @@ public String getDriverClassName() {
302314
case DB2:
303315
return "com.ibm.db2.jcc.DB2Driver";
304316
default:
305-
throw new IllegalArgumentException("Unsupported SQL Dialect: " + sqlDialect);
317+
throw new IllegalArgumentException("Unsupported SQL Dialect: " + this.getEffectiveSqlDialect());
306318
}
307319
}
308320

cli/flamingock-cli/src/main/java/io/flamingock/cli/factory/SqlDataSourceFactory.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,7 @@ public static DataSource createSqlDataSource(DatabaseConfig.SqlConfig config) {
3838
throw new IllegalArgumentException("Database endpoint is required");
3939
}
4040

41-
if (config.getSqlDialect() == null) {
42-
throw new IllegalArgumentException("Sql dialect is required");
43-
}
44-
45-
if (!SqlDialect.SQLITE.equals(config.getSqlDialect())) {
41+
if (config.getEffectiveSqlDialect() != SqlDialect.SQLITE) {
4642
if (config.getUsername() == null) {
4743
throw new IllegalArgumentException("Database username is required");
4844
}
@@ -54,16 +50,10 @@ public static DataSource createSqlDataSource(DatabaseConfig.SqlConfig config) {
5450
try {
5551
DataSource sqlDatasource;
5652

57-
if (config.getSqlDialect().equals(SqlDialect.SQLITE)) {
53+
if (config.getEffectiveSqlDialect() == (SqlDialect.SQLITE)) {
5854
SQLiteDataSource sqliteDatasource = new SQLiteDataSource();
5955
sqliteDatasource.setUrl(config.getEndpoint());
6056

61-
try (Connection conn = sqliteDatasource.getConnection();
62-
Statement stmt = conn.createStatement()) {
63-
stmt.execute("PRAGMA journal_mode=WAL;");
64-
stmt.execute("PRAGMA busy_timeout=5000;");
65-
}
66-
6757
sqlDatasource = sqliteDatasource;
6858
} else {
6959
HikariConfig datasourceConfig = new HikariConfig();

cli/flamingock-cli/src/test/java/io/flamingock/cli/SimpleCLITest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,6 @@ void shouldCreateTestConfigs() {
9393

9494
assertThat(sqlConfig).isNotNull();
9595
assertThat(sqlConfig.getAudit().getSql()).isNotNull();
96-
assertThat(sqlConfig.getAudit().getSql().getSqlDialect()).isEqualTo(SQLSERVER);
96+
assertThat(sqlConfig.getAudit().getSql().getEffectiveSqlDialect()).isEqualTo(SQLSERVER);
9797
}
9898
}

cli/flamingock-cli/src/test/java/io/flamingock/cli/config/SimpleConfigLoaderTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.io.IOException;
2323
import java.nio.file.Files;
2424
import java.nio.file.Path;
25+
import java.util.Optional;
2526

2627
import static io.flamingock.internal.common.sql.SqlDialect.SQLSERVER;
2728
import static org.assertj.core.api.Assertions.*;
@@ -100,7 +101,7 @@ void shouldLoadValidSqlConfiguration() throws IOException {
100101
assertThat(config.getAudit().getSql().getEndpoint()).isEqualTo("jdbc:sqlserver://localhost:1433");
101102
assertThat(config.getAudit().getSql().getUsername()).isEqualTo("test-user");
102103
assertThat(config.getAudit().getSql().getPassword()).isEqualTo("test-password");
103-
assertThat(config.getAudit().getSql().getSqlDialect()).isEqualTo(SQLSERVER);
104+
assertThat(config.getAudit().getSql().getSqlDialect()).isEqualTo(Optional.of(SQLSERVER));
104105
}
105106

106107
@Test

cli/flamingock-cli/src/test/java/io/flamingock/cli/integration/CLISqlIntegrationTest.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ void shouldRunAuditListCommandWithSql(SqlDialect sqlDialect, String dialectName)
100100
" sql:\n" +
101101
" endpoint: \"" + sqlContainer.getJdbcUrl() + "\"\n" +
102102
" username: \"" + sqlContainer.getUsername() + "\"\n" +
103-
" password: \"" + sqlContainer.getPassword() + "\"\n" +
104-
" sql-dialect: \"" + dialectName + "\"\n";
103+
" password: \"" + sqlContainer.getPassword() + "\"\n";
105104

106105
Files.write(configFile, sqlConfig.getBytes());
107106

@@ -182,8 +181,7 @@ void shouldHandleInvalidSqlConnectionGracefully(SqlDialect sqlDialect, String di
182181
" sql:\n" +
183182
" endpoint: \"jdbc:sqlserver://invalid-host:1433\"\n" +
184183
" username: \"" + sqlContainer.getUsername() + "\"\n" +
185-
" password: \"" + sqlContainer.getPassword() + "\"\n" +
186-
" sql-dialect: \"" + dialectName + "\"\n";
184+
" password: \"" + sqlContainer.getPassword() + "\"\n";
187185

188186
Files.write(configFile, invalidConfig.getBytes());
189187

cli/flamingock-cli/src/test/java/io/flamingock/cli/test/TestUtils.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ public static FlamingockConfig createSqlConfig() {
8080
sqlConfig.setEndpoint("jdbc:sqlserver://localhost:1433");
8181
sqlConfig.setUsername("test-user");
8282
sqlConfig.setPassword("test-password");
83-
sqlConfig.setSqlDialect("SqlServer");
8483
databaseConfig.setSql(sqlConfig);
8584

8685
config.setAudit(databaseConfig);

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

0 commit comments

Comments
 (0)