package cz.cuni.mff.d3s.been.objectrepository.mongo;
import java.util.*;
import cz.cuni.mff.d3s.been.core.persistence.Entity;
import cz.cuni.mff.d3s.been.persistence.*;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import cz.cuni.mff.d3s.been.cluster.ServiceException;
import cz.cuni.mff.d3s.been.core.persistence.EntityID;
import cz.cuni.mff.d3s.been.util.JSONUtils;
import cz.cuni.mff.d3s.been.util.JsonException;
import cz.cuni.mff.d3s.been.storage.Storage;
import cz.cuni.mff.d3s.been.storage.StorageBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class MongoStorageTest extends Assert {
private static final Logger log = LoggerFactory.getLogger(MongoStorageTest.class);
private static final Random random = new Random();
private final JSONUtils jsonUtils = JSONUtils.newInstance();
public static class DummyEntity extends Entity {
/** A testing string */
private String something;
private Integer someNumber;
DummyEntity() {
this.something = "strange";
this.someNumber = random.nextInt();
}
DummyEntity(int someNumber) {
this.something = "strange";
this.someNumber = someNumber;
}
public String getSomething() {
return something;
}
public Integer getSomeNumber() {
return someNumber;
}
}
public static class ExtendedDummyEntity extends DummyEntity {
private Float someFloat;
public ExtendedDummyEntity() {
this.someFloat = random.nextFloat();
}
public ExtendedDummyEntity(int someNumber, Float someFloat) {
super(someNumber);
this.someFloat = someFloat;
}
public Float getSomeFloat() {
return someFloat;
}
}
class StorageUsingStatement extends Statement {
private final Statement base;
private final MongoServerStandalone mongo;
StorageUsingStatement(Statement base) {
this.base = base;
this.mongo = new MongoServerStandalone();
}
@Override
public void evaluate() throws Throwable {
mongo.start();
connectStorage();
try {
base.evaluate();
} finally {
disconnectStorage();
mongo.stop();
}
}
}
class OffedStorageUsingStatement extends Statement {
private final Statement base;
private final MongoServerStandalone mongo;
OffedStorageUsingStatement(Statement base) {
this.base = base;
this.mongo = new MongoServerStandalone();
}
@Override
public void evaluate() throws Throwable {
mongo.start();
connectStorage();
mongo.stop();
try {
base.evaluate();
} finally {
disconnectStorage();
}
}
}
class StorageAllocatorRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
if (description.getMethodName().endsWith("_dbDown")) {
return new OffedStorageUsingStatement(base);
} else {
return new StorageUsingStatement(base);
}
}
}
private Storage storage;
private final EntityID dummyId;
public MongoStorageTest() {
dummyId = new EntityID();
dummyId.setKind("results");
dummyId.setGroup("test");
}
private void connectStorage() throws ServiceException {
final Properties props = new Properties();
props.setProperty("mongodb.hostname", "localhost:12345");
storage = new MongoStorageBuilder().withProperties(props).build();
storage.start();
}
private void disconnectStorage() {
storage.stop();
storage = null;
}
@Rule
public StorageAllocatorRule storageAllocatorRule = new StorageAllocatorRule();
@Test
public void testLoadDynamically() {
Iterator<StorageBuilder> sl = ServiceLoader.load(StorageBuilder.class).iterator();
assertTrue(sl.hasNext());
assertTrue(sl.next() instanceof MongoStorageBuilder);
}
@Test
public void testSubmitAndRetrieveItems() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new DummyEntity()));
assertEquals(1, storage.query(new QueryBuilder().on(dummyId).with("something", "strange").fetch()).getData().size());
storage.store(dummyId, jsonUtils.serialize(new DummyEntity()));
assertEquals(2, storage.query(new QueryBuilder().on(dummyId).with("something", "strange").fetch()).getData().size());
}
@Test
public void testDeleteSomeResults() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new DummyEntity()));
storage.store(dummyId, jsonUtils.serialize(new DummyEntity()));
assertEquals(2, storage.query(new QueryBuilder().on(dummyId).with("something", "strange").fetch()).getData().size());
assertEquals(QueryStatus.OK, storage.query(new QueryBuilder().on(dummyId).with("something", "strange").delete()).getStatus());
assertEquals(0, storage.query(new QueryBuilder().on(dummyId).with("something", "strange").fetch()).getData().size());
}
@Test
public void testRetrieveEmptyResults() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new DummyEntity()));
assertEquals(0, storage.query(new QueryBuilder().on(dummyId).with("something", "funny").fetch()).getData().size());
}
@Test
public void testRetrieveFromInexistentCollection() {
assertEquals(0, storage.query(new QueryBuilder().on(dummyId).with("something", "strange").fetch()).getData().size());
}
@Test
public void testFetchQuery_dbDown() {
final QueryAnswer answer = storage.query(new QueryBuilder().on(dummyId).fetch());
assertEquals(QueryStatus.PERSISTENCE_DOWN, answer.getStatus());
}
@Test
public void testRegexQuery() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new DummyEntity()));
assertEquals(1, storage.query(new QueryBuilder().on(dummyId).with("something").like("str.nge").fetch()).getData().size());
}
@Test
public void testAboveQuery() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new DummyEntity(1)));
storage.store(dummyId, jsonUtils.serialize(new DummyEntity(2)));
final QueryAnswer answer = storage.query(new QueryBuilder().on(dummyId).with("someNumber").above(2).fetch());
assertEquals(QueryStatus.OK, answer.getStatus());
assertTrue(answer.isCarryingData());
assertEquals(1, answer.getData().size());
}
@Test
public void testBelowQuery() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new DummyEntity(1)));
storage.store(dummyId, jsonUtils.serialize(new DummyEntity(2)));
final QueryAnswer answer = storage.query(new QueryBuilder().on(dummyId).with("someNumber").below(2).fetch());
assertEquals(QueryStatus.OK, answer.getStatus());
assertTrue(answer.isCarryingData());
assertEquals(1, answer.getData().size());
}
@Test
public void testIntervalQuery() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new DummyEntity(1)));
storage.store(dummyId, jsonUtils.serialize(new DummyEntity(2)));
storage.store(dummyId, jsonUtils.serialize(new DummyEntity(3)));
final QueryAnswer answer = storage.query(new QueryBuilder().on(dummyId).with("someNumber").between(1, 3).fetch());
assertEquals(QueryStatus.OK, answer.getStatus());
assertTrue(answer.isCarryingData());
assertEquals(2, answer.getData().size());
}
@Test
public void testEntityCropping() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new ExtendedDummyEntity()));
final QueryAnswer answer = storage.query(new QueryBuilder().on(dummyId).retrieving("something", "someNumber").fetch());
assertEquals(QueryStatus.OK, answer.getStatus());
assertTrue(answer.isCarryingData());
assertEquals(1, answer.getData().size());
jsonUtils.deserialize(answer.getData(), DummyEntity.class);
}
@Test
public void testIncompleteEntityDeserialization() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new ExtendedDummyEntity()));
final QueryAnswer answer = storage.query(new QueryBuilder().on(dummyId).retrieving("something", "someNumber").fetch());
assertEquals(QueryStatus.OK, answer.getStatus());
assertTrue(answer.isCarryingData());
assertEquals(1, answer.getData().size());
jsonUtils.deserialize(answer.getData(), ExtendedDummyEntity.class);
}
@Test
public void testInequalityQuery() throws JsonException, DAOException {
storage.store(dummyId, jsonUtils.serialize(new DummyEntity(4)));
storage.store(dummyId, jsonUtils.serialize(new DummyEntity(5)));
final QueryAnswer answer = storage.query(new QueryBuilder().on(dummyId).with("someNumber").differentFrom(5).fetch());
assertEquals(QueryStatus.OK, answer.getStatus());
assertTrue(answer.isCarryingData());
assertEquals(1, answer.getData().size());
assertEquals(Integer.valueOf(4), jsonUtils.deserialize(answer.getData().iterator().next(), DummyEntity.class).getSomeNumber());
}
}