Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ public class BsonDocumentConverter {
public static final String DECODE = "decode";
public static final String BUILDER = "builder";
public static final String BUILD = "build";
private static final String ORG_BSON_CODECS_CONFIGURATION_CODEC_REGISTRY = "org.bson.codecs.configuration.CodecRegistry";
private static final String COM_MONGODB_MONGO_CLIENT_SETTINGS = "com.mongodb.MongoClientSettings";
private static final String COM_MONGODB_MONGO_CLIENT = "com.mongodb.MongoClient";
private static final String GET_DEFAULT_CODEC_REGISTRY = "getDefaultCodecRegistry";

/**
* Checks if the given object is an instance of a org.bson.BsonDocument.
Expand Down Expand Up @@ -62,14 +66,41 @@ public static boolean isBsonDocument(Object value) {
if (bsonDocumentClass.isInstance(bson)) {
return bson;
}
Object bsonDocument = bsonClass.getMethod(TO_BSON_DOCUMENT).invoke(bson);
return bsonDocument;
return invokeToBsonDocument(bsonClass, bsonDocumentClass, bson);
} catch (Exception | LinkageError e) {
SimpleLogger.uniqueWarn("Failed to convert Mongo query from Bson: " + e);
return null;
}
}

/**
* Calls the no-arg Bson.toBsonDocument(), which only exists since driver 4.2.
* For older drivers, falls back to toBsonDocument(Class, CodecRegistry) with the default registry.
*/
private static Object invokeToBsonDocument(Class<?> bsonClass, Class<?> bsonDocumentClass, Object bson) throws Exception {
try {
return bsonClass.getMethod(TO_BSON_DOCUMENT).invoke(bson);
} catch (NoSuchMethodException e) {
// driver < 4.2
Class<?> codecRegistryClass = loadClass(ORG_BSON_CODECS_CONFIGURATION_CODEC_REGISTRY, bson);
Object registry = getDefaultCodecRegistry(bson);
return bsonClass.getMethod(TO_BSON_DOCUMENT, Class.class, codecRegistryClass)
.invoke(bson, bsonDocumentClass, registry);
}
}

private static Object getDefaultCodecRegistry(Object instance) throws Exception {
try {
// driver >= 3.7
return loadClass(COM_MONGODB_MONGO_CLIENT_SETTINGS, instance)
.getMethod(GET_DEFAULT_CODEC_REGISTRY).invoke(null);
} catch (ClassNotFoundException | NoSuchMethodException e) {
// legacy driver (eg, 3.2)
return loadClass(COM_MONGODB_MONGO_CLIENT, instance)
.getMethod(GET_DEFAULT_CODEC_REGISTRY).invoke(null);
}
}

/**
* Converts an object of type org.bson.BsonDocument to a corresponding org.bson.Document object.
* If the input object is null, the method returns null. It also handles cases where the input
Expand Down
1 change: 1 addition & 0 deletions core-tests/e2e-tests/spring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<module>spring-rest-h2-z3solver</module>
<module>spring-web</module>
<module>spring-rest-mongo</module>
<module>spring-rest-mongo-legacy</module>
<module>spring-rest-bb</module>
<module>spring-graphql-bb</module>
<module>spring-rest-multidb</module>
Expand Down
112 changes: 112 additions & 0 deletions core-tests/e2e-tests/spring/spring-rest-mongo-legacy/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<artifactId>evomaster-e2e-tests-spring</artifactId>
<groupId>org.evomaster</groupId>
<version>6.2.1-SNAPSHOT</version>
</parent>

<artifactId>evomaster-e2e-tests-spring-rest-mongo-legacy</artifactId>
<packaging>jar</packaging>

<properties>
<skipTests>${skipMongo}</skipTests>
<!--
Legacy MongoDB driver, used to check that EvoMaster handles drivers older than 4.2
(eg, Bson.toBsonDocument() without arguments does not exist in 3.x).
Note: Spring Data MongoDB is not used, as recent versions require a 4.x driver.
-->
<mongo.legacy.driver.version>3.8.2</mongo.legacy.driver.version>
</properties>

<dependencies>
<dependency>
<groupId>org.evomaster</groupId>
<artifactId>evomaster-e2e-tests-utils</artifactId>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>org.evomaster</groupId>
<artifactId>evomaster-client-java-controller</artifactId>
</dependency>
<dependency>
<groupId>org.evomaster</groupId>
<artifactId>evomaster-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.evomaster</groupId>
<artifactId>evomaster-client-java-instrumentation</artifactId>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- uber jar, including bson, driver-core, sync and legacy APIs -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>${mongo.legacy.driver.version}</version>
</dependency>
<!--
the controller brings validation-api 1.1.0, which is incompatible with hibernate-validator 6.x
(eg, missing BootstrapConfiguration.getClockProviderClassName()), as in spring-rest-mongo
-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
</dependency>
</dependencies>


<build>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- same as in spring-rest-mongo: use separate JVM processes for each test -->
<reuseForks>false</reuseForks>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.mongolegacy;

import org.springframework.context.annotation.Bean;
import org.springframework.web.context.request.WebRequest;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import static springfox.documentation.builders.PathSelectors.regex;

public class SwaggerConfiguration {

String path;

public SwaggerConfiguration(String path) {
this.path = path;
}

@Bean
public Docket docketApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.paths(regex("/" + path + "/.*"))
.build()
.ignoredParameterTypes(WebRequest.class);
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API")
.description("Some description")
.version("1.0")
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.mongolegacy.persons;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongolegacy.SwaggerConfiguration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.context.annotation.Bean;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
* SUT using directly the legacy MongoDB driver 3.8 (no Spring Data).
* Spring Boot auto-configuration for Mongo is excluded, as it targets 4.x drivers.
*/
@EnableSwagger2
@SpringBootApplication(exclude = MongoAutoConfiguration.class)
public class LegacyMongoPersonsApp extends SwaggerConfiguration {

public LegacyMongoPersonsApp() {
super("legacymongo");
}

@Bean(destroyMethod = "close")
public MongoClient mongoClient(@Value("${spring.data.mongodb.host}") String host,
@Value("${spring.data.mongodb.port}") int port) {
return MongoClients.create("mongodb://" + host + ":" + port);
}

public static void main(String[] args) {
SpringApplication.run(LegacyMongoPersonsApp.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.mongolegacy.persons;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(path = "/legacymongo")
public class LegacyMongoPersonsRest {

@Autowired
private MongoClient mongoClient;

@Value("${spring.data.mongodb.database}")
private String databaseName;

private MongoCollection<Document> persons() {
return mongoClient.getDatabase(databaseName).getCollection("persons");
}

@PostMapping("/persons")
public ResponseEntity<Void> create(@RequestBody LegacyPersonDto dto) {
if (dto == null || dto.name == null || dto.age == null) {
return ResponseEntity.status(400).build();
}
persons().insertOne(new Document("name", dto.name).append("age", dto.age));
return ResponseEntity.status(201).build();
}

@GetMapping("/persons")
public ResponseEntity<Void> find(@RequestParam String name, @RequestParam int age) {
/*
Filters do not return a BsonDocument. With driver 3.x, converting them
requires Bson.toBsonDocument(Class, CodecRegistry), as the no-arg version only exists since 4.2
*/
Document found = persons()
.find(Filters.and(Filters.eq("name", name), Filters.gte("age", age)))
.first();
int status = found != null ? 200 : 404;
return ResponseEntity.status(status).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.mongolegacy.persons;

public class LegacyPersonDto {

public String name;

public Integer age;
}
Loading
Loading