Add template for assignment 1

This commit is contained in:
Philipp Raith
2021-03-10 08:14:26 +01:00
parent 4147115ba2
commit 720d6c193f
103 changed files with 6357 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
<?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>
<groupId>at.ac.tuwien.infosys.dst</groupId>
<artifactId>dst</artifactId>
<version>2021.1</version>
<relativePath>..</relativePath>
</parent>
<artifactId>ass1-doc</artifactId>
<packaging>jar</packaging>
<name>DST :: Assignment 1 :: Document DB</name>
<dependencies>
<dependency>
<groupId>at.ac.tuwien.infosys.dst</groupId>
<artifactId>ass1-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,15 @@
package dst.ass1.doc;
import org.bson.Document;
import java.util.List;
public interface IDocumentQuery {
Document findLocationById(Long locationId);
List<Long> findIdsByNameAndRadius(String name, double longitude, double latitude, double radius);
List<Document> getDocumentStatistics();
}
@@ -0,0 +1,11 @@
package dst.ass1.doc;
import dst.ass1.jpa.model.ILocation;
import java.util.Map;
public interface IDocumentRepository {
void insert(ILocation location, Map<String, Object> locationProperties);
}
@@ -0,0 +1,11 @@
package dst.ass1.doc;
import com.mongodb.client.MongoDatabase;
public interface IDocumentServiceFactory {
IDocumentQuery createDocumentQuery(MongoDatabase db);
IDocumentRepository createDocumentRepository();
}
@@ -0,0 +1,21 @@
package dst.ass1.doc.impl;
import com.mongodb.client.MongoDatabase;
import dst.ass1.doc.IDocumentQuery;
import dst.ass1.doc.IDocumentRepository;
import dst.ass1.doc.IDocumentServiceFactory;
public class DocumentServiceFactory implements IDocumentServiceFactory {
@Override
public IDocumentQuery createDocumentQuery(MongoDatabase db) {
// TODO
return null;
}
@Override
public IDocumentRepository createDocumentRepository() {
// TODO
return null;
}
}
@@ -0,0 +1,45 @@
package dst.ass1.doc;
import com.mongodb.client.MongoDatabase;
import dst.ass1.jpa.util.Constants;
import org.bson.Document;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.Scanner;
public class DocumentTestData implements IDocumentTestData {
private String documentResource;
public DocumentTestData() {
this("documents.json");
}
public DocumentTestData(String documentResource) {
this.documentResource = documentResource;
}
@SuppressWarnings("unchecked")
@Override
public void insertTestData(MongoDatabase db) throws IOException {
URL resource = Objects.requireNonNull(getDocumentsResource());
String testDataJson = readFully(resource);
List<Document> documents = Document.parse(testDataJson).get("documents", List.class);
db.getCollection(Constants.COLL_LOCATION_DATA).insertMany(documents);
}
private URL getDocumentsResource() {
return getClass().getClassLoader().getResource(documentResource);
}
private String readFully(URL resource) throws IOException {
try (Scanner scanner = new Scanner(resource.openStream())) {
return scanner.useDelimiter("\\Z").next();
}
}
}
@@ -0,0 +1,56 @@
package dst.ass1.doc;
import de.flapdoodle.embed.mongo.config.MongodConfig;
import de.flapdoodle.embed.mongo.config.Net;
import de.flapdoodle.embed.mongo.distribution.IFeatureAwareVersion;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.mongo.tests.MongodForTestsFactory;
import org.junit.rules.ExternalResource;
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
/**
* JUnit rule that creates an in-memory instance of MongoDB using the flapdoodle Embedded MongoDB.
*/
public class EmbeddedMongo extends ExternalResource {
private MongodForTestsFactory mongod;
@Override
protected void before() throws Throwable {
requirePort();
mongod = new MongodFactory(); // starts process in constructor
}
@Override
protected void after() {
if (mongod != null) {
mongod.shutdown();
}
}
private void requirePort() throws IOException, IllegalStateException {
try (ServerSocket ignore = new ServerSocket(27017)) {
// ignore
} catch (BindException e) {
throw new IllegalStateException("Could not bind port 27017 which is necessary to run the MongoDB tests", e);
}
}
public static class MongodFactory extends MongodForTestsFactory {
public MongodFactory() throws IOException {
super(Version.Main.V3_5);
}
@Override
protected MongodConfig newMongodConfig(IFeatureAwareVersion version) throws IOException {
return MongodConfig.builder()
.net(new Net(27017, false))
.version(version)
.build();
}
}
}
@@ -0,0 +1,18 @@
package dst.ass1.doc;
import com.mongodb.client.MongoDatabase;
// DO NOT MODIFY THIS CLASS.
/**
* The IDocumentTestData interface works like the ITestData as introduced in ass1-jpa only for the {@link MongoService}.
*/
public interface IDocumentTestData {
/**
* Inserts the data into the given MongoDatabase instance.
*
* @param db the mongo database instance
* @throws Exception if the insertion failed for some reason
*/
void insertTestData(MongoDatabase db) throws Exception;
}
@@ -0,0 +1,41 @@
package dst.ass1.doc;
import dst.ass1.jpa.model.ILocation;
public class MockLocation implements ILocation {
private Long id;
private String name;
private Long LocationId;
@Override
public Long getId() {
return id;
}
@Override
public void setId(Long id) {
this.id = id;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public Long getLocationId() {
return LocationId;
}
@Override
public void setLocationId(Long locationId) {
LocationId = locationId;
}
}
@@ -0,0 +1,124 @@
package dst.ass1.doc;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import dst.ass1.doc.impl.DocumentServiceFactory;
import dst.ass1.jpa.util.Constants;
import org.bson.Document;
import org.junit.rules.ExternalResource;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
// DO NOT MODIFY THIS CLASS.
/**
* The MongoService class is used as a JUnit rule, that fulfills the same tasks as the ORMService in ass1-jpa, and works
* very similarly.
*/
public class MongoService extends ExternalResource {
private IDocumentTestData testData;
private boolean insertTestData;
private boolean clearTestData;
private MongoClient mongoClient;
private MongoDatabase mongoDatabase;
private IDocumentServiceFactory documentServiceFactory;
private IDocumentRepository documentRepository;
private IDocumentQuery documentQuery;
public MongoService() {
this(null, false, true);
}
public MongoService(IDocumentTestData testData) {
this(testData, true, true);
}
public MongoService(IDocumentTestData testData, boolean insertTestData, boolean clearTestData) {
this.testData = testData;
this.insertTestData = insertTestData;
this.clearTestData = clearTestData;
}
public static Stream<Document> stream(MongoCollection<Document> collection) {
return StreamSupport.stream(collection.find().spliterator(), false);
}
public static <T> Map<T, Document> idMap(MongoCollection<Document> collection, Function<Document, T> idFunction) {
return stream(collection).collect(Collectors.toMap(idFunction, Function.identity()));
}
public MongoClient getMongoClient() {
return mongoClient;
}
public MongoDatabase getMongoDatabase() {
return mongoDatabase;
}
public IDocumentServiceFactory getDocumentServiceFactory() {
return documentServiceFactory;
}
public IDocumentRepository getDocumentRepository() {
return documentRepository;
}
public IDocumentQuery getDocumentQuery() {
return documentQuery;
}
@Override
protected void before() throws Throwable {
setUpMongo();
if (insertTestData && testData != null) {
insertData(testData);
}
}
@Override
protected void after() {
try {
if (clearTestData) {
clearData();
}
} finally {
tearDownMongo();
}
}
private void setUpMongo() {
mongoClient = new MongoClient("127.0.0.1");
mongoDatabase = mongoClient.getDatabase(Constants.MONGO_DB_NAME);
documentServiceFactory = new DocumentServiceFactory();
documentRepository = documentServiceFactory.createDocumentRepository();
if (documentRepository == null) {
throw new IllegalStateException("DocumentRepository returned from factory is null");
}
documentQuery = documentServiceFactory.createDocumentQuery(mongoDatabase);
}
private void tearDownMongo() {
mongoClient.close();
}
private void insertData(IDocumentTestData testData) throws Exception {
testData.insertTestData(getMongoDatabase());
}
private void clearData() {
getMongoDatabase().drop();
}
}
@@ -0,0 +1,128 @@
package dst.ass1.doc.tests;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import dst.ass1.doc.EmbeddedMongo;
import dst.ass1.doc.IDocumentRepository;
import dst.ass1.doc.MockLocation;
import dst.ass1.doc.MongoService;
import dst.ass1.jpa.util.Constants;
import org.bson.Document;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.*;
public class Ass1_4_1Test {
public static final String LOCATION_NAME_1 = "testName1";
public static final String LOCATION_NAME_2 = "testName2";
public static final Long LOCATION_ID_1 = 1L;
public static final Long LOCATION_ID_2 = 2L;
public static final Double GEO_1_1 = 16.3699;
public static final Double GEO_1_2 = 48.199;
public static final Double GEO_2_1 = 16.368528;
public static final Double GEO_2_2 = 48.200939;
@ClassRule
public static EmbeddedMongo embeddedMongo = new EmbeddedMongo();
@Rule
public MongoService mongo = new MongoService();
private MockLocation l1;
private MockLocation l2;
private Map<String, Object> l1Properties;
private Map<String, Object> l2Properties;
private Map<String, Object> geo1;
private Map<String, Object> geo2;
@Before
public void setUp() {
l1 = new MockLocation();
l1.setName(LOCATION_NAME_1);
l1.setLocationId(LOCATION_ID_1);
l2 = new MockLocation();
l2.setName(LOCATION_NAME_2);
l2.setLocationId(LOCATION_ID_2);
l1Properties = new HashMap<>();
geo1 = new HashMap<>();
geo1.put("type", "Point");
geo1.put("coordinates", Arrays.asList(GEO_1_1, GEO_1_2));
l1Properties.put("type", "place");
l1Properties.put("geo", geo1);
l1Properties.put("1337", "7331");
l1Properties.put("Foo", "Bar");
l1Properties.put("Complex", Arrays.asList(1, 2, 3, 5, 8));
l2Properties = new HashMap<>();
geo2 = new HashMap<>();
geo2.put("type", "Point");
geo2.put("coordinates", Arrays.asList(GEO_2_1, GEO_2_2));
l2Properties.put("type", "place");
l2Properties.put("geo", geo2);
l2Properties.put("123456", "654321");
l2Properties.put("F00", "B@r");
l2Properties.put("Complex2", Arrays.asList(4, 6, 7, 9));
}
@Test
public void insert_insertsDocumentsCorrectly() throws Exception {
IDocumentRepository documentRepository = mongo.getDocumentRepository();
MongoDatabase mongoDatabase = mongo.getMongoDatabase();
documentRepository.insert(l1, l1Properties);
documentRepository.insert(l2, l2Properties);
MongoCollection<Document> collection = mongoDatabase.getCollection(Constants.COLL_LOCATION_DATA);
Map<Long, Document> map = MongoService.idMap(collection, d -> d.getLong(Constants.I_LOCATION));
assertNotNull(map);
assertEquals(2, map.size());
Document document1 = map.get(1L);
assertEquals(LOCATION_ID_1, document1.get(Constants.I_LOCATION));
assertEquals(LOCATION_NAME_1, document1.get(Constants.M_LOCATION_NAME));
assertEquals("7331", document1.get("1337"));
assertEquals("Bar", document1.get("Foo"));
assertEquals(Arrays.asList(1, 2, 3, 5, 8), document1.get("Complex"));
assertEquals("place", document1.get("type"));
Map<String, Object> geo1Retrieved = document1.get("geo", new HashMap<>());
assertEquals(2, geo1Retrieved.size());
assertEquals("Point", geo1Retrieved.get("type"));
List<Double> coordinates1 = (List<Double>) geo1Retrieved.get("coordinates");
assertEquals(2, coordinates1.size());
assertThat(coordinates1, hasItems(GEO_1_1, GEO_1_2));
Document document2 = map.get(2L);
assertEquals(LOCATION_ID_2, document2.get(Constants.I_LOCATION));
assertEquals(LOCATION_NAME_2, document2.get(Constants.M_LOCATION_NAME));
assertEquals("654321", document2.get("123456"));
assertEquals("B@r", document2.get("F00"));
assertEquals(Arrays.asList(4, 6, 7, 9), document2.get("Complex2"));
assertEquals("place", document2.get("type"));
Map<String, Object> geo2Retrieved = document2.get("geo", new HashMap<>());
assertEquals(2, geo2Retrieved.size());
assertEquals("Point", geo2Retrieved.get("type"));
List<Double> coordinates2 = (List<Double>) geo2Retrieved.get("coordinates");
assertEquals(2, coordinates2.size());
assertThat(coordinates2, hasItems(GEO_2_1, GEO_2_2));
}
}
@@ -0,0 +1,53 @@
package dst.ass1.doc.tests;
import dst.ass1.doc.DocumentTestData;
import dst.ass1.doc.EmbeddedMongo;
import dst.ass1.doc.IDocumentQuery;
import dst.ass1.doc.MongoService;
import dst.ass1.jpa.util.Constants;
import org.bson.Document;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.*;
public class Ass1_4_2aTest {
@ClassRule
public static EmbeddedMongo embeddedMongo = new EmbeddedMongo();
@Rule
public MongoService mongo = new MongoService(new DocumentTestData());
@SuppressWarnings("unchecked")
@Test
public void findByLocationId_returnsCorrectDocument() {
IDocumentQuery documentQuery = mongo.getDocumentQuery();
Document location = documentQuery.findLocationById(2L);
assertNotNull(location);
assertEquals(2L, (long) location.getLong(Constants.I_LOCATION));
assertEquals("McDonald's", location.getString(Constants.M_LOCATION_NAME));
assertEquals("place", location.getString("type"));
assertEquals("Restaurant", location.getString("category"));
Document geo = location.get("geo", Document.class);
assertNotNull(geo);
List<Double> coordinates = geo.getList("coordinates", Double.class);
assertNotNull(coordinates);
assertEquals(2, coordinates.size());
assertEquals("Point", geo.getString("type"));
assertEquals(16.368528, coordinates.get(0), 0.0);
assertEquals(48.200939, coordinates.get(1), 0.0);
}
@Test
public void findByLocationId_withInvalidId_returnsNull() throws Exception {
Document material = mongo.getDocumentQuery().findLocationById(1337L);
assertNull(material);
}
}
@@ -0,0 +1,43 @@
package dst.ass1.doc.tests;
import dst.ass1.doc.DocumentTestData;
import dst.ass1.doc.EmbeddedMongo;
import dst.ass1.doc.MongoService;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import java.util.List;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.*;
public class Ass1_4_2bTest {
@ClassRule
public static EmbeddedMongo embeddedMongo = new EmbeddedMongo();
@Rule
public MongoService mongo = new MongoService(new DocumentTestData());
@Test
public void findIdsByNameAndRadius_returnsCorrectLocationIds() throws Exception {
List<Long> locationIds = mongo.getDocumentQuery().findIdsByNameAndRadius("McD", 16.367873, 48.198763, 1000);
assertFalse(locationIds.isEmpty());
assertThat(locationIds, hasItems(2L, 3L, 4L));
}
@Test
public void findIdsByType_withNonExistingType_returnsNoLocationIds() throws Exception {
List<Long> locationIds = mongo.getDocumentQuery().findIdsByNameAndRadius("McD", 16.367873, 48.198763, 5);
assertNotNull(locationIds);
assertTrue(locationIds.isEmpty());
locationIds = mongo.getDocumentQuery().findIdsByNameAndRadius("NONEXISTING", 16.367873, 48.198763, 2000);
assertNotNull(locationIds);
assertTrue(locationIds.isEmpty());
}
}
@@ -0,0 +1,39 @@
package dst.ass1.doc.tests;
import dst.ass1.doc.EmbeddedMongo;
import dst.ass1.doc.MongoService;
import dst.ass1.jpa.util.Constants;
import org.bson.Document;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import java.util.List;
import java.util.stream.StreamSupport;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class Ass1_4_3_01Test {
@ClassRule
public static EmbeddedMongo embeddedMongo = new EmbeddedMongo();
@Rule
public MongoService mongo = new MongoService(db -> {
boolean exists = StreamSupport.stream(db.listCollectionNames().spliterator(), false)
.anyMatch(Constants.COLL_LOCATION_DATA::equalsIgnoreCase);
if (!exists) {
db.createCollection(Constants.COLL_LOCATION_DATA); // make sure the empty collection exists
}
});
@Test
public void getDocumentStatistics_withEmptyData_returnsEmptyStatistics() throws Exception {
List<Document> documentStatistics = mongo.getDocumentQuery().getDocumentStatistics();
assertNotNull(documentStatistics);
assertTrue(documentStatistics.isEmpty());
}
}
@@ -0,0 +1,46 @@
package dst.ass1.doc.tests;
import dst.ass1.doc.DocumentTestData;
import dst.ass1.doc.EmbeddedMongo;
import dst.ass1.doc.MongoService;
import org.bson.Document;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.*;
public class Ass1_4_3_02Test {
@ClassRule
public static EmbeddedMongo embeddedMongo = new EmbeddedMongo();
@Rule
public MongoService mongo = new MongoService(new DocumentTestData());
@Test
public void getDocumentStatistics_returnsCorrectStatistics() throws Exception {
List<Document> documentStatistics = mongo.getDocumentQuery().getDocumentStatistics();
assertNotNull(documentStatistics);
assertEquals(3, documentStatistics.size());
List<String> types = documentStatistics.stream().map(d -> d.getString("_id")).collect(Collectors.toList());
assertThat("expected three aggregation keys", types, hasItems("Restaurant", "Park", "University"));
Map<String, Double> dsMap = documentStatistics.stream().collect(Collectors.toMap(
d -> d.getString("_id"),
d -> d.getDouble("value"))
);
assertEquals(4.0d, dsMap.get("Restaurant"), 0);
assertEquals(1.0d, dsMap.get("Park"), 0);
assertEquals(7.0d, dsMap.get("University"), 0);
}
}
@@ -0,0 +1,16 @@
package dst.ass1.doc.tests;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses( {
Ass1_4_1Test.class,
Ass1_4_2aTest.class,
Ass1_4_2bTest.class,
Ass1_4_3_01Test.class,
Ass1_4_3_02Test.class
})
public class Ass1_4_Suite {
}
+184
View File
@@ -0,0 +1,184 @@
{
"documents": [
{
"location_id": NumberLong(1),
"type": "place",
"name": "TU Wien",
"geo": {
"type": "Point",
"coordinates": [
16.3699,
48.199
]
},
"category": "University"
},
{
"location_id": NumberLong(2),
"type": "place",
"name": "McDonald's",
"geo": {
"type": "Point",
"coordinates": [
16.368528,
48.200939
]
},
"category": "Restaurant"
},
{
"location_id": NumberLong(3),
"type": "place",
"name": "McDonald's",
"geo": {
"type": "Point",
"coordinates": [
16.374138,
48.201085
]
},
"category": "Restaurant"
},
{
"location_id": NumberLong(4),
"type": "place",
"name": "McDonald's",
"geo": {
"type": "Point",
"coordinates": [
16.371674,
48.205241
]
},
"category": "Restaurant"
},
{
"location_id": NumberLong(5),
"type": "place",
"name": "McDonald's",
"geo": {
"type": "Point",
"coordinates": [
16.380754,
48.219325
]
},
"category": "Restaurant"
},
{
"location_id": NumberLong(6),
"type": "address",
"name": "Zirkusgasse 1",
"geo": {
"type": "Point",
"coordinates": [
16.384230,
48.216310
]
}
},
{
"location_id": NumberLong(7),
"type": "address",
"name": "Handelskai 9",
"geo": {
"type": "Point",
"coordinates": [
16.406082,
48.225571
]
}
},
{
"location_id": NumberLong(8),
"type": "place",
"name": "Cairngorms National Park",
"geo": {
"type": "Point",
"coordinates": [
-3.562790,
57.046944
]
},
"category": "Park"
},
{
"location_id": NumberLong(9),
"type": "place",
"name": "Distributed Systems Group",
"geo": {
"type": "Point",
"coordinates": [
16.371425,
48.197742
]
},
"category": "University"
},
{
"location_id": NumberLong(10),
"type": "place",
"name": "Computer Vision Lab",
"geo": {
"type": "Point",
"coordinates": [
16.369572,
48.195244
]
},
"category": "University"
},
{
"location_id": NumberLong(11),
"type": "place",
"name": "Uni Wien",
"geo": {
"type": "Point",
"coordinates": [
16.360372,
48.213069
]
},
"category": "University"
},
{
"location_id": NumberLong(12),
"type": "place",
"name": "BOKU Wien",
"geo": {
"type": "Point",
"coordinates": [
16.337443,
48.236530
]
},
"category": "University"
},
{
"location_id": NumberLong(13),
"type": "place",
"name": "WU Wien",
"geo": {
"type": "Point",
"coordinates": [
16.408456,
48.213561
]
},
"category": "University"
},
{
"location_id": NumberLong(14),
"type": "place",
"name": "Audimax TU Wien",
"geo": {
"type": "Point",
"coordinates": [
16.363949,
48.200822
]
},
"category": "University"
}
]
}
+17
View File
@@ -0,0 +1,17 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - %highlight(%5p) [%12.12thread] %cyan(%-40.40logger{39}): %m%n</pattern>
</encoder>
</appender>
<logger name="org.mongodb.driver" level="WARN"/>
<logger name="de.flapdoodle.embed" level="WARN"/>
<root level="${log.level:-INFO}">
<appender-ref ref="STDOUT"/>
</root>
</configuration>