Skip to content

Commit

Permalink
added ability to connect to external database for unit tests (#632)
Browse files Browse the repository at this point in the history
* modified MongoContext (for tests) to allow connections to external database
  • Loading branch information
asereda-gs authored and elucash committed Jun 2, 2017
1 parent 385da3d commit 0e994a4
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 33 deletions.
6 changes: 3 additions & 3 deletions mongo/src/org/immutables/mongo/repository/Repositories.java
Expand Up @@ -131,9 +131,9 @@ protected final FluentFuture<Integer> doInsert(final ImmutableList<T> documents)
public WriteResult call() {
DBCollection collection = collection();
return collection.insert(
BsonEncoding.wrapInsertObjectList(documents, adapter),
collection.getWriteConcern(),
BsonEncoding.encoder());
BsonEncoding.wrapInsertObjectList(documents, adapter),
collection.getWriteConcern(),
BsonEncoding.encoder());
}
}).lazyTransform(GetN.FUNCTION);
}
Expand Down
Expand Up @@ -249,7 +249,7 @@ public void putAll(Map m) {

@Override
public Object get(String key) {
throw new UnsupportedOperationException();
return cached().get(key);
}

@Override
Expand Down
Expand Up @@ -15,19 +15,22 @@
*/
package org.immutables.mongo.fixture;

import java.util.List;
import org.immutables.mongo.types.Binary;
import org.junit.Rule;
import org.junit.Test;

import java.util.List;

import static org.immutables.check.Checkers.check;
import static org.junit.Assert.fail;

/**
* Basic CRUD operations on the top of repository
*/
public class BasicMongoOperationsTest {

@Rule
public final MongoContext context = new MongoContext();
public final MongoContext context = MongoContext.create();

private final ItemRepository repository = new ItemRepository(context.setup());

Expand Down Expand Up @@ -55,17 +58,71 @@ public void readWrite_single() throws Exception {
check(repository.findById("1").fetchAll().getUnchecked()).hasSize(1);
}

@Test
public void insert() throws Exception {
repository.insert(item()).getUnchecked();
check(repository.findAll().fetchAll().getUnchecked()).hasSize(1);
repository.insert(item().withId("another_id")).getUnchecked();
check(repository.findAll().fetchAll().getUnchecked()).hasSize(2);

try {
repository.insert(item()).getUnchecked();
fail("Didn't fail when duplicate key inserted");
} catch (Exception ignore) {
}

check(repository.findAll().fetchAll().getUnchecked()).hasSize(2);
}

@Test
public void upsert() throws Exception {
repository.upsert(item()).getUnchecked();
check(findItem()).is(item());

repository.upsert(item().withList("foo", "bar")).getUnchecked();
check(findItem().list()).hasAll("foo", "bar");

// add item with different ID. This should be insert (not update)
repository.upsert(item().withId("another_id").withList("aaa")).getUnchecked();
check(repository.findAll().fetchAll().getUnchecked()).hasSize(2);
}

@Test
public void update() throws Exception {
ImmutableItem item = item();
repository.insert(item).getUnchecked();

check(repository.update(repository.criteria().id(item.id()))
.addList("foo").updateAll().getUnchecked())
.is(1);

check(repository.findAll().fetchAll().getUnchecked()).hasSize(1);
check(repository.findAll().fetchAll().getUnchecked().get(0).list()).hasAll("foo");
}

@Test
public void delete() throws Exception {
Item item = ImmutableItem.builder()
.id("1")
.binary(Binary.create(new byte[0]))
.build();
Item item = item();

repository.insert(item).getUnchecked();

check(repository.insert(item).getUnchecked()).is(1);
// expect single entry to be deleted
check(repository.findAll().deleteAll().getUnchecked()).is(1);
// second time no entries remaining
check(repository.findAll().deleteAll().getUnchecked()).is(0);


}

private Item findItem() {
return repository.findById(item().id()).fetchFirst().getUnchecked().get();
}

private static ImmutableItem item() {
return ImmutableItem.builder()
.id("1")
.binary(Binary.create(new byte[] {1}))
.build();
}

}
118 changes: 103 additions & 15 deletions mongo/test/org/immutables/mongo/fixture/MongoContext.java
Expand Up @@ -16,37 +16,92 @@
package org.immutables.mongo.fixture;

import com.github.fakemongo.Fongo;
import com.google.common.base.Preconditions;
import com.google.common.io.Closer;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapterFactory;
import com.mongodb.DB;
import java.util.ServiceLoader;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.WriteConcern;
import org.immutables.mongo.fixture.holder.Holder;
import org.immutables.mongo.fixture.holder.HolderJsonSerializer;
import org.immutables.mongo.fixture.holder.ImmutableHolder;
import org.immutables.mongo.repository.RepositorySetup;
import org.junit.rules.ExternalResource;

import java.io.Closeable;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ServiceLoader;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
* JUnit rule which allows tests to access {@link RepositorySetup} and in-memory database (fongo).
*/
public class MongoContext extends ExternalResource {
* JUnit rule which allows tests to access {@link RepositorySetup} backed by real database (fongo or MongoDB). It
* is a good habit to run tests on different versions of the database. By default Fongo is used.
*
* <p>If you want to connect to external mongo database use system property {@code mongo}.
* With maven it will look something like this:
* <pre>
* {@code $ mvn test -DargLine="-Dmongo=mongodb://localhost"}
* </pre>
*
* @see <a href="https://github.com/fakemongo/fongo">Fongo</a>
**/
public class MongoContext extends ExternalResource implements AutoCloseable {

private static final String DBNAME = "testDB";

private final Closer closer;
private final RepositorySetup setup;
private final DB database;
private final ListeningExecutorService executor;

public MongoContext() {
this.database = new Fongo("FakeMongo").getDB("testDB");
this.executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
private MongoContext(final MongoClient client) {
Preconditions.checkNotNull(client, "client");

// allows to cleanup resources after each test
final Closer closer = Closer.create();

closer.register(new Closeable() {
@Override
public void close() throws IOException {
client.close();
}
});

// drop database if exists (to have a clean test)
if (client.getDatabaseNames().contains(DBNAME)) {
client.getDB(DBNAME).dropDatabase();
}

this.database = client.getDB(DBNAME);

closer.register(new Closeable() {
@Override
public void close() throws IOException {
database.dropDatabase();
}
});

final ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());

closer.register(new Closeable() {
@Override
public void close() throws IOException {
MoreExecutors.shutdownAndAwaitTermination(executor, 100, TimeUnit.MILLISECONDS);
}
});

this.setup = RepositorySetup.builder()
.gson(createGson())
.executor(executor)
.database(database)
.build();
.gson(createGson())
.executor(executor)
.database(database)
.build();

this.closer = closer;
}

public DB database() {
Expand All @@ -71,11 +126,44 @@ private static com.google.gson.Gson createGson() {
return gson.create();
}

public static MongoContext create() {
try {
return new MongoContext(createClient());
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}

/**
* Allows to switch between Fongo and MongoDB based on system parameter {@code mongo}.
*/
private static MongoClient createClient() throws UnknownHostException {
final MongoClient client;

final String uri = System.getProperty("mongo");
if (uri != null) {
client = new MongoClient(new MongoClientURI(uri));
} else {
client = new Fongo("FakeMongo").getMongo();
}

return client;
}

/**
* Cleanup (terminate executor gracefully)
*/
@Override
protected void after() {
MoreExecutors.shutdownAndAwaitTermination(executor, 100, TimeUnit.MILLISECONDS);
try {
close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

@Override
public void close() throws Exception {
closer.close();
}
}
25 changes: 20 additions & 5 deletions mongo/test/org/immutables/mongo/fixture/SimpleReplacerTest.java
Expand Up @@ -15,6 +15,8 @@
*/
package org.immutables.mongo.fixture;

import com.mongodb.CommandFailureException;
import com.mongodb.CommandResult;
import com.mongodb.DuplicateKeyException;
import org.junit.Rule;
import org.junit.Test;
Expand All @@ -24,7 +26,7 @@
public class SimpleReplacerTest {

@Rule
public final MongoContext context = new MongoContext();
public final MongoContext context = MongoContext.create();

private final EntityRepository repository = new EntityRepository(context.setup());

Expand Down Expand Up @@ -88,13 +90,26 @@ public void duplicateKeyException_upsert_SameKey_different_versions() throws Exc

fail("Should fail with " + DuplicateKeyException.class.getName());
} catch (Exception e) {
if (!(e.getCause() instanceof DuplicateKeyException)) {
fail(String.format("Expected failure to be %s got %s",
DuplicateKeyException.class.getName(),
e.getCause().getClass()));
failIfNotDuplicateKeyException(e.getCause());
}
}

private static void failIfNotDuplicateKeyException(Throwable exception) {
// fongo throws directly DuplicateKeyException
if (exception instanceof DuplicateKeyException) return;

// for MongoDB need to check CommandResult
if (exception instanceof CommandFailureException) {
CommandResult result = ((CommandFailureException) exception).getCommandResult();
if (!"DuplicateKey".equals(result.get("codeName"))) {
fail("Not a duplicate key exception for " + result);
}

return;
}

// all others exceptions
fail("Excepted duplicate key exception from " + exception.getCause());
}

@Test
Expand Down
Expand Up @@ -28,7 +28,7 @@
public class SimpleUpdaterTest {

@Rule
public final MongoContext context = new MongoContext();
public final MongoContext context = MongoContext.create();

private final ItemRepository repository = new ItemRepository(context.setup());

Expand Down
Expand Up @@ -25,7 +25,7 @@
public class HolderTest {

@Rule
public final MongoContext context = new MongoContext();
public final MongoContext context = MongoContext.create();

private HolderRepository repository;

Expand Down

0 comments on commit 0e994a4

Please sign in to comment.