Add support for reactive streams with mongodb. (#1720)

Add support for reactive streams with mongodb. (fixes 1480)

1. Replace mongodb driver with reactive mongodb driver. Change APIs accordingly.
2. Use webflux + reactor framework to execute mongodb queries in event loop model.
3. Add test to test MongoPluginExecutor class' method "testDatasource".
This commit is contained in:
Sumit Kumar 2020-11-18 10:58:50 +05:30 committed by GitHub
parent fc3197b78f
commit 2c2aa06e32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 319 additions and 297 deletions

View File

@ -44,11 +44,6 @@
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.11.1</version>
</dependency>
<!-- Test Dependencies -->
<dependency>

View File

@ -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<Document> 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<MongoClient> 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<DatasourceTestResult> 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<DatasourceStructure.Table> 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<DatasourceStructure.Column> columns = new ArrayList<>();
final ArrayList<DatasourceStructure.Template> templates = new ArrayList<>();
tables.add(new DatasourceStructure.Table(
DatasourceStructure.TableType.COLLECTION,
collectionName,
columns,
new ArrayList<>(),
templates
));
final ArrayList<DatasourceStructure.Column> columns = new ArrayList<>();
final ArrayList<DatasourceStructure.Template> 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<DatasourceStructure.Column> columns = tuple.getT1();
final ArrayList<DatasourceStructure.Template> 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<String, String> sampleInsertValues = new LinkedHashMap<>();
for (Map.Entry<String, Object> 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<DatasourceStructure.Column> columns,
ArrayList<DatasourceStructure.Template> templates) {
String filterFieldName = null;
String filterFieldValue = null;
Map<String, String> sampleInsertValues = new LinkedHashMap<>();
for (Map.Entry<String, Object> 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) {

View File

@ -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<Document> 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<Document> 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();
}
}