Skip to content

Commit

Permalink
ADD: mongo populator, junit4 rule, junit5 extension
Browse files Browse the repository at this point in the history
  • Loading branch information
antkorwin committed Dec 1, 2018
0 parents commit a9205b1
Show file tree
Hide file tree
Showing 26 changed files with 1,103 additions and 0 deletions.
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/target/
!.mvn/wrapper/maven-wrapper.jar

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
130 changes: 130 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?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>

<groupId>com.antkorwin</groupId>
<artifactId>spring-test-mongo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-test-mongo</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<junit.vintage.version>5.1.1</junit.vintage.version>
<junit-jupiter.version>5.2.0</junit-jupiter.version>
<junit-platform.version>1.2.0</junit-platform.version>
<jackson.version>2.9.7</jackson.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>


<!-- Junit 5 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit-jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
<version>${junit-platform.version}</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>${junit-platform.version}</version>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.vintage.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit-jupiter.version}</version>
</dependency>
<!-- Junit 5 -->


<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.4.3</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>

<dependency>
<groupId>com.antkorwin</groupId>
<artifactId>common-utils</artifactId>
<version>1.2</version>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
</build>


</project>
111 changes: 111 additions & 0 deletions src/main/java/com/antkorwin/springtestmongo/MongoPopulator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.antkorwin.springtestmongo;

import com.antkorwin.commonutils.exceptions.InternalException;
import com.antkorwin.commonutils.validation.Guard;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

import static com.antkorwin.springtestmongo.errorinfo.RiderErrorInfo.*;


/**
* Created by Korovin A. on 21.01.2018.
* <p>
* MongoDB data populate utility
*
* @author Korovin Anatoliy
*/
public class MongoPopulator {

private static ObjectMapper objectMapper = new ObjectMapper();

private static Logger log = LoggerFactory.getLogger(MongoPopulator.class);

/**
* Populate DataSet from file to mongo
*
* @param mongoTemplate connection to mongo database
* @param dataSetFileName path to the json dataset
*/
public static void populate(MongoTemplate mongoTemplate, String dataSetFileName) {

Guard.check(dataSetFileName != null, InternalException.class, DATASET_FILE_NAME_IS_MANDATORY);
Guard.check(mongoTemplate != null, InternalException.class, MONGO_TEMPLATE_IS_MANDATORY);

final InputStream inputStream = MongoPopulator.class.getClass().getResourceAsStream(dataSetFileName);
Guard.check(inputStream != null, InternalException.class, FILE_NOT_FOUND);

try {
// read dataset from file:
String stringDataSet = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

// convert to Map of Object:
Map<String, Object> objectMap =
objectMapper.readValue(stringDataSet,
new TypeReference<Map<String, Object>>() {
});

// populate data in db:
internalPopulate(mongoTemplate, objectMap);

} catch (JsonMappingException | JsonParseException e) {
e.printStackTrace();
throw new InternalException(DATASET_PARSING_ERROR, e);
} catch (IOException e) {
e.printStackTrace();
throw new InternalException(READ_DATASETS_FILE_ERROR, e);
}
}


private static void internalPopulate(MongoTemplate mongoTemplate, Map<String, Object> objectMap) {
objectMap.forEach((key, value) -> {
Guard.check(value instanceof List, InternalException.class, DATASET_FORMAT_ERROR);
populateOneDocumentCollection(mongoTemplate, getDocumentClassByName(key), (List) value);
});
}


private static void populateOneDocumentCollection(MongoTemplate mongoTemplate, Class<?> documentClassType,
List<?> recordCollection) {
recordCollection.forEach(document -> {
try {
// TODO: unfortunately I don`t find way without twice transformation (Object->String->documentClass)
// it would be nice to find an option to parsing object without obtain target class type
String stringDocument = objectMapper.writeValueAsString(document);
Object r = objectMapper.readValue(stringDocument, documentClassType);
mongoTemplate.save(r);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalException(DOCUMENT_RECORD_PARSING_ERROR);
} catch (IOException e) {
e.printStackTrace();
throw new InternalException(DATASET_PARSING_ERROR);
}
});
}


private static Class<?> getDocumentClassByName(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
log.error("Unresolved document collection class reference: {}", className, e);
throw new InternalException(UNRESOLVED_DOCUMENT_COLLECTION_CLASS_TYPE, e);
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.antkorwin.springtestmongo.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Created by Korovin A. on 21.01.2018.
*
* This annotation used to specify the path
* of a data-set file and other options.
*
* @author Korovin Anatoliy
* @version 1.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MongoDataSet {

/**
* Path to file with dataSet for populating
*/
String value() default "";

/**
* Clean MongoDB data before run test
*/
boolean cleanBefore() default false;

/**
* Clean MongoDB data after run test
*/
boolean cleanAfter() default false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.antkorwin.springtestmongo.errorinfo;

import com.antkorwin.commonutils.validation.ErrorInfo;

/**
* Created by Korovin A. on 21.01.2018.
*
* MongoDbRider error details
*
* @author Korovin Anatoliy
* @version 1.0
*/
public enum RiderErrorInfo implements ErrorInfo {

READ_DATASETS_FILE_ERROR("Error while reading file with a DataSet."),
FILE_NOT_FOUND("Not found a DataSet file."),
DATASET_FILE_NAME_IS_MANDATORY("DataSet's file name is a mandatory argument."),
MONGO_TEMPLATE_IS_MANDATORY("MongoTemplate is a mandatory argument."),
UNRESOLVED_DOCUMENT_COLLECTION_CLASS_TYPE("Unresolved document collection class reference from the DataSet."),
DOCUMENT_RECORD_PARSING_ERROR("Error while parsing the document record in the collection."),
DATASET_PARSING_ERROR("Error while parsing the file with a dataset."),
DATASET_FORMAT_ERROR("Wrong dataset's format.");

private final String message;
private final int base = 1000;


RiderErrorInfo(String msg) {
this.message = msg;
}

@Override
public String getMessage() {
return message;
}

@Override
public Integer getCode() {
return base + ordinal();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.antkorwin.springtestmongo.junit4;

import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import org.testcontainers.containers.GenericContainer;

/**
* Created by Korovin A. on 19.01.2018.
* <p>
* Running all context configurations include MongoDB test container.
* Also initializing the MongoDbRiderRule to write an integration
* test case witch using the MongoDataSet annotation.
*
* @author Korovin Anatoliy
* @version 1.0
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public abstract class BaseMongoIT {

private static final Integer MONGO_PORT = 27017;

static {
System.out.println("Start MongoDb testcontainers extension...\n");

GenericContainer mongo = new GenericContainer("mongo:latest")
.withExposedPorts(MONGO_PORT);

mongo.start();

System.setProperty("spring.data.mongodb.host", mongo.getContainerIpAddress());
System.setProperty("spring.data.mongodb.port", mongo.getMappedPort(MONGO_PORT).toString());
}

@Autowired
protected MongoTemplate mongoTemplate;

@Rule
public MongoDbRiderRule mongoDbRiderRule = new MongoDbRiderRule(() -> mongoTemplate);
}
Loading

0 comments on commit a9205b1

Please sign in to comment.