diff --git a/app/server/appsmith-plugins/mongoPlugin/pom.xml b/app/server/appsmith-plugins/mongoPlugin/pom.xml index eb23e20225..fcb6b212c4 100644 --- a/app/server/appsmith-plugins/mongoPlugin/pom.xml +++ b/app/server/appsmith-plugins/mongoPlugin/pom.xml @@ -44,11 +44,6 @@ 1.18.8 provided - - org.mongodb - mongo-java-driver - 3.11.1 - diff --git a/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java b/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java index 8c22861c49..803b8a81f6 100644 --- a/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java +++ b/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java @@ -14,12 +14,16 @@ import com.appsmith.external.pluginExceptions.AppsmithPluginException; import com.appsmith.external.pluginExceptions.StaleConnectionException; import com.appsmith.external.plugins.BasePlugin; import com.appsmith.external.plugins.PluginExecutor; -import com.mongodb.MongoClient; -import com.mongodb.MongoClientURI; import com.mongodb.MongoCommandException; import com.mongodb.MongoTimeoutException; -import com.mongodb.client.ClientSession; -import com.mongodb.client.MongoDatabase; +import com.mongodb.MongoClientURI; +import com.mongodb.reactivestreams.client.MongoClient; +import com.mongodb.reactivestreams.client.MongoClients; +import com.mongodb.reactivestreams.client.ClientSession; +import com.mongodb.reactivestreams.client.MongoCollection; +import com.mongodb.reactivestreams.client.MongoDatabase; +import com.mongodb.reactivestreams.client.Success; + import lombok.extern.slf4j.Slf4j; import org.bson.Document; import org.bson.conversions.Bson; @@ -32,6 +36,7 @@ import org.pf4j.PluginWrapper; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; +import reactor.core.publisher.Flux; import java.math.BigDecimal; import java.math.BigInteger; @@ -81,7 +86,7 @@ public class MongoPlugin extends BasePlugin { * https://docs.huihoo.com/mongodb/3.4/reference/command/index.html * * @param mongoClient : This is the connection that is established to the data source. This connection is according - * to the parameters in Datasource Configuration + * to the parameters in Datasource Configuration * @param datasourceConfiguration : These are the configurations which have been used to create a Datasource from a Plugin * @param actionConfiguration : These are the configurations which have been used to create an Action from a Datasource. * @return Result data from executing the action's query. @@ -96,71 +101,79 @@ public class MongoPlugin extends BasePlugin { throw new StaleConnectionException(); } + MongoDatabase database = mongoClient.getDatabase(getDatabaseName(datasourceConfiguration)); + Bson command = Document.parse(actionConfiguration.getBody()); + Mono mongoOutputMono = Mono.from(database.runCommand(command)); ActionExecutionResult result = new ActionExecutionResult(); - MongoDatabase database = mongoClient.getDatabase(getDatabaseName(datasourceConfiguration)); + return mongoOutputMono + .flatMap(mongoOutput -> { + try { + JSONObject outputJson = new JSONObject(mongoOutput.toJson()); + //The output json contains the key "ok". This is the status of the command + BigInteger status = outputJson.getBigInteger("ok"); + JSONArray headerArray = new JSONArray(); - Bson command = Document.parse(actionConfiguration.getBody()); + if (BigInteger.ONE.equals(status)) { + result.setIsExecutionSuccess(true); - try { - Document mongoOutput = database.runCommand(command); + /** + * For the `findAndModify` command, we don't get the count of modifications made. Instead, + * we either get the modified new value or the pre-modified old value (depending on the + * `new` field in the command. Let's return that value to the user. + */ + if (outputJson.has(VALUE_STR)) { + result.setBody(objectMapper.readTree( + cleanUp(new JSONObject().put(VALUE_STR, outputJson.get(VALUE_STR))).toString() + )); + } - JSONObject outputJson = new JSONObject(mongoOutput.toJson()); + /** + * The json contains key "cursor" when find command was issued and there are 1 or more + * results. In case there are no results for find, this key is not present in the result json. + */ + if (outputJson.has("cursor")) { + JSONArray outputResult = (JSONArray) cleanUp( + outputJson.getJSONObject("cursor").getJSONArray("firstBatch")); + result.setBody(objectMapper.readTree(outputResult.toString())); + } - //The output json contains the key "ok". This is the status of the command - BigInteger status = outputJson.getBigInteger("ok"); - JSONArray headerArray = new JSONArray(); + /** + * The json contains key "n" when insert/update command is issued. "n" for update + * signifies the no of documents selected for update. "n" in case of insert signifies the + * number of documents inserted. + */ + if (outputJson.has("n")) { + JSONObject body = new JSONObject().put("n", outputJson.getBigInteger("n")); + result.setBody(body); + headerArray.put(body); + } - if (BigInteger.ONE.equals(status)) { - result.setIsExecutionSuccess(true); + /** + * The json key contains key "nModified" in case of update command. This signifies the no of + * documents updated. + */ + if (outputJson.has(N_MODIFIED)) { + JSONObject body = new JSONObject().put(N_MODIFIED, outputJson.getBigInteger(N_MODIFIED)); + result.setBody(body); + headerArray.put(body); + } - // For the `findAndModify` command, we don't get the count of modifications made. Instead, we either - // get the modified new value or the pre-modified old value (depending on the `new` field in the - // command. Let's return that value to the user. - if (outputJson.has(VALUE_STR)) { - result.setBody(objectMapper.readTree( - cleanUp(new JSONObject().put(VALUE_STR, outputJson.get(VALUE_STR))).toString() - )); - } + /** TODO + * Go through all the possible fields that are returned in the output JSON and add all the fields + * that are important to the headerArray. + */ + } - //The json contains key "cursor" when find command was issued and there are 1 or more results. In case - //there are no results for find, this key is not present in the result json. - if (outputJson.has("cursor")) { - JSONArray outputResult = (JSONArray) cleanUp( - outputJson.getJSONObject("cursor").getJSONArray("firstBatch")); - result.setBody(objectMapper.readTree(outputResult.toString())); - } + JSONObject statusJson = new JSONObject().put("ok", status); + headerArray.put(statusJson); + result.setHeaders(objectMapper.readTree(headerArray.toString())); + } catch (Exception e) { + return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, e)); + } - //The json contains key "n" when insert/update command is issued. "n" for update signifies the no of - //documents selected for update. "n" in case of insert signifies the number of documents inserted. - if (outputJson.has("n")) { - JSONObject body = new JSONObject().put("n", outputJson.getBigInteger("n")); - result.setBody(body); - headerArray.put(body); - } - - //The json key contains key "nModified" in case of update command. This signifies the no of - //documents updated. - if (outputJson.has(N_MODIFIED)) { - JSONObject body = new JSONObject().put(N_MODIFIED, outputJson.getBigInteger(N_MODIFIED)); - result.setBody(body); - headerArray.put(body); - } - - /** TODO - * Go through all the possible fields that are returned in the output JSON and add all the fields - * that are important to the headerArray. - */ - } - - JSONObject statusJson = new JSONObject().put("ok", status); - headerArray.put(statusJson); - result.setHeaders(objectMapper.readTree(headerArray.toString())); - } catch (Exception e) { - return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, e)); - } - - return Mono.just(result); + return Mono.just(result); + }); } private String getDatabaseName(DatasourceConfiguration datasourceConfiguration) { @@ -178,18 +191,20 @@ public class MongoPlugin extends BasePlugin { @Override public Mono datasourceCreate(DatasourceConfiguration datasourceConfiguration) { - // TODO: ReadOnly seems to be not supported at the driver level. The recommendation is to connect with a - // user that doesn't have write permissions on the database. - // Ref: https://api.mongodb.com/java/2.13/com/mongodb/DB.html#setReadOnly-java.lang.Boolean- + /** + * TODO: ReadOnly seems to be not supported at the driver level. The recommendation is to connect with a + * user that doesn't have write permissions on the database. + * Ref: https://api.mongodb.com/java/2.13/com/mongodb/DB.html#setReadOnly-java.lang.Boolean- + */ try { - return Mono.just(new MongoClient(buildClientURI(datasourceConfiguration))); + return Mono.just(MongoClients.create(buildClientURI(datasourceConfiguration))); } catch (Exception e) { return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, e)); } } - public static MongoClientURI buildClientURI(DatasourceConfiguration datasourceConfiguration) { + public static String buildClientURI(DatasourceConfiguration datasourceConfiguration) { StringBuilder builder = new StringBuilder(); final Connection connection = datasourceConfiguration.getConnection(); @@ -252,9 +267,7 @@ public class MongoPlugin extends BasePlugin { builder.deleteCharAt(builder.length() - 1); } - final String uri = builder.toString(); - log.info("MongoPlugin URI: `{}`.", uri); - return new MongoClientURI(uri); + return builder.toString(); } @Override @@ -313,56 +326,22 @@ public class MongoPlugin extends BasePlugin { @Override public Mono testDatasource(DatasourceConfiguration datasourceConfiguration) { - final Connection.Type connectionType = datasourceConfiguration.getConnection().getType(); return datasourceCreate(datasourceConfiguration) - .map(mongoClient -> { - ClientSession clientSession = null; - - try { - // Not using try-with-resources here since we want to close the *session* before closing the - // MongoClient instance. - if (Connection.Type.REPLICA_SET.equals(connectionType)) { - // For REPLICA_SET connections, we check by creating a session, as this is faster. - clientSession = mongoClient.startSession(); - - } else { - // For DIRECT connections, we check by running a DB command, as it's the only reliable - // method of checking if the connection is usable. - mongoClient - .getDatabase("admin") - .runCommand(new Document("listDatabases", 1)); - return new DatasourceTestResult(); - - } - - } catch (MongoTimeoutException e) { - log.warn("Timeout connecting to MongoDB from MongoPlugin.", e); - return new DatasourceTestResult("Timed out trying to connect to MongoDB host."); - - } catch (MongoCommandException e) { - // The fact that we got a response saying "Unauthorized" means that the connection to the - // MongoDB instance is valid. It also means we don't have access to the admin database, but - // that's okay for our purposes here. - return "Unauthorized".equals(e.getErrorCodeName()) - ? new DatasourceTestResult() - : new DatasourceTestResult(e.getMessage()); - - } catch (Exception e) { - return new DatasourceTestResult(e.getMessage()); - - } finally { - if (clientSession != null) { - clientSession.close(); - } - if (mongoClient != null) { - mongoClient.close(); - } - - } - - return new DatasourceTestResult(); + .flatMap(mongoClient -> { + return Mono.zip(Mono.just(mongoClient), + Mono.from(mongoClient.getDatabase("admin").runCommand(new Document( + "listDatabases", 1)))); }) - .onErrorResume(error -> Mono.just(new DatasourceTestResult(error.getMessage()))); + .doOnSuccess(tuple -> { + MongoClient mongoClient = tuple.getT1(); + + if(mongoClient != null) { + mongoClient.close(); + } + }) + .then(Mono.just(new DatasourceTestResult())) + .onErrorResume(error -> { + return Mono.just(new DatasourceTestResult(error.getMessage()));}); } @Override @@ -370,166 +349,181 @@ public class MongoPlugin extends BasePlugin { final DatasourceStructure structure = new DatasourceStructure(); List tables = new ArrayList<>(); structure.setTables(tables); - final MongoDatabase database = mongoClient.getDatabase(getDatabaseName(datasourceConfiguration)); - for (Document collection : database.listCollections()) { - final String collectionName = collection.getString("name"); + return Flux.from(database.listCollectionNames()). + flatMap(collectionName -> { + final ArrayList columns = new ArrayList<>(); + final ArrayList templates = new ArrayList<>(); + tables.add(new DatasourceStructure.Table( + DatasourceStructure.TableType.COLLECTION, + collectionName, + columns, + new ArrayList<>(), + templates + )); - final ArrayList columns = new ArrayList<>(); - final ArrayList templates = new ArrayList<>(); - tables.add(new DatasourceStructure.Table( - DatasourceStructure.TableType.COLLECTION, - collectionName, - columns, - new ArrayList<>(), - templates - )); + return Mono.zip( + Mono.just(columns), + Mono.just(templates), + Mono.just(collectionName), + Mono.from(database.getCollection(collectionName).find().limit(1).first()) + ); + }). + flatMap(tuple -> { + final ArrayList columns = tuple.getT1(); + final ArrayList templates = tuple.getT2(); + String collectionName = tuple.getT3(); + Document document = tuple.getT4(); - final Document first = database.getCollection(collectionName).find().limit(1).first(); - if (first == null) { - continue; - } + generateTemplatesAndStructureForACollection(collectionName, document, columns, templates); - String filterFieldName = null; - String filterFieldValue = null; - Map sampleInsertValues = new LinkedHashMap<>(); - - for (Map.Entry entry : first.entrySet()) { - final String name = entry.getKey(); - final Object value = entry.getValue(); - String type; - - if (value instanceof Integer) { - type = "Integer"; - sampleInsertValues.put(name, "1"); - } else if (value instanceof Long) { - type = "Long"; - sampleInsertValues.put(name, "NumberLong(\"1\")"); - } else if (value instanceof Double) { - type = "Double"; - sampleInsertValues.put(name, "1"); - } else if (value instanceof Decimal128) { - type = "BigDecimal"; - sampleInsertValues.put(name, "NumberDecimal(\"1\")"); - } else if (value instanceof String) { - type = "String"; - sampleInsertValues.put(name, "\"new value\""); - if (filterFieldName == null || filterFieldName.compareTo(name) > 0) { - filterFieldName = name; - filterFieldValue = (String) value; - } - } else if (value instanceof ObjectId) { - type = "ObjectId"; - if (!value.equals("_id")) { - sampleInsertValues.put(name, "ObjectId(\"a_valid_object_id_hex\")"); - } - } else if (value instanceof Collection) { - type = "Array"; - sampleInsertValues.put(name, "[1, 2, 3]"); - } else if (value instanceof Date) { - type = "Date"; - sampleInsertValues.put(name, "new Date(\"2019-07-01\")"); - } else { - type = "Object"; - sampleInsertValues.put(name, "{}"); - } - - columns.add(new DatasourceStructure.Column(name, type, null)); - } - - columns.sort(Comparator.naturalOrder()); - - templates.add( - new DatasourceStructure.Template( - "Find", - "{\n" + - " \"find\": \"" + collectionName + "\",\n" + - ( - filterFieldName == null ? "" : - " \"filter\": {\n" + - " \"" + filterFieldName + "\": \"" + filterFieldValue + "\"\n" + - " },\n" - ) + - " \"sort\": {\n" + - " \"_id\": 1\n" + - " },\n" + - " \"limit\": 10\n" + - "}\n" - ) - ); - - templates.add( - new DatasourceStructure.Template( - "Find by ID", - "{\n" + - " \"find\": \"" + collectionName + "\",\n" + - " \"filter\": {\n" + - " \"_id\": ObjectId(\"id_to_query_with\")\n" + - " }\n" + - "}\n" - ) - ); - - sampleInsertValues.entrySet().stream() - .map(entry -> " \"" + entry.getKey() + "\": " + entry.getValue() + ",\n") - .collect(Collectors.joining("")); - templates.add( - new DatasourceStructure.Template( - "Insert", - "{\n" + - " \"insert\": \"" + collectionName + "\",\n" + - " \"documents\": [\n" + - " {\n" + - sampleInsertValues.entrySet().stream() - .map(entry -> " \"" + entry.getKey() + "\": " + entry.getValue() + ",\n") - .sorted() - .collect(Collectors.joining("")) + - " }\n" + - " ]\n" + - "}\n" - ) - ); - - templates.add( - new DatasourceStructure.Template( - "Update", - "{\n" + - " \"update\": \"" + collectionName + "\",\n" + - " \"updates\": [\n" + - " {\n" + - " \"q\": {\n" + - " \"_id\": ObjectId(\"id_of_document_to_update\")\n" + - " },\n" + - " \"u\": { \"$set\": { \"" + filterFieldName + "\": \"new value\" } }\n" + - " }\n" + - " ]\n" + - "}\n" - ) - ); - - templates.add( - new DatasourceStructure.Template( - "Delete", - "{\n" + - " \"delete\": \"" + collectionName + "\",\n" + - " \"deletes\": [\n" + - " {\n" + - " \"q\": {\n" + - " \"_id\": \"id_of_document_to_delete\"\n" + - " },\n" + - " \"limit\": 1\n" + - " }\n" + - " ]\n" + - "}\n" - ) - ); - } - - tables.sort(Comparator.comparing(DatasourceStructure.Table::getName)); - return Mono.just(structure); + return Mono.just(structure); + }). + collectList(). + flatMap(documentList -> { + return Mono.just(structure); + }); } + private static void generateTemplatesAndStructureForACollection(String collectionName, + Document document, + ArrayList columns, + ArrayList templates) { + String filterFieldName = null; + String filterFieldValue = null; + Map sampleInsertValues = new LinkedHashMap<>(); + + for (Map.Entry entry : document.entrySet()) { + final String name = entry.getKey(); + final Object value = entry.getValue(); + String type; + + if (value instanceof Integer) { + type = "Integer"; + sampleInsertValues.put(name, "1"); + } else if (value instanceof Long) { + type = "Long"; + sampleInsertValues.put(name, "NumberLong(\"1\")"); + } else if (value instanceof Double) { + type = "Double"; + sampleInsertValues.put(name, "1"); + } else if (value instanceof Decimal128) { + type = "BigDecimal"; + sampleInsertValues.put(name, "NumberDecimal(\"1\")"); + } else if (value instanceof String) { + type = "String"; + sampleInsertValues.put(name, "\"new value\""); + if (filterFieldName == null || filterFieldName.compareTo(name) > 0) { + filterFieldName = name; + filterFieldValue = (String) value; + } + } else if (value instanceof ObjectId) { + type = "ObjectId"; + if (!value.equals("_id")) { + sampleInsertValues.put(name, "ObjectId(\"a_valid_object_id_hex\")"); + } + } else if (value instanceof Collection) { + type = "Array"; + sampleInsertValues.put(name, "[1, 2, 3]"); + } else if (value instanceof Date) { + type = "Date"; + sampleInsertValues.put(name, "new Date(\"2019-07-01\")"); + } else { + type = "Object"; + sampleInsertValues.put(name, "{}"); + } + + columns.add(new DatasourceStructure.Column(name, type, null)); + } + + columns.sort(Comparator.naturalOrder()); + + templates.add( + new DatasourceStructure.Template( + "Find", + "{\n" + + " \"find\": \"" + collectionName + "\",\n" + + ( + filterFieldName == null ? "" : + " \"filter\": {\n" + + " \"" + filterFieldName + "\": \"" + filterFieldValue + "\"\n" + + " },\n" + ) + + " \"sort\": {\n" + + " \"_id\": 1\n" + + " },\n" + + " \"limit\": 10\n" + + "}\n" + ) + ); + + templates.add( + new DatasourceStructure.Template( + "Find by ID", + "{\n" + + " \"find\": \"" + collectionName + "\",\n" + + " \"filter\": {\n" + + " \"_id\": ObjectId(\"id_to_query_with\")\n" + + " }\n" + + "}\n" + ) + ); + + sampleInsertValues.entrySet().stream() + .map(entry -> " \"" + entry.getKey() + "\": " + entry.getValue() + ",\n") + .collect(Collectors.joining("")); + templates.add( + new DatasourceStructure.Template( + "Insert", + "{\n" + + " \"insert\": \"" + collectionName + "\",\n" + + " \"documents\": [\n" + + " {\n" + + sampleInsertValues.entrySet().stream() + .map(entry -> " \"" + entry.getKey() + "\": " + entry.getValue() + ",\n") + .sorted() + .collect(Collectors.joining("")) + + " }\n" + + " ]\n" + + "}\n" + ) + ); + + templates.add( + new DatasourceStructure.Template( + "Update", + "{\n" + + " \"update\": \"" + collectionName + "\",\n" + + " \"updates\": [\n" + + " {\n" + + " \"q\": {\n" + + " \"_id\": ObjectId(\"id_of_document_to_update\")\n" + + " },\n" + + " \"u\": { \"$set\": { \"" + filterFieldName + "\": \"new value\" } }\n" + + " }\n" + + " ]\n" + + "}\n" + ) + ); + + templates.add( + new DatasourceStructure.Template( + "Delete", + "{\n" + + " \"delete\": \"" + collectionName + "\",\n" + + " \"deletes\": [\n" + + " {\n" + + " \"q\": {\n" + + " \"_id\": \"id_of_document_to_delete\"\n" + + " },\n" + + " \"limit\": 1\n" + + " }\n" + + " ]\n" + + "}\n" + ) + ); + } } private static String urlEncode(String text) { diff --git a/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java b/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java index 84d380ef6f..0e8230f30d 100644 --- a/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java +++ b/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java @@ -9,14 +9,24 @@ import com.appsmith.external.models.Endpoint; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.mongodb.MongoClient; -import com.mongodb.client.MongoCollection; + +import com.mongodb.reactivestreams.client.MongoClient; +import com.mongodb.reactivestreams.client.MongoClients; +import com.mongodb.reactivestreams.client.ClientSession; +import com.mongodb.reactivestreams.client.MongoCollection; +import com.mongodb.reactivestreams.client.MongoDatabase; +import com.mongodb.reactivestreams.client.Success; +import org.reactivestreams.Publisher; +import java.util.concurrent.TimeUnit; + +import org.json.JSONObject; import org.bson.Document; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.testcontainers.containers.GenericContainer; import reactor.core.publisher.Mono; +import reactor.core.publisher.Flux; import reactor.test.StepVerifier; import java.math.BigDecimal; @@ -25,14 +35,12 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * Unit tests for MongoPlugin */ + public class MongoPluginTest { MongoPlugin.MongoPluginExecutor pluginExecutor = new MongoPlugin.MongoPluginExecutor(); @@ -51,23 +59,30 @@ public class MongoPluginTest { public static void setUp() { address = mongoContainer.getContainerIpAddress(); port = mongoContainer.getFirstMappedPort(); + String uri = "mongodb://" + address + ":" + Integer.toString(port); + final MongoClient mongoClient = MongoClients.create(uri); - final MongoClient mongoClient = new MongoClient(address, port); - if (!mongoClient.getDatabase("test").listCollectionNames().iterator().hasNext()) { - final MongoCollection usersCollection = mongoClient.getDatabase("test").getCollection("users"); - usersCollection.insertMany(List.of( - new Document(Map.of( - "name", "Cierra Vega", - "gender", "F", - "age", 20, - "luckyNumber", 987654321L, - "dob", LocalDate.of(2018, 12, 31), - "netWorth", new BigDecimal("123456.789012") - )), - new Document(Map.of("name", "Alden Cantrell", "gender", "M", "age", 30)), - new Document(Map.of("name", "Kierra Gentry", "gender", "F", "age", 40)) - )); - } + Flux.from(mongoClient.getDatabase("test").listCollectionNames()).collectList(). + flatMap(collectionNamesList -> { + final MongoCollection usersCollection = mongoClient.getDatabase("test").getCollection( + "users"); + if(collectionNamesList.size() == 0) { + Mono.from(usersCollection.insertMany(List.of( + new Document(Map.of( + "name", "Cierra Vega", + "gender", "F", + "age", 20, + "luckyNumber", 987654321L, + "dob", LocalDate.of(2018, 12, 31), + "netWorth", new BigDecimal("123456.789012") + )), + new Document(Map.of("name", "Alden Cantrell", "gender", "M", "age", 30)), + new Document(Map.of("name", "Kierra Gentry", "gender", "F", "age", 40)) + ))).block(); + } + + return Mono.just(usersCollection); + }).block(); } private DatasourceConfiguration createDatasourceConfiguration() { @@ -103,6 +118,25 @@ public class MongoPluginTest { .verifyComplete(); } + /** + * 1. Test "testDatasource" method in MongoPluginExecutor class. + */ + @Test + public void testDatasourceFail() { + System.out.println(mongoContainer.getContainerIpAddress()); + System.out.println(mongoContainer.getFirstMappedPort()); + DatasourceConfiguration dsConfig = createDatasourceConfiguration(); + dsConfig.getEndpoints().get(0).setHost("badHost"); + System.out.println(dsConfig); + + StepVerifier.create(pluginExecutor.testDatasource(dsConfig)) + .assertNext(datasourceTestResult -> { + assertNotNull(datasourceTestResult); + assertFalse(datasourceTestResult.isSuccess()); + }) + .verifyComplete(); + } + @Test public void testExecuteReadQuery() { DatasourceConfiguration dsConfig = createDatasourceConfiguration(); @@ -311,5 +345,4 @@ public class MongoPluginTest { }) .verifyComplete(); } - }