Package de.bwaldvogel.mongo.backend.memory

Source Code of de.bwaldvogel.mongo.backend.memory.MemoryBackendTest

package de.bwaldvogel.mongo.backend.memory;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
import static org.junit.Assert.assertFalse;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Pattern;

import org.bson.BSONObject;
import org.bson.BasicBSONObject;
import org.bson.types.ObjectId;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.mongodb.BasicDBObject;
import com.mongodb.Bytes;
import com.mongodb.CommandFailureException;
import com.mongodb.CommandResult;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.DuplicateKeyException;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
import com.mongodb.WriteResult;
import com.mongodb.util.JSON;

import de.bwaldvogel.mongo.MongoServer;
import de.bwaldvogel.mongo.backend.Constants;

public class MemoryBackendTest {

    private Mongo client;
    private MongoServer mongoServer;
    private DB db;
    private DBCollection collection;
    private DB admin;

    private CommandResult command(String command) {
        return admin.command(command);
    }

    private BasicDBObject json(String string) {
        string = string.trim();
        if (!string.startsWith("{")) {
            string = "{" + string + "}";
        }
        return (BasicDBObject) JSON.parse(string);
    }

    @Before
    public void setUp() throws Exception {
        mongoServer = new MongoServer(new MemoryBackend());
        InetSocketAddress serverAddress = mongoServer.bind();
        client = new MongoClient(new ServerAddress(serverAddress));
        db = client.getDB("testdb");
        admin = client.getDB("admin");
        collection = db.getCollection("testcoll");
    }

    @After
    public void tearDown() {
        client.close();
        mongoServer.shutdownNow();
    }

    @Test
    public void testUnsupportedModifier() throws Exception {
        collection.insert(json("{}"));
        try {
            collection.update(json("{}"), json("$foo: {}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10147);
            assertThat(e.getMessage()).contains("Invalid modifier specified: $foo");
        }
    }

    @Test
    public void testAnotherUpsert() {
        DBObject query = json("_id:{ f: 'ca', 1: { l: 2 }, t: { t: 11 } }");
        DBObject update = json("'$inc': { 'n.!' : 1 , 'n.a.b:false' : 1}");

        collection.update(query, update, true, false);

        query.putAll((BSONObject) json("n: {!: 1, a: {'b:false': 1}}"));
        assertThat(collection.findOne()).isEqualTo(query);
    }

    @Test
    public void testBasicUpdate() {
        collection.insert(json("_id:1"));
        collection.insert(json("_id:2, b:5"));
        collection.insert(json("_id:3"));
        collection.insert(json("_id:4"));

        collection.update(json("_id:2"), json("_id:2, a:5"));

        assertThat(collection.findOne(json("_id:2"))).isEqualTo(json("_id:2, a:5"));
    }

    @Test
    public void testCollectionStats() throws Exception {
        CommandResult stats = collection.getStats();
        assertThat(stats.ok()).isFalse();
        assertThat(stats.getErrorMessage()).isEqualTo("ns not found");

        collection.insert(json("{}"));
        collection.insert(json("abc: 'foo'"));
        stats = collection.getStats();
        stats.throwOnError();
        assertThat(((Number) stats.get("count")).longValue()).isEqualTo(2);
        assertThat(((Number) stats.get("size")).longValue()).isEqualTo(57);
        assertThat(((Number) stats.get("avgObjSize")).doubleValue()).isEqualTo(28.5);
    }

    @Test
    public void testGetLogStartupWarnings() throws Exception {
        CommandResult startupWarnings = client.getDB("admin").command(json("getLog: 'startupWarnings'"));
        startupWarnings.throwOnError();
        assertThat(startupWarnings.get("totalLinesWritten")).isEqualTo(0);
        assertThat(startupWarnings.get("log")).isEqualTo(Collections.emptyList());
    }

    @Test
    public void testGetLogWhichDoesNotExist() throws Exception {
        CommandResult startupWarnings = client.getDB("admin").command(json("getLog: 'illegal'"));
        try {
            startupWarnings.throwOnError();
            fail("CommandFailureException expected");
        } catch (CommandFailureException e) {
            assertThat(e.getMessage()).contains("no RamLog");
        }
    }

    @Test
    public void testCompoundDateIdUpserts() {
        DBObject query = json("{ _id : { $lt : { n: 'a' , t: 10} , $gte: { n: 'a', t: 1}}}");

        List<BasicDBObject> toUpsert = Arrays.asList(json("_id: {n:'a', t: 1}"), json("_id: {n:'a', t: 2}"),
                json("_id: {n:'a', t: 3}"), json("_id: {n:'a', t: 11}"));

        for (BasicDBObject dbo : toUpsert) {
            collection.update(dbo, ((BasicDBObject) dbo.copy()).append("foo", "bar"), true, false);
        }
        List<DBObject> results = collection.find(query).toArray();
        assertThat(results).containsExactly(json("_id: {n:'a', t:1}, foo:'bar'"), //
                json("_id: {n:'a', t:2}, foo:'bar'"), //
                json("_id: {n:'a', t:3}, foo:'bar'"));
    }

    @Test
    public void testCompoundSort() {
        collection.insert(json("a:1, _id:1"));
        collection.insert(json("a:2, _id:5"));
        collection.insert(json("a:1, _id:2"));
        collection.insert(json("a:2, _id:4"));
        collection.insert(json("a:1, _id:3"));

        @SuppressWarnings("resource")
        DBCursor cursor = collection.find().sort(json("a:1, _id:-1"));
        assertThat(cursor.toArray()).containsExactly(json("a:1, _id:3"), json("a:1, _id:2"), json("a:1, _id:1"),
                json("a:2, _id:5"), json("a:2, _id:4"));
    }

    @Test
    public void testCountCommand() {
        assertThat(collection.count()).isZero();
    }

    @Test
    public void testCountWithQueryCommand() {
        collection.insert(json("n:1"));
        collection.insert(json("n:2"));
        collection.insert(json("n:2"));
        assertThat(collection.count(json("n:2"))).isEqualTo(2);
    }

    @Test
    public void testCreateIndexes() {
        collection.createIndex(new BasicDBObject("n", 1));
        collection.createIndex(new BasicDBObject("b", 1));
        List<DBObject> indexes = db.getCollection("system.indexes").find().toArray();
        assertThat(indexes).containsExactly(

        json("key:{_id:1}").append("ns", collection.getFullName()).append("name", "_id_"),
                json("key:{n:1}").append("ns", collection.getFullName()).append("name", "n_1"),
                json("key:{b:1}").append("ns", collection.getFullName()).append("name", "b_1"));
    }

    @Test
    public void testCurrentOperations() throws Exception {
        DBObject currentOperations = admin.getCollection("$cmd.sys.inprog").findOne();
        assertThat(currentOperations).isNotNull();
        assertThat(currentOperations.get("inprog")).isInstanceOf(List.class);
    }

    @Test
    public void testDatabaseStats() throws Exception {
        CommandResult stats = db.getStats();
        stats.throwOnError();
        assertThat(((Number) stats.get("objects")).longValue()).isEqualTo(1);
        assertThat(((Number) stats.get("collections")).longValue()).isEqualTo(1);
        assertThat(((Number) stats.get("indexes")).longValue()).isEqualTo(0);
        assertThat(((Number) stats.get("dataSize")).longValue()).isEqualTo(37);

        db.getCollection("foo").insert(json("{}"));
        db.getCollection("foo").insert(json("{}"));
        db.getCollection("bar").insert(json("{}"));

        stats = db.getStats();
        stats.throwOnError();

        assertThat(((Number) stats.get("objects")).longValue()).isEqualTo(8);
        assertThat(((Number) stats.get("collections")).longValue()).isEqualTo(3);
        assertThat(((Number) stats.get("indexes")).longValue()).isEqualTo(2);
        assertThat(((Number) stats.get("dataSize")).longValue()).isEqualTo(271);
    }

    @Test
    public void testDeleteDecrementsCount() {
        collection.insert(json("key: 'value'"));
        assertThat(collection.count()).isEqualTo(1);
        collection.remove(json("{}"));
        assertThat(collection.count()).isZero();
    }

    @Test
    public void testDeleteInSystemNamespace() throws Exception {
        try {
            db.getCollection("system.foobar").remove(json("{}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(12050);
            assertThat(e.getMessage()).contains("cannot delete from system namespace");
        }

        try {
            db.getCollection("system.namespaces").remove(json("{}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(12050);
            assertThat(e.getMessage()).contains("cannot delete from system namespace");
        }
    }

    @Test
    public void testUpdateInSystemNamespace() throws Exception {
        try {
            db.getCollection("system.foobar").update(json("{}"), json("{}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10156);
            assertThat(e.getMessage()).contains("cannot update system collection");
        }

        try {
            db.getCollection("system.namespaces").update(json("{}"), json("{}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10156);
            assertThat(e.getMessage()).contains("cannot update system collection");
        }
    }

    @Test
    public void testDistinctQuery() {
        collection.insert(new BasicDBObject("n", 3));
        collection.insert(new BasicDBObject("n", 1));
        collection.insert(new BasicDBObject("n", 2));
        collection.insert(new BasicDBObject("n", 1));
        collection.insert(new BasicDBObject("n", 1));
        assertThat(collection.distinct("n")).containsExactly(1, 2, 3);
        assertThat(collection.distinct("foobar")).isEmpty();
        assertThat(collection.distinct("_id")).hasSize((int) collection.count());
    }

    @Test
    public void testDropCollection() throws Exception {
        collection.insert(json("{}"));
        assertThat(db.getCollectionNames()).contains(collection.getName());
        collection.drop();
        assertThat(db.getCollectionNames()).excludes(collection.getName());
    }

    @Test
    public void testDropCollectionAlsoDropsFromDB() throws Exception {
        collection.insert(json("{}"));
        collection.drop();
        assertThat(collection.count()).isZero();
        assertThat(db.getCollectionNames()).excludes(collection.getName());
    }

    @Test
    public void testDropDatabaseAlsoDropsCollectionData() throws Exception {
        collection.insert(json("{}"));
        db.dropDatabase();
        assertThat(collection.count()).isZero();
    }

    @Test
    public void testDropDatabaseDropsAllData() throws Exception {
        collection.insert(json("{}"));
        DBCollection collection2 = db.getCollection("testcoll2");
        collection2.insert(json("{}"));

        client.dropDatabase(db.getName());
        assertThat(client.getDatabaseNames()).excludes(db.getName());
        assertThat(collection.count()).isZero();
        assertThat(db.getCollectionNames()).excludes(collection.getName(), collection2.getName());
    }

    @Test
    public void testEmbeddedSort() {
        collection.insert(json("_id: 1"));
        collection.insert(json("_id: 2"));
        collection.insert(json("_id: 3"));
        collection.insert(json("_id: 4, counts:{done:1}"));
        collection.insert(json("_id: 5, counts:{done:2}"));

        @SuppressWarnings("resource")
        DBCursor cursor = collection.find(json("c: {$ne:true}")).sort(json("counts.done: -1"));
        assertThat(cursor.toArray()).containsExactly(json("_id: 5, counts:{done:2}"), json("_id: 4, counts:{done:1}"),
                json("_id: 1"), json("_id: 2"), json("_id: 3"));
    }

    @Test
    public void testFindAndModifyCommandEmpty() throws Exception {
        DBObject cmd = new BasicDBObject("findandmodify", collection.getName());
        CommandResult result = db.command(cmd);
        assertThat(result.getErrorMessage()).isEqualTo("need remove or update");
        assertThat(result.ok()).isFalse();
    }

    @Test
    public void testFindAndModifyCommandIllegalOp() throws Exception {
        collection.insert(json("_id: 1"));

        DBObject cmd = new BasicDBObject("findAndModify", collection.getName());
        cmd.put("query", json("_id: 1"));
        cmd.put("update", new BasicDBObject("$inc", json("_id: 1")));

        assertThat(collection.findOne()).isEqualTo(json("_id: 1"));

        CommandResult result = db.command(cmd);
        try {
            result.throwOnError();
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10148);
            assertThat(e.getMessage()).contains("Mod on _id not allowed");
        }
    }

    @Test
    public void testFindAndModifyCommandUpdate() throws Exception {
        collection.insert(json("_id: 1"));

        DBObject cmd = new BasicDBObject("findAndModify", collection.getName());
        cmd.put("query", json("_id: 1"));
        cmd.put("update", json("$inc: {a: 1}"));

        CommandResult result = db.command(cmd);
        assertThat(result.get("lastErrorObject")).isEqualTo(json("updatedExisting: true, n: 1"));

        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: 1"));
        assertThat(result.ok()).isTrue();
    }

    @Test
    public void testFindAndModifyError() throws Exception {
        collection.insert(json("_id: 1, a: 1"));

        try {
            collection.findAndModify(json("_id: 1"), null, null, false, json("$inc: {_id: 1}"), false, false);
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10148);
            assertThat(e.getMessage()).contains("Mod on _id not allowed");
        }
    }

    @Test
    public void testFindAndModifyFields() throws Exception {
        collection.insert(json("_id: 1, a: 1"));
        DBObject result = collection.findAndModify(json("_id: 1"), json("_id: 1"), null, false, json("$inc: {a:1}"),
                true, false);

        assertThat(result).isEqualTo(json("_id: 1"));
    }

    @Test
    public void testFindAndModifyNotFound() throws Exception {
        collection.insert(json("_id: 1, a: 1"));
        DBObject result = collection.findAndModify(json("_id: 2"), null, null, false, new BasicDBObject("$inc",
                json("a: 1")), false, false);

        assertThat(result).isNull();
        assertThat(collection.count()).isEqualTo(1);
    }

    @Test
    public void testFindAndModifyRemove() {
        collection.insert(json("_id: 1, a: 1"));
        DBObject result = collection.findAndModify(json("_id: 1"), null, null, true, null, false, false);

        assertThat(result).isEqualTo(json("_id: 1, a: 1"));
        assertThat(collection.count()).isZero();
    }

    // https://github.com/foursquare/fongo/issues/32
    @Test
    public void testFindAndModifyReturnNew() {
        collection.insert(json("_id: 1, a: 1, b: {c: 1}"));

        DBObject query = json("_id: 1");
        DBObject update = json("$inc: {a: 1, 'b.c': 1}");
        DBObject result = collection.findAndModify(query, null, null, false, update, true, false);

        assertThat(result).isEqualTo(json("_id: 1, a: 2, b: {c: 2}"));
    }

    // https://github.com/foursquare/fongo/issues/32
    @Test
    public void testFindAndModifyReturnOld() {
        collection.insert(json("_id: 1, a: 1, b: {c: 1}"));

        DBObject query = json("_id: 1");
        DBObject update = json("$inc: {a: 1, 'b.c': 1}");
        DBObject result = collection.findAndModify(query, null, null, false, update, false, false);

        assertThat(result).isEqualTo(json("_id: 1, a: 1, b: {c: 1}"));
        assertThat(collection.findOne(query)).isEqualTo(json("_id: 1, a: 2, b: {c: 2}"));
    }

    @Test
    public void testFindAndModifySorted() throws Exception {
        collection.insert(json("_id: 1, a:15"));
        collection.insert(json("_id: 2, a:10"));
        collection.insert(json("_id: 3, a:20"));

        DBObject order = json("a:1");
        DBObject result = collection.findAndModify(json("{}"), null, order, false, json("$inc: {a: 1}"), true, false);
        assertThat(result).isEqualTo(json("_id: 2, a: 11"));

        order = json("a: -1");
        result = collection.findAndModify(json("{}"), null, order, false, json("$inc: {a: 1}"), true, false);
        assertThat(result).isEqualTo(json("_id: 3, a: 21"));

    }

    @Test
    public void testFindAndModifyUpsert() {
        DBObject result = collection.findAndModify(json("_id: 1"), null, null, false, json("$inc: {a:1}"), true, true);

        assertThat(result).isEqualTo(json("_id: 1, a: 1"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: 1"));
    }

    @Test
    public void testFindAndModifyUpsertReturnNewFalse() {
        DBObject result = collection.findAndModify(json("_id: 1"), null, null, false, json("$inc: {a:1}"), false, true);

        assertThat(result).isEqualTo(json("{}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: 1"));
    }

    @Test
    public void testFindAndRemoveFromEmbeddedList() {
        BasicDBObject obj = json("_id: 1, a: [1]");
        collection.insert(obj);
        DBObject result = collection.findAndRemove(json("_id: 1"));
        assertThat(result).isEqualTo(obj);
        assertThat(collection.count()).isZero();
    }

    @Test
    public void testFindOne() {
        collection.insert(json("key: 'value'"));
        collection.insert(json("key: 'value'"));
        DBObject result = collection.findOne();
        assertThat(result).isNotNull();
        assertThat(result.get("_id")).isNotNull();
    }

    @Test
    public void testFindOneById() {
        collection.insert(json("_id: 1"));
        DBObject result = collection.findOne(json("_id: 1"));
        assertThat(result).isEqualTo(json("_id: 1"));
        assertThat(collection.findOne(json("_id: 2"))).isNull();
    }

    @Test
    public void testFindOneIn() {
        collection.insert(json("_id: 1"));
        DBObject result = collection.findOne(json("_id: {$in: [1,2]}"));
        assertThat(result).isEqualTo(json("_id: 1"));
    }

    @Test
    public void testFindWithLimit() {
        collection.insert(json("_id: 1"));
        collection.insert(json("_id: 2"));
        collection.insert(json("_id: 3"));
        collection.insert(json("_id: 4"));

        List<DBObject> actual = collection.find().limit(2).toArray();
        assertThat(actual).containsExactly(json("_id: 1"), json("_id: 2"));

        List<DBObject> actualNegativeLimit = collection.find().limit(-2).toArray();
        assertThat(actualNegativeLimit).isEqualTo(actual);
    }

    @Test
    public void testFindWithPattern() {
        collection.insert(json("_id: 'marta'"));
        collection.insert(json("_id: 'john', foo: 'bar'"));
        collection.insert(json("_id: 'jon', foo: 'ba'"));
        collection.insert(json("_id: 'jo'"));

        assertThat(collection.find(new BasicDBObject("_id", Pattern.compile("mart"))).toArray()).containsExactly(
                json("_id: 'marta'"));

        assertThat(collection.find(new BasicDBObject("foo", Pattern.compile("ba"))).toArray()).containsExactly(
                json("_id: 'john', foo: 'bar'"), json("_id: 'jon', foo: 'ba'"));

        assertThat(collection.find(new BasicDBObject("foo", Pattern.compile("ba$"))).toArray()).containsExactly(
                json("_id: 'jon', foo: 'ba'"));
    }

    @Test
    public void testFindWithQuery() {
        collection.insert(json("name: 'jon'"));
        collection.insert(json("name: 'leo'"));
        collection.insert(json("name: 'neil'"));
        collection.insert(json("name: 'neil'"));

        @SuppressWarnings("resource")
        DBCursor cursor = collection.find(json("name: 'neil'"));
        assertThat(cursor.toArray()).hasSize(2);
    }

    @Test
    public void testFindWithSkipLimit() {
        collection.insert(json("_id: 1"));
        collection.insert(json("_id: 2"));
        collection.insert(json("_id: 3"));
        collection.insert(json("_id: 4"));

        @SuppressWarnings("resource")
        DBCursor cursor = collection.find().limit(2).skip(2);
        assertThat(cursor.toArray()).containsExactly(json("_id: 3"), json("_id: 4"));
    }

    @Test
    public void testFindWithSkipLimitAfterDelete() {
        collection.insert(json("_id: 1"));
        collection.insert(json("_id: 2"));
        collection.insert(json("_id: 3"));
        collection.insert(json("_id: 4"));
        collection.insert(json("_id: 5"));

        collection.remove(json("_id: 1"));
        collection.remove(json("_id: 3"));

        @SuppressWarnings("resource")
        DBCursor cursor = collection.find().limit(2).skip(2);
        assertThat(cursor.toArray()).containsExactly(json("_id: 5"));
    }

    @Test
    public void testFullUpdateWithSameId() throws Exception {
        collection.insert(json("_id: 1"));
        collection.insert(json("_id: 2, b: 5"));
        collection.insert(json("_id: 3"));
        collection.insert(json("_id: 4"));

        collection.update(json("_id: 2, b:5"), json("_id: 2, a:5"));

        assertThat(collection.findOne(json("_id: 2"))).isEqualTo(json("_id: 2, a:5"));
    }

    @Test
    public void testGetCollection() {
        DBCollection collection = db.getCollection("coll");
        db.getCollection("coll").insert(json("{}"));

        assertThat(collection).isNotNull();
        assertThat(db.getCollection("coll")).isSameAs(collection);
        assertThat(db.getCollectionFromString("coll")).isSameAs(collection);
        assertThat(db.getCollectionNames()).contains("coll");
    }

    /**
     * Test that ObjectId is getting generated even if _id is present in
     * DBObject but it's value is null
     */
    @Test
    public void testIdGenerated() throws Exception {
        DBObject toSave = json("{_id: null, name: 'test'}");

        collection.save(toSave);
        DBObject result = collection.findOne(json("name: 'test'"));
        assertThat(result.get(Constants.ID_FIELD)).isInstanceOf(ObjectId.class);
    }

    @Test
    public void testIdInQueryResultsInIndexOrder() {
        collection.insert(json("_id: 4"));
        collection.insert(json("_id: 3"));
        collection.insert(json("_id: 1"));
        collection.insert(json("_id: 2"));

        @SuppressWarnings("resource")
        DBCursor cursor = collection.find(json("_id: {$in: [3,2,1]}"));
        assertThat(cursor.toArray()).containsExactly(json("_id: 1"), json("_id: 2"), json("_id: 3"));
    }

    @Test
    public void testIdNotAllowedToBeUpdated() {
        collection.insert(json("_id: 1"));

        try {
            collection.update(json("_id: 1"), json("_id:2, a:4"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getMessage()).contains(
                    "cannot change _id of a document old:{ \\\"_id\\\" : 1} new:{ \\\"_id\\\" : 2}");
        }

        // test with $set

        try {
            collection.update(json("_id: 1"), new BasicDBObject("$set", json("_id: 2")));
            fail("should throw exception");
        } catch (MongoException e) {
            assertThat(e.getMessage()).contains("Mod on _id not allowed");
        }
    }

    @Test
    public void testIllegalCommand() throws Exception {
        try {
            command("foo").throwOnError();
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getMessage()).contains("no such cmd: foo");
        }

        try {
            client.getDB("bar").command("foo").throwOnError();
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getMessage()).contains("no such cmd: foo");
        }
    }

    @Test
    public void testInsert() throws Exception {
        assertThat(collection.count()).isEqualTo(0);

        for (int i = 0; i < 3; i++) {
            collection.insert(new BasicDBObject("_id", Integer.valueOf(i)));
        }

        assertThat(collection.count()).isEqualTo(3);

        WriteResult result = collection.insert(json("foo: [1,2,3]"));
        assertThat(result.getN()).isZero();
        assertThat(result.isUpdateOfExisting()).isFalse();

        collection.insert(new BasicDBObject("foo", new byte[10]));
        BasicDBObject insertedObject = new BasicDBObject("foo", UUID.randomUUID());
        collection.insert(insertedObject);
        assertThat(collection.findOne(insertedObject)).isEqualTo(insertedObject);
    }

    @Test
    public void testInsertDuplicate() throws Exception {
        assertThat(collection.count()).isEqualTo(0);

        collection.insert(json("_id: 1"));
        assertThat(collection.count()).isEqualTo(1);

        try {
            collection.insert(json("_id: 1"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getMessage()).contains("duplicate key error");
        }

        try {
            collection.insert(new BasicDBObject("_id", Double.valueOf(1.0)));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getMessage()).contains("duplicate key error");
        }

        assertThat(collection.count()).isEqualTo(1);
    }

    @Test(expected = MongoException.class)
    public void testInsertDuplicateThrows() {
        collection.insert(json("_id: 1"));
        collection.insert(json("_id: 1"));
    }

    @Test(expected = MongoException.class)
    public void testInsertDuplicateWithConcernThrows() {
        collection.insert(json("_id: 1"));
        collection.insert(json("_id: 1"), WriteConcern.SAFE);
    }

    @Test
    public void testInsertIncrementsCount() {
        assertThat(collection.count()).isZero();
        collection.insert(json("key: 'value'"));
        assertThat(collection.count()).isEqualTo(1);
    }

    @Test
    public void testInsertQuery() throws Exception {
        assertThat(collection.count()).isEqualTo(0);

        BasicDBObject insertedObject = json("_id: 1");
        insertedObject.put("foo", "bar");
        collection.insert(insertedObject);

        assertThat(collection.findOne(insertedObject)).isEqualTo(insertedObject);
        assertThat(collection.findOne(new BasicDBObject("_id", Long.valueOf(1)))).isEqualTo(insertedObject);
        assertThat(collection.findOne(new BasicDBObject("_id", Double.valueOf(1.0)))).isEqualTo(insertedObject);
        assertThat(collection.findOne(new BasicDBObject("_id", Float.valueOf(1.0001f)))).isNull();
        assertThat(collection.findOne(json("foo: 'bar'"))).isEqualTo(insertedObject);
    }

    @Test
    public void testInsertRemove() throws Exception {
        for (int i = 0; i < 10; i++) {
            collection.insert(json("_id: 1"));
            assertThat(collection.count()).isEqualTo(1);
            collection.remove(json("_id: 1"));
            assertThat(collection.count()).isZero();

            collection.insert(new BasicDBObject("_id", i));
            collection.remove(new BasicDBObject("_id", i));
        }
        assertThat(collection.count()).isZero();
        collection.remove(json("'doesnt exist': 1"));
        assertThat(collection.count()).isZero();
    }

    @Test
    public void testInsertInSystemNamespace() throws Exception {
        try {
            db.getCollection("system.foobar").insert(json("{}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(16459);
            assertThat(e.getMessage()).contains("attempt to insert in system namespace");
        }

        try {
            db.getCollection("system.namespaces").insert(json("{}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(16459);
            assertThat(e.getMessage()).contains("attempt to insert in system namespace");
        }
    }

    @Test
    public void testListDatabaseNames() throws Exception {
        assertThat(client.getDatabaseNames()).isEmpty();
        db.getCollection(collection.getName()).insert(json("{}"));
        assertThat(client.getDatabaseNames()).containsExactly(db.getName());
        client.getDB("bar").getCollection(collection.getName()).insert(json("{}"));
        assertThat(client.getDatabaseNames()).containsExactly("bar", db.getName());
    }

    @Test
    public void testMaxBsonSize() throws Exception {
        int maxBsonObjectSize = client.getMaxBsonObjectSize();
        assertThat(maxBsonObjectSize).isEqualTo(16777216);
    }

    @Test
    public void testQuery() throws Exception {
        DBObject obj = collection.findOne(json("_id: 1"));
        assertThat(obj).isNull();
        assertThat(collection.count()).isEqualTo(0);
    }

    @Test
    public void testQueryAll() throws Exception {
        List<Object> inserted = new ArrayList<Object>();
        for (int i = 0; i < 10; i++) {
            BasicDBObject obj = new BasicDBObject("_id", i);
            collection.insert(obj);
            inserted.add(obj);
        }
        assertThat(collection.count()).isEqualTo(10);

        assertThat(collection.find().toArray()).isEqualTo(inserted);
    }

    @Test
    public void testQueryCount() throws Exception {
        for (int i = 0; i < 100; i++) {
            collection.insert(json("{}"));
        }
        assertThat(collection.count()).isEqualTo(100);

        BasicDBObject obj = json("_id: 1");
        assertThat(collection.find(obj).count()).isEqualTo(0);
        collection.insert(obj);
        assertThat(collection.find(obj).count()).isEqualTo(1);
    }

    @Test
    public void testQueryLimit() throws Exception {
        for (int i = 0; i < 5; i++) {
            collection.insert(json("{}"));
        }
        List<DBObject> objects = collection.find().limit(1).toArray();
        assertThat(objects.size()).isEqualTo(1);

        assertThat(collection.find().limit(-1).toArray()).isEqualTo(objects);
    }

    @Test
    public void testQueryNull() throws Exception {
        BasicDBObject object = json("_id: 1");
        collection.insert(object);
        assertThat(collection.findOne(json("foo: null"))).isEqualTo(object);
    }

    @Test
    @SuppressWarnings("resource")
    public void testQuerySkipLimit() throws Exception {
        for (int i = 0; i < 10; i++) {
            collection.insert(json("{}"));
        }

        DBCursor cursor = collection.find().skip(3);
        assertThat(cursor.itcount()).isEqualTo(7);

        cursor = collection.find().skip(3).limit(5);
        assertThat(cursor.itcount()).isEqualTo(5);
    }

    @Test
    public void testQuerySort() throws Exception {
        Random random = new Random(4711);
        for (int i = 0; i < 10; i++) {
            collection.insert(new BasicDBObject("_id", Double.valueOf(random.nextDouble())));
        }

        List<DBObject> objects = collection.find().sort(json("_id: 1")).toArray();
        double before = Double.MIN_VALUE;
        for (DBObject dbObject : objects) {
            double value = ((Number) dbObject.get("_id")).doubleValue();
            assertThat(value).isGreaterThanOrEqualTo(before);
            before = value;
        }

        // reverse sort
        objects = collection.find().sort(json("_id: -1")).toArray();
        before = Double.MAX_VALUE;
        for (DBObject dbObject : objects) {
            double value = ((Number) dbObject.get("_id")).doubleValue();
            assertThat(value).isLessThanOrEqualTo(before);
            before = value;
        }
    }

    @Test
    public void testQueryWithFieldSelector() throws Exception {
        collection.insert(json("foo: 'bar'"));
        DBObject obj = collection.findOne(json("{}"), json("foo: 1"));
        assertThat(obj.keySet()).containsOnly("_id", "foo");

        obj = collection.findOne(json("foo:'bar'"), json("_id: 1"));
        assertThat(obj.keySet()).containsOnly("_id");

        obj = collection.findOne(json("foo: 'bar'"), json("_id: 0, foo:1"));
        assertThat(obj.keySet()).containsOnly("foo");
    }

    @Test
    public void testQueryWithDotNotationFieldSelector() throws Exception {
        collection.insert(json("_id: 123, index: false, foo: { a: 'a1', b: 0}"));
        DBObject obj = collection.findOne(json("{}"), json("foo.a: 1, foo.b: 1"));
        assertThat(obj).isEqualTo(json("_id: 123, foo: {a: 'a1', b: 0}"));

        obj = collection.findOne(json("{}"), json("foo.a: 1"));
        assertThat(obj).isEqualTo(json("_id: 123, foo: {a: 'a1'}"));

        obj = collection.findOne(json("{}"), json("foo.a: 1, index: 1, _id: 0"));
        assertThat(obj).isEqualTo(json("foo: {a: 'a1'}, index: false"));

        obj = collection.findOne(json("{}"), json("foo: 1, _id: 0"));
        assertThat(obj).isEqualTo(json("foo: {a: 'a1', b: 0}"));

        obj = collection.findOne(json("{}"), json("foo.a.b.c.d: 1"));
        assertThat(obj).isEqualTo(json("_id: 123, foo: {}"));
    }

    @Test
    public void testQuerySystemNamespace() throws Exception {
        assertThat(db.getCollection("system.foobar").findOne()).isNull();
        assertThat(db.getCollectionNames()).containsOnly("system.indexes");

        collection.insert(json("{}"));
        BasicDBObject expectedObj = new BasicDBObject("name", collection.getFullName());
        DBObject coll = db.getCollection("system.namespaces").findOne(expectedObj);
        assertThat(coll).isEqualTo(expectedObj);
    }

    @Test
    public void testQueryAllExpression() throws Exception {
        collection.insert(json(" _id : [ { x : 1 } , { x : 2  } ]"));
        collection.insert(json(" _id : [ { x : 2 } , { x : 3  } ]"));

        assertThat(collection.find(json("'_id.x':{$all:[1,2]}")).toArray()).hasSize(1);
        assertThat(collection.find(json("'_id.x':{$all:[2,3]}")).toArray()).hasSize(1);
    }

    @Test
    public void testRemove() {
        collection.insert(json("_id: 1"));
        collection.insert(json("_id: 2"));
        collection.insert(json("_id: 3"));
        collection.insert(json("_id: 4"));

        collection.remove(json("_id: 2"));

        assertThat(collection.findOne(json("_id: 2"))).isNull();
        assertThat(collection.count()).isEqualTo(3);

        collection.remove(json("_id: {$gte: 3}"));
        assertThat(collection.count()).isEqualTo(1);
        assertThat(collection.findOne()).isEqualTo(json("_id: 1"));
    }

    @Test
    public void testRemoveSingle() throws Exception {
        DBObject obj = new BasicDBObject("_id", ObjectId.get());
        collection.insert(obj);
        collection.remove(obj);
    }

    @Test
    public void testRemoveReturnsModifiedDocumentCount() {
        collection.insert(json("{}"));
        collection.insert(json("{}"));

        WriteResult result = collection.remove(json("{}"));
        assertThat(result.getN()).isEqualTo(2);

        result = collection.remove(json("{}"));
        assertThat(result.getN()).isEqualTo(0);
    }

    @Test
    public void testReservedCollectionNames() throws Exception {
        try {
            db.getCollection("foo$bar").insert(json("{}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getMessage()).contains("cannot insert into reserved $ collection");
        }

        try {
            db.getCollection("").insert(json("{}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getMessage().toLowerCase()).contains("invalid ns");
        }

        try {
            db.getCollection(
                    "verylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstringverylongstring")
                    .insert(json("{}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getMessage()).contains("name too long");
        }
    }

    @Test
    public void testSave() {
        BasicDBObject inserted = json("_id: 1");
        collection.insert(inserted);
        collection.save(inserted);
    }

    @Test
    public void testServerStatus() throws Exception {
        Date before = new Date();
        CommandResult serverStatus = command("serverStatus");
        serverStatus.throwOnError();
        assertThat(serverStatus.get("uptime")).isInstanceOf(Number.class);
        assertThat(serverStatus.get("uptimeMillis")).isInstanceOf(Long.class);
        Date serverTime = (Date) serverStatus.get("localTime");
        assertThat(serverTime).isNotNull();
        assertThat(serverTime.after(new Date())).isFalse();
        assertThat(before.after(serverTime)).isFalse();

        BSONObject connections = (BSONObject) serverStatus.get("connections");
        assertThat(connections.get("current")).isNotNull();
    }

    @Test
    public void testReplSetGetStatus() throws Exception {
        CommandResult result = command("replSetGetStatus");
        assertThat(result.ok()).isFalse();
        assertThat(result.getErrorMessage()).isEqualTo("not running with --replSet");
    }

    @Test
    public void testWhatsMyUri() throws Exception {
        for (String dbname : new String[] { "admin", "local", "test" }) {
            CommandResult result = client.getDB(dbname).command("whatsmyuri");
            result.throwOnError();
            assertThat(result.ok()).isTrue();
            assertThat(result.get("you")).isNotNull();
            assertThat(result.get("you").toString()).startsWith("127.0.0.1:");
        }
    }

    @Test
    public void testSort() {
        collection.insert(json("a:1, _id:1"));
        collection.insert(json("a:2, _id:2"));
        collection.insert(json("_id: 5"));
        collection.insert(json("a:3, _id:3"));
        collection.insert(json("a:4, _id:4"));

        @SuppressWarnings("resource")
        DBCursor cursor = collection.find().sort(json("a: -1"));
        assertThat(cursor.toArray()).containsExactly(json("a:4, _id:4"), json("a:3, _id:3"), json("a:2, _id:2"),
                json("a:1, _id:1"), json("_id: 5"));
    }

    @Test
    public void testSortByEmbeddedKey() {
        collection.insert(json("_id: 1, a: { b:1 }"));
        collection.insert(json("_id: 2, a: { b:2 }"));
        collection.insert(json("_id: 3, a: { b:3 }"));
        List<DBObject> results = collection.find().sort(json("'a.b': -1")).toArray();
        assertThat(results).containsExactly(json("_id: 3, a: { b:3 }"), json("_id: 2, a: { b:2 }"),
                json("_id: 1, a: { b:1 }"));
    }

    @Test
    public void testUpdate() throws Exception {
        BasicDBObject object = json("_id: 1");

        BasicDBObject newObject = json("_id: 1");
        newObject.put("foo", "bar");

        collection.insert(object);
        WriteResult result = collection.update(object, newObject);
        assertThat(result.getN()).isEqualTo(1);
        assertThat(result.isUpdateOfExisting()).isTrue();
        assertThat(result.getUpsertedId()).isNull();
        assertThat(collection.findOne(object)).isEqualTo(newObject);
    }

    @Test
    public void testUpdateNothing() throws Exception {
        BasicDBObject object = json("_id: 1");
        WriteResult result = collection.update(object, object);
        assertThat(result.getN()).isEqualTo(0);
        assertThat(result.getUpsertedId()).isNull();
    }

    @Test
    public void testUpdateBlank() throws Exception {
        DBObject document = json("'': 1, _id: 2, a: 3, b: 4");
        collection.insert(document);

        collection.update(json("{}"), json("$set: {c:5}"));
        assertThat(collection.findOne()).isEqualTo(json("'': 1, _id: 2, a: 3, b: 4, c:5"));
    }

    @Test
    public void testUpdateEmptyPositional() throws Exception {
        try {
            collection.update(json("{}"), json("$set:{'a.$.b': 1}"), true, false);
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(16650);
            assertThat(e.getMessage()).contains(
                    "Cannot apply the positional operator without a corresponding query field containing an array.");
        }
    }

    @Test
    public void testUpdateMultiplePositional() throws Exception {
        collection.insert(json("{a: {b: {c: 1}}}"));
        try {
            collection.update(json("{'a.b.c':1}"), json("$set:{'a.$.b.$.c': 1}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(16650);
            assertThat(e.getMessage()).contains(
                    "Cannot apply the positional operator without a corresponding query field containing an array.");
        }
    }

    @Test
    public void testUpdateIllegalFieldName() throws Exception {

        // Disallow $ in field names - SERVER-3730

        collection.insert(json("{x:1}"));

        collection.update(json("{x:1}"), json("$set: {y:1}")); // ok

        try {
            collection.update(json("{x:1}"), json("$set: {$z:1}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(15896);
            assertThat(e.getMessage()).contains("Modified field name may not start with $");
        }

        // unset ok to remove bad fields
        collection.update(json("{x:1}"), json("$unset: {$z:1}"));

        try {
            collection.update(json("{x:1}"), json("$inc: {$z:1}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(15896);
            assertThat(e.getMessage()).contains("Modified field name may not start with $");
        }

        try {
            collection.update(json("{x:1}"), json("$pushAll: {$z:[1,2,3]}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(15896);
            assertThat(e.getMessage()).contains("Modified field name may not start with $");
        }

    }

    @Test
    public void testUpdateSubdocument() throws Exception {
        try {
            collection.update(json("{}"), json("'a.b.c': 123"));
            fail("IllegalArgumentException expected");
        } catch (IllegalArgumentException e) {
            assertThat(e.getMessage()).contains("Bad Key");
        }
    }

    @Test
    public void testUpdateIdNoChange() {
        collection.insert(json("_id: 1"));
        collection.update(json("_id: 1"), json("_id: 1, a: 5"));

        assertThat(collection.findOne(json("_id: 1"))).isEqualTo(json("_id: 1, a: 5"));

        collection.update(json("_id: 1"), json("$set: {_id: 1, b: 3}"));

        assertThat(collection.findOne(json("_id: 1"))).isEqualTo(json("_id: 1, a: 5, b: 3"));

        // test with $set

        collection.update(json("_id: 1"), json("$set: {_id: 1, a: 7}"));

        assertThat(collection.findOne(json("_id: 1"))).isEqualTo(json("_id: 1, a: 7, b: 3"));
    }

    @Test
    public void testUpdatePush() throws Exception {
        BasicDBObject idObj = json("_id: 1");
        collection.insert(idObj);
        collection.update(idObj, json("$push: {'field.subfield.subsubfield': 'value'}"));
        DBObject expected = json("_id: 1, field:{subfield:{subsubfield: ['value']}}");
        assertThat(collection.findOne(idObj)).isEqualTo(expected);

        // push to non-array
        collection.update(idObj, json("$set: {field: 'value'}"));
        try {
            collection.update(idObj, json("$push: {field: 'value'}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10141);
            assertThat(e.getMessage()).contains("Cannot apply $push modifier to non-array");
        }

        // push with multiple fields

        DBObject pushObj = json("$push: {field1: 'value', field2: 'value2'}");
        collection.update(idObj, pushObj);

        expected = json("_id: 1, field: 'value', field1: ['value'], field2: ['value2']");
        assertThat(collection.findOne(idObj)).isEqualTo(expected);

        // push duplicate
        pushObj = json("$push: {field1: 'value'}");
        collection.update(idObj, pushObj);
        expected.put("field1", Arrays.asList("value", "value"));
        assertThat(collection.findOne(idObj)).isEqualTo(expected);
    }

    @Test
    public void testUpdatePushAll() throws Exception {
        DBObject idObj = json("_id: 1");
        collection.insert(idObj);
        try {
            collection.update(idObj, json("$pushAll: {field: 'value'}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10153);
            assertThat(e.getMessage()).contains("Modifier $pushAll allowed for arrays only");
        }

        collection.update(idObj, json("$pushAll: {field: ['value', 'value2']}"));
        assertThat(collection.findOne(idObj)).isEqualTo(json("_id: 1, field: ['value', 'value2']"));
    }

    @Test
    public void testUpdateAddToSet() throws Exception {
        BasicDBObject idObj = json("_id: 1");
        collection.insert(idObj);
        collection.update(idObj, json("$addToSet: {'field.subfield.subsubfield': 'value'}"));
        assertThat(collection.findOne(idObj)).isEqualTo(json("_id: 1, field:{subfield:{subsubfield:['value']}}"));

        // addToSet to non-array
        collection.update(idObj, json("$set: {field: 'value'}"));
        try {
            collection.update(idObj, json("$addToSet: {field: 'value'}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10141);
            assertThat(e.getMessage()).contains("Cannot apply $addToSet modifier to non-array");
        }

        // addToSet with multiple fields

        collection.update(idObj, json("$addToSet: {field1: 'value', field2: 'value2'}"));

        assertThat(collection.findOne(idObj)).isEqualTo(
                json("_id: 1, field: 'value', field1: ['value'], field2: ['value2']"));

        // addToSet duplicate
        collection.update(idObj, json("$addToSet: {field1: 'value'}"));
        assertThat(collection.findOne(idObj)).isEqualTo(
                json("_id: 1, field: 'value', field1: ['value'], field2: ['value2']"));
    }

    @Test
    public void testUpdateAddToSetEach() throws Exception {
        collection.insert(json("_id: 1"));

        collection.update(json("_id: 1"), json("$addToSet: {a: {$each: [6,5,4]}}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: [6,5,4]"));

        collection.update(json("_id: 1"), json("$addToSet: {a: {$each: [3,2,1]}}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: [6,5,4,3,2,1]"));

        collection.update(json("_id: 1"), json("$addToSet: {a: {$each: [4,7,9,2]}}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: [6,5,4,3,2,1,7,9]"));

        collection.update(json("_id: 1"), json("$addToSet: {a: {$each: [12,13,12]}}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: [6,5,4,3,2,1,7,9,12,13]"));
    }

    @Test
    public void testUpdateDatasize() throws Exception {
        DBObject obj = json("{_id:1, a:{x:[1, 2, 3]}}");
        collection.insert(obj);
        int oldSize = collection.getStats().getInt("size");

        collection.update(json("_id:1"), json("$set:{'a.x.0': 3}"));
        assertThat(collection.findOne().get("a")).isEqualTo(json("x:[3,2,3]"));
        assertThat(collection.getStats().getInt("size")).isEqualTo(oldSize);

        // now increase the db
        collection.update(json("_id:1"), json("$set:{'a.x.0': 'abc'}"));
        assertThat(collection.getStats().getInt("size") - oldSize).isEqualTo(4);
    }

    @Test
    public void testUpdatePull() throws Exception {
        BasicDBObject obj = json("_id: 1");
        collection.insert(obj);

        // pull from non-existing field
        assertThat(collection.findOne(obj)).isEqualTo(obj);

        // pull from non-array
        collection.update(obj, json("$set: {field: 'value'}"));
        try {
            collection.update(obj, json("$pull: {field: 'value'}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10142);
            assertThat(e.getMessage()).contains("Cannot apply $pull modifier to non-array");
        }

        // pull standard
        collection.update(obj, json("$set: {field: ['value1', 'value2', 'value1']}"));

        collection.update(obj, json("$pull: {field: 'value1'}"));

        assertThat(collection.findOne(obj).get("field")).isEqualTo(Arrays.asList("value2"));

        // pull with multiple fields

        collection.update(obj, json("$set: {field1: ['value1', 'value2', 'value1']}"));
        collection.update(obj, json("$set: {field2: ['value3', 'value3', 'value1']}"));

        collection.update(obj, json("$pull: {field1: 'value2', field2: 'value3'}"));

        assertThat(collection.findOne(obj).get("field1")).isEqualTo(Arrays.asList("value1", "value1"));
        assertThat(collection.findOne(obj).get("field2")).isEqualTo(Arrays.asList("value1"));
    }

    @Test
    public void testUpdatePullAll() throws Exception {
        DBObject obj = json("_id: 1");
        collection.insert(obj);
        collection.update(obj, json("$set: {field: 'value'}"));
        try {
            collection.update(obj, json("$pullAll: {field: 'value'}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10142);
            assertThat(e.getMessage()).contains("Cannot apply $pullAll modifier to non-array");
        }

        collection.update(obj, json("$set: {field1: ['value1', 'value2', 'value1', 'value3', 'value4', 'value3']}"));

        collection.update(obj, json("$pullAll: {field1: ['value1', 'value3']}"));

        assertThat(collection.findOne(obj).get("field1")).isEqualTo(Arrays.asList("value2", "value4"));

        try {
            collection.update(obj, json("$pullAll: {field1: 'bar'}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10153);
            assertThat(e.getMessage()).contains("Modifier $pullAll allowed for arrays only");
        }

    }

    @Test
    public void testUpdateSet() throws Exception {
        BasicDBObject object = json("_id: 1");

        collection.insert(object);
        assertThat(collection.findOne(object)).isEqualTo(object);

        collection.update(object, json("$set: {foo: 'bar'}"));

        BasicDBObject expected = json("{}");
        expected.putAll((BSONObject) object);
        expected.put("foo", "bar");

        collection.update(object, json("$set: {bar: 'bla'}"));
        expected.put("bar", "bla");
        assertThat(collection.findOne(object)).isEqualTo(expected);

        collection.update(object, json("$set: {'foo.bar': 'bla'}"));
        expected.put("foo", json("bar: 'bla'"));
        assertThat(collection.findOne(object)).isEqualTo(expected);

        collection.update(object, json("$set: {'foo.foo': '123'}"));
        ((BasicBSONObject) expected.get("foo")).put("foo", "123");
        assertThat(collection.findOne(object)).isEqualTo(expected);
    }

    @Test
    public void testUpdateSetOnInsert() throws Exception {
        BasicDBObject object = json("_id: 1");
        collection.update(object, json("$set: {b: 3}, $setOnInsert: {a: 3}"), true, true);
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, b: 3, a: 3"));

        collection.update(object, json("$set: {b: 4}, $setOnInsert: {a: 5}"), true, true);
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, b: 4, a: 3")); // 'a'
                                                                                // is
                                                                                // unchanged
    }

    @Test
    public void testUpdateSetWithArrayIndices() throws Exception {

        // SERVER-181

        collection.insert(json("_id: 1, a: [{x:0}]"));
        collection.update(json("{}"), json("$set: {'a.0.x': 3}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: [{x:3}]"));

        collection.update(json("{}"), json("$set: {'a.1.z': 17}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: [{x:3}, {z:17}]"));

        collection.update(json("{}"), json("$set: {'a.0.y': 7}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: [{x:3, y:7}, {z:17}]"));

        collection.update(json("{}"), json("$set: {'a.1': 'test'}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: [{x:3, y:7}, 'test']"));
    }

    @Test
    public void testUpdateUnsetWithArrayIndices() throws Exception {

        // SERVER-273

        collection.insert(json("_id: 1, a:[{x:0}]"));
        collection.update(json("{}"), json("$unset: {'a.0.x': 1}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a:[{}]"));

        collection.update(json("{}"), json("$unset: {'a.0': 1}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a:[null]"));

        collection.update(json("{}"), json("$unset: {'a.10': 1}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a:[null]"));
    }

    @Test
    public void testUpdatePop() throws Exception {
        BasicDBObject object = json("_id: 1");

        collection.insert(object);
        collection.update(object, json("$pop: {'foo.bar': 1}"));

        assertThat(collection.findOne(object)).isEqualTo(object);
        collection.update(object, json("$set: {'foo.bar': [1,2,3]}"));
        assertThat(collection.findOne(object)).isEqualTo(json("_id:1, foo:{bar:[1,2,3]}"));

        collection.update(object, json("$pop: {'foo.bar': 1}"));
        assertThat(collection.findOne(object)).isEqualTo(json("_id:1, foo:{bar:[1,2]}"));

        collection.update(object, json("$pop: {'foo.bar': -1}"));
        assertThat(collection.findOne(object)).isEqualTo(json("_id:1, foo:{bar:[2]}"));

        collection.update(object, json("$pop: {'foo.bar': null}"));
        assertThat(collection.findOne(object)).isEqualTo(json("_id:1, foo:{bar:[]}"));

    }

    @Test
    public void testUpdateUnset() throws Exception {
        DBObject obj = json("_id: 1, a: 1, b: null, c: 'value'");
        collection.insert(obj);
        try {
            collection.update(obj, json("$unset: {_id: ''}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10148);
            assertThat(e.getMessage()).contains("Mod on _id not allowed");
        }

        collection.update(obj, json("$unset: {a:'', b:''}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, c: 'value'"));

        collection.update(obj, json("$unset: {'c.y': 1}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, c: 'value'"));

        collection.update(json("_id: 1"), json("a: {b: 'foo', c: 'bar'}"));

        collection.update(json("_id: 1"), json("$unset: {'a.b':1}"));
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: {c: 'bar'}"));
    }

    @Test
    public void testUpdateWithIdIn() {
        collection.insert(json("_id: 1"));
        DBObject update = json("$push: {n: {_id: 2, u:3}}, $inc: {c:4}");
        DBObject expected = json("_id: 1, n: [{_id: 2, u:3}], c:4");
        collection.update(json("_id: {$in: [1]}"), update, false, true);
        assertThat(collection.findOne()).isEqualTo(expected);
    }

    @Test
    public void testUpdateMulti() throws Exception {
        collection.insert(json("a: 1"));
        collection.insert(json("a: 1"));
        WriteResult result = collection.update(json("a: 1"), json("$set: {b: 2}"));

        assertThat(result.getN()).isEqualTo(1);
        assertThat(result.isUpdateOfExisting()).isTrue();

        assertThat(collection.find(new BasicDBObject("b", 2)).count()).isEqualTo(1);

        result = collection.update(json("a: 1"), json("$set: {b: 3}"), false, true);
        assertThat(result.getN()).isEqualTo(2);
        assertThat(result.isUpdateOfExisting()).isTrue();
        assertThat(collection.find(new BasicDBObject("b", 2)).count()).isEqualTo(0);
        assertThat(collection.find(new BasicDBObject("b", 3)).count()).isEqualTo(2);
    }

    @Test
    public void testUpdateIllegalInt() throws Exception {
        collection.insert(json("_id: 1, a:{x:1}"));
        try {
            collection.update(json("_id: 1"), json("$inc: {a: 1}"));
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getMessage()).contains("can not increment");
        }
    }

    @Test
    public void testUpdateWithIdInMulti() {
        collection.insert(json("_id: 1"), json("_id: 2"));
        collection.update(json("_id: {$in:[1,2]}"), json("$set: {n:1}"), false, true);
        List<DBObject> results = collection.find().toArray();
        assertThat(results).containsExactly(json("_id: 1, n:1"), json("_id: 2, n: 1"));
    }

    @Test
    public void testUpdateWithIdInMultiReturnModifiedDocumentCount() {
        collection.insert(json("_id: 1"), json("_id: 2"));
        WriteResult result = collection.update(json("_id: {$in:[1,2]}"), json("$set:{n:1}"), false, true);
        assertThat(result.getN()).isEqualTo(2);
    }

    @Test
    public void testUpdateWithIdQuery() {
        collection.insert(json("_id: 1"), json("_id: 2"));
        collection.update(json("_id: {$gt:1}"), json("$set: {n:1}"), false, true);
        List<DBObject> results = collection.find().toArray();
        assertThat(results).containsExactly(json("_id: 1"), json("_id: 2, n:1"));
    }

    @Test
    public void testUpdateWithObjectId() {
        collection.insert(json("_id: {n:1}"));
        WriteResult result = collection.update(json("_id: {n:1}"), json("$set: {a:1}"), false, false);
        assertThat(collection.findOne()).isEqualTo(json("_id: {n:1}, a:1"));
        assertThat(result.getN()).isEqualTo(1);
    }

    @Test
    public void testUpdateArrayMatch() throws Exception {

        collection.insert(json("_id:1, a:[{x:1,y:1}, {x:2,y:2}, {x:3,y:3}]"));

        collection.update(json("'a.x': 2"), json("$inc: {'a.$.y': 1}"));

        assertThat(collection.findOne(json("'a.x': 2"))).isEqualTo(json("_id:1, a:[{x:1,y:1}, {x:2,y:3}, {x:3,y:3}]"));

        collection.insert(json("{'array': [{'123a':{'name': 'old'}}]}"));
        assertThat(collection.findOne(json("{'array.123a.name': 'old'}"))).isNotNull();
        collection.update(json("{'array.123a.name': 'old'}"), json("{$set: {'array.$.123a.name': 'new'}}"));
        assertThat(collection.findOne(json("{'array.123a.name': 'new'}"))).isNotNull();
        assertThat(collection.findOne(json("{'array.123a.name': 'old'}"))).isNull();
    }

    @Test
    public void testMultiUpdateArrayMatch() throws Exception {
        collection.insert(json("{}"));
        collection.insert(json("x:[1,2,3]"));
        collection.insert(json("x:99"));

        collection.update(json("x:2"), json("$inc:{'x.$': 1}"), false, true);
        assertThat(collection.findOne(json("x:1")).get("x")).isEqualTo(Arrays.asList(1, 3, 3));
    }

    @Test
    public void testMultiUpdateNoOperator() throws Exception {
        collection.insert(json("x:99"));
        try {
            collection.update(json("{x:99}"), json("x:99, y:17"), false, true);
            fail("MongoException expected");
        } catch (MongoException e) {
            assertThat(e.getCode()).isEqualTo(10158);
            assertThat(e.getMessage()).contains("multi update only works with $ operators");
        }
    }

    @Test
    public void testUpsert() {
        WriteResult result = collection.update(json("n:'jon'"), json("$inc:{a:1}"), true, false);
        assertThat(result.getN()).isEqualTo(1);

        DBObject object = collection.findOne();
        assertThat(result.getUpsertedId()).isEqualTo(object.get("_id"));

        object.removeField("_id");
        assertThat(object).isEqualTo(json("n:'jon', a:1"));

        result = collection.update(json("_id: 17, n:'jon'"), json("$inc:{a:1}"), true, false);
        assertThat(result.getUpsertedId()).isNull();
        assertThat(collection.findOne(json("_id:17"))).isEqualTo(json("_id: 17, n:'jon', a:1"));
    }

    @Test
    public void testUpsertFieldOrder() throws Exception {
        collection.update(json("'x.y': 2"), json("$inc: {a:7}"), true, false);
        DBObject obj = collection.findOne();
        obj.removeField("_id");
        // this actually differs from the official MongoDB implementation
        assertThat(obj).isEqualTo(json("x:{y:2}, a:7"));
    }

    @Test
    public void testUpsertWithoutId() {
        WriteResult result = collection.update(json("a:1"), json("a:2"), true, false);
        assertThat(result.getN()).isEqualTo(1);
        assertThat(result.isUpdateOfExisting()).isFalse();
        assertThat(collection.findOne().get("_id")).isInstanceOf(ObjectId.class);
        assertThat(collection.findOne().get("a")).isEqualTo(2);
    }

    @Test
    public void testUpsertOnIdWithPush() {
        DBObject update1 = json("$push: {c: {a:1, b:2} }");
        DBObject update2 = json("$push: {c: {a:3, b:4} }");

        collection.update(json("_id: 1"), update1, true, false);

        collection.update(json("_id: 1"), update2, true, false);

        DBObject expected = json("_id: 1, c: [{a:1, b:2}, {a:3, b:4}]");

        assertThat(collection.findOne(json("'c.a':3, 'c.b':4"))).isEqualTo(expected);
    }

    @Test
    public void testUpsertWithConditional() {
        DBObject query = json("_id: 1, b: {$gt: 5}");
        BasicDBObject update = json("$inc: {a: 1}");
        collection.update(query, update, true, false);
        assertThat(collection.findOne()).isEqualTo(json("_id: 1, a: 1"));
    }

    @Test
    public void testUpsertWithEmbeddedQuery() {
        collection.update(json("_id: 1, e.i: 1"), json("$set: {a:1}"), true, false);
        assertThat(collection.findOne(json("_id: 1"))).isEqualTo(json("_id:1, e: {i:1}, a:1"));
    }

    @Test
    public void testUpsertWithIdIn() throws Exception {
        DBObject query = json("_id: {$in: [1]}");
        DBObject update = json("$push: {n: {_id: 2 ,u : 3}}, $inc: {c: 4}");
        DBObject expected = json("_id: 1, n: [{_id: 2 ,u : 3}], c: 4");

        collection.update(query, update, true, false);

        // the ID generation actually differs from official MongoDB which just
        // create a random object id
        DBObject actual = collection.findOne();
        assertThat(actual).isEqualTo(expected);
    }

    @Test
    public void testIsMaster() throws Exception {
        CommandResult isMaster = db.command("isMaster");
        assertThat(isMaster.ok()).isTrue();
        assertThat(isMaster.getBoolean("ismaster")).isTrue();
        assertThat(isMaster.getDate("localTime")).isInstanceOf(Date.class);
        assertThat(isMaster.getInt("maxBsonObjectSize")).isGreaterThan(1000);
        assertThat(isMaster.getInt("maxMessageSizeBytes")).isGreaterThan(isMaster.getInt("maxBsonObjectSize"));
    }

    // https://github.com/foursquare/fongo/pull/26
    // http://stackoverflow.com/questions/12403240/storing-null-vs-not-storing-the-key-at-all-in-mongodb
    @Test
    public void testFindWithNullOrNoFieldFilter() {

        collection.insert(json("name: 'jon', group: 'group1'"));
        collection.insert(json("name: 'leo', group: 'group1'"));
        collection.insert(json("name: 'neil1', group: 'group2'"));
        collection.insert(json("name: 'neil2', group: null"));
        collection.insert(json("name: 'neil3'"));

        // check {group: null} vs {group: {$exists: false}} filter
        List<DBObject> objs = collection.find(json("group: null")).toArray();
        assertThat(objs).as("should have two neils (neil2, neil3)").hasSize(2);

        objs = collection.find(json("group: {$exists: false}")).toArray();
        assertThat(objs).as("should have one neils (neil3)").hasSize(1);

        // same check but for fields which do not exist in DB
        objs = collection.find(json("other: null")).toArray();
        assertThat(objs).as("should return all documents").hasSize(5);

        objs = collection.find(json("other: {$exists: false}")).toArray();
        assertThat(objs).as("should return all documents").hasSize(5);
    }

    @Test
    public void testInsertsWithUniqueIndex() {
        collection.createIndex(new BasicDBObject("uniqueKeyField", 1), new BasicDBObject("unique", true));

        collection.insert(json("uniqueKeyField: 'abc1', afield: 'avalue'"));
        collection.insert(json("uniqueKeyField: 'abc2', afield: 'avalue'"));
        collection.insert(json("uniqueKeyField: 'abc3', afield: 'avalue'"));

        try {
            collection.insert(json("uniqueKeyField: 'abc2', afield: 'avalue'"));
            fail("DuplicateKeyException expected");
        } catch (DuplicateKeyException e) {
            // expected
        }
    }

    @Test
    public void testAddNonUniqueIndexOnNonIdField() {
        collection.createIndex(new BasicDBObject("someField", 1), new BasicDBObject("unique", false));

        collection.insert(json("someField: 'abc'"));
        collection.insert(json("someField: 'abc'"));
    }

    @Test
    public void testCompoundUniqueIndicesNotSupportedAndThrowsException() {
        try {
            collection.createIndex(new BasicDBObject("a", 1).append("b", 1), new BasicDBObject("unique", true));
            fail("MongoException expected");
        } catch (MongoException e) {
            // expected
        }
    }

    @Test
    public void testCursorOptionNoTimeout() throws Exception {
        DBCursor cursor = collection.find().addOption(Bytes.QUERYOPTION_NOTIMEOUT);
        try {
            assertFalse(cursor.iterator().hasNext());
        } finally {
            cursor.close();
        }
    }

}
TOP

Related Classes of de.bwaldvogel.mongo.backend.memory.MemoryBackendTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.