Skip to content

Commit

Permalink
Merge pull request #4 from antkorwin/feature/expected-data-set
Browse files Browse the repository at this point in the history
Add ExpectedDataSet annotation
  • Loading branch information
antkorwin authored Dec 13, 2018
2 parents 8998467 + 63d2f0b commit 963ad67
Show file tree
Hide file tree
Showing 36 changed files with 1,945 additions and 89 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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;

/**
* You can use this annotation in tests
* to check a state of the mongodb after the test execution.
*
* After test execution, all document collections will check
* to match to expected data set in the selected file.
*
* @author Korovin Anatoliy
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExpectedMongoDataSet {

/**
* Path to the file with an expected data set (after test execution)
*
* @return path to file with an expected data set
*/
String value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
*
* @author Korovin Anatoliy
*/
interface DataSet {
public interface DataSet {

/**
* Read the data set from some kind of source
*
* @return map with the data set,
* map looks like this:
* "org.package....FirstDocument" : [FirstDocument doc1, FirstDocument doc2, FirstDocument doc3],
* "org.package....SecondDocument" : [SecondDocument Doc1, SecondDocument Doc2, SecondDocument Doc3]
* "org.package....FirstDocument" : [{"id":"1", "field":"aaa"}, {"id":"2", "field":"bbb"}],
* "org.package....SecondDocument" : [{"id":"1", "value":"123"}, {"id":"2", "value":"456"}]
*/
Map<String, List<?>> read();
Map<String, List<Map<String, Object>>> read();
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ class JsonImport implements DataSet {
}

@Override
public Map<String, List<?>> read() {
public Map<String, List<Map<String, Object>>> read() {

String content = text.read();
try {
return objectMapper.readValue(content, new TypeReference<Map<String, List<?>>>() {
});
return objectMapper.readValue(content,
new TypeReference<Map<String, List<Map<String, Object>>>>() {});
} catch (IOException e) {
e.printStackTrace();
throw new InternalException(JSON_PARSING_ERROR, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import com.antkorwin.commonutils.exceptions.InternalException;
import com.antkorwin.commonutils.validation.Guard;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.antkorwin.springtestmongo.errorinfo.MongoDbErrorInfo.MONGO_TEMPLATE_IS_MANDATORY;

Expand All @@ -20,15 +22,17 @@
class MongoDataExport implements DataSet {

private final MongoTemplate mongoTemplate;
private final ObjectMapper objectMapper;

MongoDataExport(MongoTemplate mongoTemplate) {
Guard.check(mongoTemplate != null, InternalException.class, MONGO_TEMPLATE_IS_MANDATORY);
this.mongoTemplate = mongoTemplate;
this.objectMapper = new ObjectMapper();
}

@Override
public Map<String, List<?>> read() {
Map<String, List<?>> map = new HashMap<>();
public Map<String, List<Map<String, Object>>> read() {
Map<String, List<Map<String, Object>>> map = new HashMap<>();

for (String name : mongoTemplate.getCollectionNames()) {
map.put(getEntityClassName(name), getDataSet(name));
Expand All @@ -37,7 +41,7 @@ public Map<String, List<?>> read() {
return map;
}

private List<?> getDataSet(String collectionName) {
private List<Map<String, Object>> getDataSet(String collectionName) {

Document first = mongoTemplate.getCollection(collectionName)
.find(Document.class)
Expand All @@ -49,9 +53,14 @@ private List<?> getDataSet(String collectionName) {
try {
String className = (String) first.get("_class");
Class<?> aClass = Class.forName(className);
return mongoTemplate.findAll(aClass);
}
catch (ClassNotFoundException e) {

return mongoTemplate.findAll(aClass)
.stream()
.map(e -> objectMapper.convertValue(e, Map.class))
.map(e -> (Map<String,Object>)e)
.collect(Collectors.toList());

} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new InternalException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.antkorwin.commonutils.exceptions.InternalException;
import com.antkorwin.commonutils.validation.Guard;
import com.antkorwin.springtestmongo.internal.expect.MatchDataSets;

import org.springframework.data.mongodb.core.MongoTemplate;

import static com.antkorwin.springtestmongo.errorinfo.MongoDbErrorInfo.MONGO_TEMPLATE_IS_MANDATORY;
Expand Down Expand Up @@ -38,4 +40,16 @@ public void exportTo(String fileName) {
public void importFrom(String fileName) {
new MongoDataImport(mongoTemplate).importFrom(new JsonImport(new ImportFile(fileName)));
}

/**
* Check data in the mongodb,
* try to match data from the DB to loaded from file data set.
*
* @param fileName path to file with an expected data set
*/
public void expect(String fileName) {
DataSet dataSet = new JsonImport(new ImportFile(fileName));
DataSet mongoData = new MongoDataExport(mongoTemplate);
new MatchDataSets(mongoData, dataSet).check();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.antkorwin.springtestmongo.internal.expect;

import com.antkorwin.commonutils.exceptions.InternalException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
* Evaluate the IndexedGraph and
* assert that all patterns applied to any data record.
*/
public class AssertGraph {

private final IndexedGraph indexGraph;
private final ObjectMapper objectMapper = new ObjectMapper();
private boolean failed = false;
private List<String> errors = new ArrayList<>();


public AssertGraph(Graph graph) {
this.indexGraph = new IndexedGraph(graph);
}

public void doAssert() {
validateDataRecords(indexGraph.evaluateDataIndexes());
validatePatterns(indexGraph.evaluatePatternIndexes());
if (failed) {
throw new Error("\nExpectedDataSet of " + indexGraph.getDocumentName() + " \n\n" +
errors.stream().collect(Collectors.joining("\n")) + "\n");
}
}

private void validateDataRecords(Set<Integer> indexes) {
if (indexes.size() != indexGraph.dataCount()) {

String notFoundDataRecords = IntStream.range(0, indexGraph.dataCount())
.boxed()
.filter(i -> !indexes.contains(i))
.map(indexGraph::getDataRecord)
.map(this::mapToString)
.collect(Collectors.joining("\n"));

error("Not expected: \n" + notFoundDataRecords + "\n");
}
}


private void validatePatterns(Set<Integer> indexes) {
if (indexes.size() != indexGraph.patternCount()) {

String notFoundPatterns = IntStream.range(0, indexGraph.patternCount())
.boxed()
.filter(i -> !indexes.contains(i))
.map(indexGraph::getPattern)
.map(this::mapToString)
.collect(Collectors.joining("\n"));

error("Expected but not found: \n" + notFoundPatterns + "\n");
}
}

private String mapToString(Map<String, Object> stringObjectMap) {
try {
return objectMapper.writeValueAsString(stringObjectMap);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalException(e);
}
}

private void error(String message) {
failed = true;
errors.add(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.antkorwin.springtestmongo.internal.expect;

import java.util.Map;

/**
* Created on 09.12.2018.
*
* Graph is a model to calculate the matching of data in
* mongodb and patterns in provided data sets, for one
* type of document collection.
*
* @author Korovin Anatoliy
*/
public interface Graph {

/**
* convert graph to matrix
*
* @return matrix view of graph
*/
boolean[][] calculate();

/**
* @return count of data records from mongodb
*/
int dataCount();

/**
* @return count of patterns from data set file
*/
int patternCount();

/**
* retrieve a data record by the index in graph
*
* @param index position of needed data record
* @return data record from mongodb by the index in graph
*/
Map<String, Object> getDataRecord(int index);

/**
* retrieve the pattern from data set file
*
* @param index position of this pattern in the graph
* @return pattern object from a data set file by the index from the graph
*/
Map<String, Object> getPattern(int index);

/**
* @return name of the mongodb document associated to this graph
*/
String getDocumentName();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.antkorwin.springtestmongo.internal.expect;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* Add in graph indexes of successful matched patterns
* and data records.
*/
public class IndexedGraph implements Graph {

private final Graph graph;
private boolean indexReady;
private Set<Integer> patternIndexes;
private Set<Integer> dataIndexes;

public IndexedGraph(Graph graph) {
this.graph = graph;
this.dataIndexes = new HashSet<>();
this.patternIndexes = new HashSet<>();
}

@Override
public boolean[][] calculate() {
return graph.calculate();
}

@Override
public int dataCount() {
return graph.dataCount();
}

@Override
public int patternCount() {
return graph.patternCount();
}

@Override
public Map<String, Object> getDataRecord(int index) {
return graph.getDataRecord(index);
}

@Override
public Map<String, Object> getPattern(int index) {
return graph.getPattern(index);
}

@Override
public String getDocumentName() {
return graph.getDocumentName();
}

/**
* @return set with indexes of patterns used in this graph
*/
public Set<Integer> evaluatePatternIndexes() {
if (!indexReady) {
evaluateIndexes();
}
return patternIndexes;
}

/**
* @return set with indexes of data records used in this graph
*/
public Set<Integer> evaluateDataIndexes() {
if (!indexReady) {
evaluateIndexes();
}
return dataIndexes;
}

/**
* calculate all used indexes of patterns and
* data records matched for this patterns
*/
private void evaluateIndexes() {

boolean[][] matrix = graph.calculate();

for (int i = 0; i < dataCount(); i++) {
for (int j = 0; j < patternCount(); j++) {
if (matrix[i][j]) {
dataIndexes.add(i);
patternIndexes.add(j);
}
}
}
indexReady = true;
}
}
Loading

0 comments on commit 963ad67

Please sign in to comment.