From dbbb85ac4e160eb40c85f2984c80d49c4c036d52 Mon Sep 17 00:00:00 2001 From: davidfrigolet Date: Wed, 31 Dec 2025 16:18:02 +0000 Subject: [PATCH] feat: mongodb sync template new operations and unit tests --- .../mapper/CreateViewOptionsMapper.java | 37 ++++ .../mapper/RenameCollectionOptionsMapper.java | 37 ++++ .../mongodb/model/MongoOperation.java | 34 ++++ .../mongodb/model/MongoOperationType.java | 14 +- .../model/operator/CreateViewOperator.java | 35 ++++ .../operator/DropCollectionOperator.java | 32 ++++ .../model/operator/DropIndexOperator.java | 37 ++++ .../model/operator/DropViewOperator.java | 32 ++++ .../operator/ModifyCollectionOperator.java | 43 +++++ .../operator/RenameCollectionOperator.java | 37 ++++ .../CreateCollectionOperatorTest.java | 87 +++++++++ .../operations/CreateIndexOperatorTest.java | 143 ++++++++++++++ .../operations/CreateViewOperatorTest.java | 110 +++++++++++ .../DropCollectionOperatorTest.java | 88 +++++++++ .../operations/DropIndexOperatorTest.java | 129 +++++++++++++ .../operations/DropViewOperatorTest.java | 93 ++++++++++ .../operations/InsertOperatorTest.java | 174 ++++++++++++++++++ .../ModifyCollectionOperatorTest.java | 96 ++++++++++ .../RenameCollectionOperatorTest.java | 94 ++++++++++ 19 files changed, 1351 insertions(+), 1 deletion(-) create mode 100644 templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/mapper/CreateViewOptionsMapper.java create mode 100644 templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/mapper/RenameCollectionOptionsMapper.java create mode 100644 templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/CreateViewOperator.java create mode 100644 templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropCollectionOperator.java create mode 100644 templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropIndexOperator.java create mode 100644 templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropViewOperator.java create mode 100644 templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/ModifyCollectionOperator.java create mode 100644 templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/RenameCollectionOperator.java create mode 100644 templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateCollectionOperatorTest.java create mode 100644 templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateIndexOperatorTest.java create mode 100644 templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateViewOperatorTest.java create mode 100644 templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropCollectionOperatorTest.java create mode 100644 templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropIndexOperatorTest.java create mode 100644 templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropViewOperatorTest.java create mode 100644 templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/InsertOperatorTest.java create mode 100644 templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/ModifyCollectionOperatorTest.java create mode 100644 templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/RenameCollectionOperatorTest.java diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/mapper/CreateViewOptionsMapper.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/mapper/CreateViewOptionsMapper.java new file mode 100644 index 000000000..a528bbe3b --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/mapper/CreateViewOptionsMapper.java @@ -0,0 +1,37 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.mapper; + +import com.mongodb.client.model.CreateViewOptions; + +import java.util.Map; + +import static io.flamingock.template.mongodb.mapper.MapperUtil.getCollation; + +public final class CreateViewOptionsMapper { + + private CreateViewOptionsMapper() {} + + public static CreateViewOptions map(Map options) { + CreateViewOptions result = new CreateViewOptions(); + + if (options.containsKey("collation")) { + result.collation(getCollation(options, "collation")); + } + + return result; + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/mapper/RenameCollectionOptionsMapper.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/mapper/RenameCollectionOptionsMapper.java new file mode 100644 index 000000000..ade56d87b --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/mapper/RenameCollectionOptionsMapper.java @@ -0,0 +1,37 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.mapper; + +import com.mongodb.client.model.RenameCollectionOptions; + +import java.util.Map; + +import static io.flamingock.template.mongodb.mapper.MapperUtil.getBoolean; + +public final class RenameCollectionOptionsMapper { + + private RenameCollectionOptionsMapper() {} + + public static RenameCollectionOptions map(Map options) { + RenameCollectionOptions result = new RenameCollectionOptions(); + + if (options.containsKey("dropTarget")) { + result.dropTarget(getBoolean(options, "dropTarget")); + } + + return result; + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/MongoOperation.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/MongoOperation.java index 4d931e157..115d09c55 100644 --- a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/MongoOperation.java +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/MongoOperation.java @@ -69,6 +69,40 @@ public Document getFilter() { return new Document((Map) parameters.get("filter")); } + public String getIndexName() { + Object value = parameters.get("indexName"); + return value != null ? (String) value : null; + } + + public String getTarget() { + return (String) parameters.get("target"); + } + + @SuppressWarnings("unchecked") + public Document getValidator() { + Object value = parameters.get("validator"); + return value != null ? new Document((Map) value) : null; + } + + public String getValidationLevel() { + return (String) parameters.get("validationLevel"); + } + + public String getValidationAction() { + return (String) parameters.get("validationAction"); + } + + public String getViewOn() { + return (String) parameters.get("viewOn"); + } + + @SuppressWarnings("unchecked") + public List getPipeline() { + List> rawPipeline = (List>) parameters.get("pipeline"); + return rawPipeline != null + ? rawPipeline.stream().map(Document::new).collect(Collectors.toList()) + : null; + } public MongoOperator getOperator(MongoDatabase db) { return MongoOperationType.getFromValue(getType()).getOperator(db, this); diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/MongoOperationType.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/MongoOperationType.java index f54c893e2..4cafa1b3c 100644 --- a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/MongoOperationType.java +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/MongoOperationType.java @@ -18,8 +18,14 @@ import com.mongodb.client.MongoDatabase; import io.flamingock.template.mongodb.model.operator.CreateCollectionOperator; import io.flamingock.template.mongodb.model.operator.CreateIndexOperator; +import io.flamingock.template.mongodb.model.operator.CreateViewOperator; +import io.flamingock.template.mongodb.model.operator.DropCollectionOperator; +import io.flamingock.template.mongodb.model.operator.DropIndexOperator; +import io.flamingock.template.mongodb.model.operator.DropViewOperator; import io.flamingock.template.mongodb.model.operator.InsertOperator; +import io.flamingock.template.mongodb.model.operator.ModifyCollectionOperator; import io.flamingock.template.mongodb.model.operator.MongoOperator; +import io.flamingock.template.mongodb.model.operator.RenameCollectionOperator; import java.util.Arrays; import java.util.function.BiFunction; @@ -28,7 +34,13 @@ public enum MongoOperationType { CREATE_COLLECTION("createCollection", CreateCollectionOperator::new), CREATE_INDEX("createIndex", CreateIndexOperator::new), - INSERT("insert", InsertOperator::new); + INSERT("insert", InsertOperator::new), + DROP_COLLECTION("dropCollection", DropCollectionOperator::new), + DROP_INDEX("dropIndex", DropIndexOperator::new), + RENAME_COLLECTION("renameCollection", RenameCollectionOperator::new), + MODIFY_COLLECTION("modifyCollection", ModifyCollectionOperator::new), + CREATE_VIEW("createView", CreateViewOperator::new), + DROP_VIEW("dropView", DropViewOperator::new); private final String value; private final BiFunction createOperatorFunction; diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/CreateViewOperator.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/CreateViewOperator.java new file mode 100644 index 000000000..09633971d --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/CreateViewOperator.java @@ -0,0 +1,35 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.model.operator; + +import com.mongodb.client.ClientSession; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.CreateViewOptions; +import io.flamingock.template.mongodb.mapper.CreateViewOptionsMapper; +import io.flamingock.template.mongodb.model.MongoOperation; + +public class CreateViewOperator extends MongoOperator { + + public CreateViewOperator(MongoDatabase mongoDatabase, MongoOperation operation) { + super(mongoDatabase, operation, false); + } + + @Override + protected void applyInternal(ClientSession clientSession) { + CreateViewOptions options = CreateViewOptionsMapper.map(op.getOptions()); + mongoDatabase.createView(op.getCollection(), op.getViewOn(), op.getPipeline(), options); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropCollectionOperator.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropCollectionOperator.java new file mode 100644 index 000000000..e27f59363 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropCollectionOperator.java @@ -0,0 +1,32 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.model.operator; + +import com.mongodb.client.ClientSession; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; + +public class DropCollectionOperator extends MongoOperator { + + public DropCollectionOperator(MongoDatabase mongoDatabase, MongoOperation operation) { + super(mongoDatabase, operation, false); + } + + @Override + protected void applyInternal(ClientSession clientSession) { + mongoDatabase.getCollection(op.getCollection()).drop(); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropIndexOperator.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropIndexOperator.java new file mode 100644 index 000000000..504de9889 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropIndexOperator.java @@ -0,0 +1,37 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.model.operator; + +import com.mongodb.client.ClientSession; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; + +public class DropIndexOperator extends MongoOperator { + + public DropIndexOperator(MongoDatabase mongoDatabase, MongoOperation operation) { + super(mongoDatabase, operation, false); + } + + @Override + protected void applyInternal(ClientSession clientSession) { + String indexName = op.getIndexName(); + if (indexName != null) { + mongoDatabase.getCollection(op.getCollection()).dropIndex(indexName); + } else { + mongoDatabase.getCollection(op.getCollection()).dropIndex(op.getKeys()); + } + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropViewOperator.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropViewOperator.java new file mode 100644 index 000000000..369bc9b2d --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/DropViewOperator.java @@ -0,0 +1,32 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.model.operator; + +import com.mongodb.client.ClientSession; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; + +public class DropViewOperator extends MongoOperator { + + public DropViewOperator(MongoDatabase mongoDatabase, MongoOperation operation) { + super(mongoDatabase, operation, false); + } + + @Override + protected void applyInternal(ClientSession clientSession) { + mongoDatabase.getCollection(op.getCollection()).drop(); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/ModifyCollectionOperator.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/ModifyCollectionOperator.java new file mode 100644 index 000000000..fb0323ee2 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/ModifyCollectionOperator.java @@ -0,0 +1,43 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.model.operator; + +import com.mongodb.client.ClientSession; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import org.bson.Document; + +public class ModifyCollectionOperator extends MongoOperator { + + public ModifyCollectionOperator(MongoDatabase mongoDatabase, MongoOperation operation) { + super(mongoDatabase, operation, false); + } + + @Override + protected void applyInternal(ClientSession clientSession) { + Document command = new Document("collMod", op.getCollection()); + if (op.getValidator() != null) { + command.append("validator", op.getValidator()); + } + if (op.getValidationLevel() != null) { + command.append("validationLevel", op.getValidationLevel()); + } + if (op.getValidationAction() != null) { + command.append("validationAction", op.getValidationAction()); + } + mongoDatabase.runCommand(command); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/RenameCollectionOperator.java b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/RenameCollectionOperator.java new file mode 100644 index 000000000..af50238a6 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/main/java/io/flamingock/template/mongodb/model/operator/RenameCollectionOperator.java @@ -0,0 +1,37 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.model.operator; + +import com.mongodb.MongoNamespace; +import com.mongodb.client.ClientSession; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.RenameCollectionOptions; +import io.flamingock.template.mongodb.mapper.RenameCollectionOptionsMapper; +import io.flamingock.template.mongodb.model.MongoOperation; + +public class RenameCollectionOperator extends MongoOperator { + + public RenameCollectionOperator(MongoDatabase mongoDatabase, MongoOperation operation) { + super(mongoDatabase, operation, false); + } + + @Override + protected void applyInternal(ClientSession clientSession) { + MongoNamespace target = new MongoNamespace(mongoDatabase.getName(), op.getTarget()); + RenameCollectionOptions options = RenameCollectionOptionsMapper.map(op.getOptions()); + mongoDatabase.getCollection(op.getCollection()).renameCollection(target, options); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateCollectionOperatorTest.java b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateCollectionOperatorTest.java new file mode 100644 index 000000000..4aa050b11 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateCollectionOperatorTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.operations; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import io.flamingock.template.mongodb.model.operator.CreateCollectionOperator; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.util.ArrayList; +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Testcontainers +class CreateCollectionOperatorTest { + + private static final String DB_NAME = "test"; + private static final String COLLECTION_NAME = "newTestCollection"; + + private static MongoClient mongoClient; + private static MongoDatabase mongoDatabase; + + @Container + public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + + @BeforeAll + static void beforeAll() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + mongoDatabase = mongoClient.getDatabase(DB_NAME); + } + + @BeforeEach + void setupEach() { + mongoDatabase.getCollection(COLLECTION_NAME).drop(); + } + + @Test + @DisplayName("WHEN createCollection operator is applied THEN collection is created") + void createCollectionTest() { + assertFalse(collectionExists(COLLECTION_NAME), "Collection should not exist before creation"); + + MongoOperation operation = new MongoOperation(); + operation.setType("createCollection"); + operation.setCollection(COLLECTION_NAME); + operation.setParameters(new HashMap<>()); + + CreateCollectionOperator operator = new CreateCollectionOperator(mongoDatabase, operation); + operator.apply(null); + + assertTrue(collectionExists(COLLECTION_NAME), "Collection should exist after creation"); + } + + private boolean collectionExists(String collectionName) { + return mongoDatabase.listCollectionNames() + .into(new ArrayList<>()) + .contains(collectionName); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateIndexOperatorTest.java b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateIndexOperatorTest.java new file mode 100644 index 000000000..a49ae801e --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateIndexOperatorTest.java @@ -0,0 +1,143 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.operations; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import io.flamingock.template.mongodb.model.operator.CreateIndexOperator; +import org.bson.Document; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Testcontainers +class CreateIndexOperatorTest { + + private static final String DB_NAME = "test"; + private static final String COLLECTION_NAME = "indexTestCollection"; + private static final String INDEX_NAME = "email_unique_index"; + + private static MongoClient mongoClient; + private static MongoDatabase mongoDatabase; + + @Container + public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + + @BeforeAll + static void beforeAll() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + mongoDatabase = mongoClient.getDatabase(DB_NAME); + } + + @BeforeEach + void setupEach() { + mongoDatabase.getCollection(COLLECTION_NAME).drop(); + } + + @Test + @DisplayName("WHEN createIndex operator is applied THEN index is created") + void createIndexTest() { + mongoDatabase.createCollection(COLLECTION_NAME); + + MongoOperation operation = new MongoOperation(); + operation.setType("createIndex"); + operation.setCollection(COLLECTION_NAME); + + Map params = new HashMap<>(); + Map keys = new HashMap<>(); + keys.put("email", 1); + params.put("keys", keys); + operation.setParameters(params); + + CreateIndexOperator operator = new CreateIndexOperator(mongoDatabase, operation); + operator.apply(null); + + assertTrue(indexExistsByKeys("email"), "Index should exist after creation"); + } + + @Test + @DisplayName("WHEN createIndex operator is applied with options THEN index is created with options") + void createIndexWithOptionsTest() { + mongoDatabase.createCollection(COLLECTION_NAME); + + MongoOperation operation = new MongoOperation(); + operation.setType("createIndex"); + operation.setCollection(COLLECTION_NAME); + + Map params = new HashMap<>(); + Map keys = new HashMap<>(); + keys.put("email", 1); + params.put("keys", keys); + + Map options = new HashMap<>(); + options.put("unique", true); + options.put("name", INDEX_NAME); + params.put("options", options); + + operation.setParameters(params); + + CreateIndexOperator operator = new CreateIndexOperator(mongoDatabase, operation); + operator.apply(null); + + assertTrue(indexExists(INDEX_NAME), "Index should exist with specified name"); + assertTrue(isIndexUnique(INDEX_NAME), "Index should be unique"); + } + + private boolean indexExists(String indexName) { + List indexes = mongoDatabase.getCollection(COLLECTION_NAME) + .listIndexes() + .into(new ArrayList<>()); + return indexes.stream().anyMatch(idx -> indexName.equals(idx.getString("name"))); + } + + private boolean indexExistsByKeys(String keyField) { + List indexes = mongoDatabase.getCollection(COLLECTION_NAME) + .listIndexes() + .into(new ArrayList<>()); + return indexes.stream().anyMatch(idx -> { + Document key = idx.get("key", Document.class); + return key != null && key.containsKey(keyField); + }); + } + + private boolean isIndexUnique(String indexName) { + List indexes = mongoDatabase.getCollection(COLLECTION_NAME) + .listIndexes() + .into(new ArrayList<>()); + return indexes.stream() + .filter(idx -> indexName.equals(idx.getString("name"))) + .anyMatch(idx -> Boolean.TRUE.equals(idx.getBoolean("unique"))); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateViewOperatorTest.java b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateViewOperatorTest.java new file mode 100644 index 000000000..b8b3330c4 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/CreateViewOperatorTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.operations; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import io.flamingock.template.mongodb.model.operator.CreateViewOperator; +import org.bson.Document; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Testcontainers +class CreateViewOperatorTest { + + private static final String DB_NAME = "test"; + private static final String SOURCE_COLLECTION = "viewSourceCollection"; + private static final String VIEW_NAME = "activeUsersView"; + + private static MongoClient mongoClient; + private static MongoDatabase mongoDatabase; + + @Container + public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + + @BeforeAll + static void beforeAll() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + mongoDatabase = mongoClient.getDatabase(DB_NAME); + } + + @BeforeEach + void setupEach() { + mongoDatabase.getCollection(SOURCE_COLLECTION).drop(); + mongoDatabase.getCollection(VIEW_NAME).drop(); + } + + @Test + @DisplayName("WHEN createView operator is applied THEN view is created and filters data") + void createViewTest() { + mongoDatabase.createCollection(SOURCE_COLLECTION); + mongoDatabase.getCollection(SOURCE_COLLECTION).insertMany(Arrays.asList( + new Document("name", "Active User").append("status", "active"), + new Document("name", "Inactive User").append("status", "inactive") + )); + + MongoOperation operation = new MongoOperation(); + operation.setType("createView"); + operation.setCollection(VIEW_NAME); + + Map params = new HashMap<>(); + params.put("viewOn", SOURCE_COLLECTION); + + List> pipeline = new ArrayList<>(); + Map matchStage = new HashMap<>(); + Map matchQuery = new HashMap<>(); + matchQuery.put("status", "active"); + matchStage.put("$match", matchQuery); + pipeline.add(matchStage); + params.put("pipeline", pipeline); + + operation.setParameters(params); + + CreateViewOperator operator = new CreateViewOperator(mongoDatabase, operation); + operator.apply(null); + + List collections = mongoDatabase.listCollectionNames().into(new ArrayList<>()); + assertTrue(collections.contains(VIEW_NAME), "View should exist"); + + List viewResults = mongoDatabase.getCollection(VIEW_NAME) + .find() + .into(new ArrayList<>()); + assertEquals(1, viewResults.size(), "View should return only active users"); + assertEquals("Active User", viewResults.get(0).getString("name")); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropCollectionOperatorTest.java b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropCollectionOperatorTest.java new file mode 100644 index 000000000..276f49e52 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropCollectionOperatorTest.java @@ -0,0 +1,88 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.operations; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import io.flamingock.template.mongodb.model.operator.DropCollectionOperator; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.util.ArrayList; +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Testcontainers +class DropCollectionOperatorTest { + + private static final String DB_NAME = "test"; + private static final String COLLECTION_NAME = "testCollection"; + + private static MongoClient mongoClient; + private static MongoDatabase mongoDatabase; + + @Container + public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + + @BeforeAll + static void beforeAll() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + mongoDatabase = mongoClient.getDatabase(DB_NAME); + } + + @BeforeEach + void setupEach() { + mongoDatabase.getCollection(COLLECTION_NAME).drop(); + } + + @Test + @DisplayName("WHEN dropCollection operator is applied THEN collection is dropped") + void dropCollectionTest() { + mongoDatabase.createCollection(COLLECTION_NAME); + assertTrue(collectionExists(COLLECTION_NAME), "Collection should exist before drop"); + + MongoOperation operation = new MongoOperation(); + operation.setType("dropCollection"); + operation.setCollection(COLLECTION_NAME); + operation.setParameters(new HashMap<>()); + + DropCollectionOperator operator = new DropCollectionOperator(mongoDatabase, operation); + operator.apply(null); + + assertFalse(collectionExists(COLLECTION_NAME), "Collection should have been dropped"); + } + + private boolean collectionExists(String collectionName) { + return mongoDatabase.listCollectionNames() + .into(new ArrayList<>()) + .contains(collectionName); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropIndexOperatorTest.java b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropIndexOperatorTest.java new file mode 100644 index 000000000..fbb4a3342 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropIndexOperatorTest.java @@ -0,0 +1,129 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.operations; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import io.flamingock.template.mongodb.model.operator.DropIndexOperator; +import org.bson.Document; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Testcontainers +class DropIndexOperatorTest { + + private static final String DB_NAME = "test"; + private static final String COLLECTION_NAME = "indexTestCollection"; + private static final String INDEX_NAME = "email_index"; + + private static MongoClient mongoClient; + private static MongoDatabase mongoDatabase; + + @Container + public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + + @BeforeAll + static void beforeAll() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + mongoDatabase = mongoClient.getDatabase(DB_NAME); + } + + @BeforeEach + void setupEach() { + mongoDatabase.getCollection(COLLECTION_NAME).drop(); + } + + @Test + @DisplayName("WHEN dropIndex operator is applied with index name THEN index is dropped") + void dropIndexByNameTest() { + mongoDatabase.createCollection(COLLECTION_NAME); + mongoDatabase.getCollection(COLLECTION_NAME).createIndex(new Document("email", 1), + new com.mongodb.client.model.IndexOptions().name(INDEX_NAME)); + assertTrue(indexExists(INDEX_NAME), "Index should exist before drop"); + + MongoOperation operation = new MongoOperation(); + operation.setType("dropIndex"); + operation.setCollection(COLLECTION_NAME); + Map params = new HashMap<>(); + params.put("indexName", INDEX_NAME); + operation.setParameters(params); + + DropIndexOperator operator = new DropIndexOperator(mongoDatabase, operation); + operator.apply(null); + + assertFalse(indexExists(INDEX_NAME), "Index should have been dropped"); + } + + @Test + @DisplayName("WHEN dropIndex operator is applied with keys THEN index is dropped") + void dropIndexByKeysTest() { + mongoDatabase.createCollection(COLLECTION_NAME); + mongoDatabase.getCollection(COLLECTION_NAME).createIndex(new Document("name", 1)); + assertTrue(indexExistsByKeys("name"), "Index should exist before drop"); + + MongoOperation operation = new MongoOperation(); + operation.setType("dropIndex"); + operation.setCollection(COLLECTION_NAME); + Map params = new HashMap<>(); + Map keys = new HashMap<>(); + keys.put("name", 1); + params.put("keys", keys); + operation.setParameters(params); + + DropIndexOperator operator = new DropIndexOperator(mongoDatabase, operation); + operator.apply(null); + + assertFalse(indexExistsByKeys("name"), "Index should have been dropped"); + } + + private boolean indexExists(String indexName) { + List indexes = mongoDatabase.getCollection(COLLECTION_NAME) + .listIndexes() + .into(new ArrayList<>()); + return indexes.stream().anyMatch(idx -> indexName.equals(idx.getString("name"))); + } + + private boolean indexExistsByKeys(String keyField) { + List indexes = mongoDatabase.getCollection(COLLECTION_NAME) + .listIndexes() + .into(new ArrayList<>()); + return indexes.stream().anyMatch(idx -> { + Document key = idx.get("key", Document.class); + return key != null && key.containsKey(keyField); + }); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropViewOperatorTest.java b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropViewOperatorTest.java new file mode 100644 index 000000000..dfd2b1e4a --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/DropViewOperatorTest.java @@ -0,0 +1,93 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.operations; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import io.flamingock.template.mongodb.model.operator.DropViewOperator; +import org.bson.Document; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Testcontainers +class DropViewOperatorTest { + + private static final String DB_NAME = "test"; + private static final String SOURCE_COLLECTION = "dropViewSourceCollection"; + private static final String VIEW_NAME = "viewToDrop"; + + private static MongoClient mongoClient; + private static MongoDatabase mongoDatabase; + + @Container + public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + + @BeforeAll + static void beforeAll() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + mongoDatabase = mongoClient.getDatabase(DB_NAME); + } + + @BeforeEach + void setupEach() { + mongoDatabase.getCollection(SOURCE_COLLECTION).drop(); + mongoDatabase.getCollection(VIEW_NAME).drop(); + } + + @Test + @DisplayName("WHEN dropView operator is applied THEN view is dropped") + void dropViewTest() { + mongoDatabase.createCollection(SOURCE_COLLECTION); + mongoDatabase.createView(VIEW_NAME, SOURCE_COLLECTION, Collections.emptyList()); + assertTrue(collectionExists(VIEW_NAME), "View should exist before drop"); + + MongoOperation operation = new MongoOperation(); + operation.setType("dropView"); + operation.setCollection(VIEW_NAME); + operation.setParameters(new HashMap<>()); + + DropViewOperator operator = new DropViewOperator(mongoDatabase, operation); + operator.apply(null); + + assertFalse(collectionExists(VIEW_NAME), "View should have been dropped"); + } + + private boolean collectionExists(String collectionName) { + List collections = mongoDatabase.listCollectionNames().into(new ArrayList<>()); + return collections.contains(collectionName); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/InsertOperatorTest.java b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/InsertOperatorTest.java new file mode 100644 index 000000000..87334c1a6 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/InsertOperatorTest.java @@ -0,0 +1,174 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.operations; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import io.flamingock.template.mongodb.model.operator.InsertOperator; +import org.bson.Document; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Testcontainers +class InsertOperatorTest { + + private static final String DB_NAME = "test"; + private static final String COLLECTION_NAME = "insertTestCollection"; + + private static MongoClient mongoClient; + private static MongoDatabase mongoDatabase; + + @Container + public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + + @BeforeAll + static void beforeAll() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + mongoDatabase = mongoClient.getDatabase(DB_NAME); + } + + @BeforeEach + void setupEach() { + mongoDatabase.getCollection(COLLECTION_NAME).drop(); + mongoDatabase.createCollection(COLLECTION_NAME); + } + + @Test + @DisplayName("WHEN insert operator is applied with one document THEN document is inserted") + void insertOneDocumentTest() { + // Verify collection is empty before + assertEquals(0, getDocumentCount(), "Collection should be empty before insert"); + + // Create the operation + MongoOperation operation = new MongoOperation(); + operation.setType("insert"); + operation.setCollection(COLLECTION_NAME); + + Map params = new HashMap<>(); + List> documents = new ArrayList<>(); + Map doc = new HashMap<>(); + doc.put("name", "John Doe"); + doc.put("email", "john@example.com"); + documents.add(doc); + params.put("documents", documents); + operation.setParameters(params); + + // Execute the operator + InsertOperator operator = new InsertOperator(mongoDatabase, operation); + operator.apply(null); + + // Verify + assertEquals(1, getDocumentCount(), "Collection should have one document"); + Document inserted = mongoDatabase.getCollection(COLLECTION_NAME).find().first(); + assertEquals("John Doe", inserted.getString("name")); + assertEquals("john@example.com", inserted.getString("email")); + } + + @Test + @DisplayName("WHEN insert operator is applied with multiple documents THEN documents are inserted") + void insertManyDocumentsTest() { + assertEquals(0, getDocumentCount(), "Collection should be empty before insert"); + + MongoOperation operation = new MongoOperation(); + operation.setType("insert"); + operation.setCollection(COLLECTION_NAME); + + Map params = new HashMap<>(); + List> documents = new ArrayList<>(); + + Map doc1 = new HashMap<>(); + doc1.put("name", "Alice"); + doc1.put("email", "alice@example.com"); + documents.add(doc1); + + Map doc2 = new HashMap<>(); + doc2.put("name", "Bob"); + doc2.put("email", "bob@example.com"); + documents.add(doc2); + + Map doc3 = new HashMap<>(); + doc3.put("name", "Charlie"); + doc3.put("email", "charlie@example.com"); + documents.add(doc3); + + params.put("documents", documents); + operation.setParameters(params); + + InsertOperator operator = new InsertOperator(mongoDatabase, operation); + operator.apply(null); + + assertEquals(3, getDocumentCount(), "Collection should have three documents"); + + List insertedDocs = mongoDatabase.getCollection(COLLECTION_NAME) + .find() + .into(new ArrayList<>()); + + List names = Arrays.asList("Alice", "Bob", "Charlie"); + for (Document doc : insertedDocs) { + assertTrue(names.contains(doc.getString("name")), "Document name should be in expected list"); + } + } + + @Test + @DisplayName("WHEN insert operator is applied with empty documents THEN nothing is inserted") + void insertEmptyDocumentsTest() { + assertEquals(0, getDocumentCount(), "Collection should be empty before insert"); + + MongoOperation operation = new MongoOperation(); + operation.setType("insert"); + operation.setCollection(COLLECTION_NAME); + + Map params = new HashMap<>(); + params.put("documents", new ArrayList<>()); + operation.setParameters(params); + + InsertOperator operator = new InsertOperator(mongoDatabase, operation); + operator.apply(null); + + assertEquals(0, getDocumentCount(), "Collection should still be empty"); + } + + private long getDocumentCount() { + return mongoDatabase.getCollection(COLLECTION_NAME).countDocuments(); + } + + private static void assertTrue(boolean condition, String message) { + if (!condition) { + throw new AssertionError(message); + } + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/ModifyCollectionOperatorTest.java b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/ModifyCollectionOperatorTest.java new file mode 100644 index 000000000..0a4536941 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/ModifyCollectionOperatorTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.operations; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import io.flamingock.template.mongodb.model.operator.ModifyCollectionOperator; +import org.bson.Document; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@Testcontainers +class ModifyCollectionOperatorTest { + + private static final String DB_NAME = "test"; + private static final String COLLECTION_NAME = "modifyTestCollection"; + + private static MongoClient mongoClient; + private static MongoDatabase mongoDatabase; + + @Container + public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + + @BeforeAll + static void beforeAll() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + mongoDatabase = mongoClient.getDatabase(DB_NAME); + } + + @BeforeEach + void setupEach() { + mongoDatabase.getCollection(COLLECTION_NAME).drop(); + } + + @Test + @DisplayName("WHEN modifyCollection operator is applied THEN collection validation is set") + void modifyCollectionTest() { + mongoDatabase.createCollection(COLLECTION_NAME); + + MongoOperation operation = new MongoOperation(); + operation.setType("modifyCollection"); + operation.setCollection(COLLECTION_NAME); + + Map params = new HashMap<>(); + Map validator = new HashMap<>(); + Map jsonSchema = new HashMap<>(); + jsonSchema.put("bsonType", "object"); + validator.put("$jsonSchema", jsonSchema); + params.put("validator", validator); + params.put("validationLevel", "moderate"); + params.put("validationAction", "warn"); + operation.setParameters(params); + + ModifyCollectionOperator operator = new ModifyCollectionOperator(mongoDatabase, operation); + operator.apply(null); + + Document collectionInfo = mongoDatabase.listCollections() + .filter(new Document("name", COLLECTION_NAME)) + .first(); + assertNotNull(collectionInfo, "Collection should exist"); + Document options = collectionInfo.get("options", Document.class); + assertNotNull(options, "Collection should have options"); + assertNotNull(options.get("validator"), "Collection should have validator"); + } +} diff --git a/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/RenameCollectionOperatorTest.java b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/RenameCollectionOperatorTest.java new file mode 100644 index 000000000..e9c576b54 --- /dev/null +++ b/templates/flamingock-mongodb-sync-template/src/test/java/io/flamingock/template/mongodb/operations/RenameCollectionOperatorTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.template.mongodb.operations; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import io.flamingock.template.mongodb.model.MongoOperation; +import io.flamingock.template.mongodb.model.operator.RenameCollectionOperator; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Testcontainers +class RenameCollectionOperatorTest { + + private static final String DB_NAME = "test"; + private static final String ORIGINAL_NAME = "originalCollection"; + private static final String RENAMED_NAME = "renamedCollection"; + + private static MongoClient mongoClient; + private static MongoDatabase mongoDatabase; + + @Container + public static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:6")); + + @BeforeAll + static void beforeAll() { + mongoClient = MongoClients.create(MongoClientSettings + .builder() + .applyConnectionString(new ConnectionString(mongoDBContainer.getConnectionString())) + .build()); + mongoDatabase = mongoClient.getDatabase(DB_NAME); + } + + @BeforeEach + void setupEach() { + mongoDatabase.getCollection(ORIGINAL_NAME).drop(); + mongoDatabase.getCollection(RENAMED_NAME).drop(); + } + + @Test + @DisplayName("WHEN renameCollection operator is applied THEN collection is renamed") + void renameCollectionTest() { + mongoDatabase.createCollection(ORIGINAL_NAME); + assertTrue(collectionExists(ORIGINAL_NAME), "Original collection should exist before rename"); + + MongoOperation operation = new MongoOperation(); + operation.setType("renameCollection"); + operation.setCollection(ORIGINAL_NAME); + Map params = new HashMap<>(); + params.put("target", RENAMED_NAME); + operation.setParameters(params); + + RenameCollectionOperator operator = new RenameCollectionOperator(mongoDatabase, operation); + operator.apply(null); + + assertFalse(collectionExists(ORIGINAL_NAME), "Original collection should not exist after rename"); + assertTrue(collectionExists(RENAMED_NAME), "Renamed collection should exist"); + } + + private boolean collectionExists(String collectionName) { + List collections = mongoDatabase.listCollectionNames().into(new ArrayList<>()); + return collections.contains(collectionName); + } +}