/* * Copyright (c) 2008-2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mongodb; import category.ReplicaSet; import com.mongodb.client.model.Collation; import com.mongodb.client.model.CollationAlternate; import com.mongodb.client.model.CollationCaseFirst; import com.mongodb.client.model.CollationMaxVariable; import com.mongodb.client.model.CollationStrength; import com.mongodb.operation.ListCollectionsOperation; import com.mongodb.operation.UserExistsOperation; import org.bson.BsonDocument; import org.bson.BsonString; import org.bson.codecs.BsonDocumentCodec; import org.junit.Test; import org.junit.experimental.categories.Category; import java.net.UnknownHostException; import static com.mongodb.ClusterFixture.disableMaxTimeFailPoint; import static com.mongodb.ClusterFixture.enableMaxTimeFailPoint; import static com.mongodb.ClusterFixture.getBinding; import static com.mongodb.ClusterFixture.isAuthenticated; import static com.mongodb.ClusterFixture.isDiscoverableReplicaSet; import static com.mongodb.ClusterFixture.isSharded; import static com.mongodb.ClusterFixture.serverVersionAtLeast; import static com.mongodb.DBObjectMatchers.hasFields; import static com.mongodb.DBObjectMatchers.hasSubdocument; import static com.mongodb.Fixture.getDefaultDatabaseName; import static com.mongodb.Fixture.getMongoClient; import static com.mongodb.ReadPreference.secondary; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.sameInstance; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeThat; import static org.junit.Assume.assumeTrue; @SuppressWarnings("deprecation") public class DBTest extends DatabaseTestCase { @Test public void shouldGetDefaultWriteConcern() { assertEquals(WriteConcern.ACKNOWLEDGED, database.getWriteConcern()); } @Test public void shouldGetDefaultReadPreference() { assertEquals(ReadPreference.primary(), database.getReadPreference()); } @Test public void shouldReturnCachedCollectionObjectIfExists() { DBCollection collection1 = database.getCollection("test"); DBCollection collection2 = database.getCollection("test"); assertThat("Checking that references are equal", collection1, sameInstance(collection2)); } @Test public void shouldDropItself() { // when String databaseName = "drop-test-" + System.nanoTime(); DB db = getMongoClient().getDB(databaseName); db.createCollection(collectionName, new BasicDBObject()); // then assertThat(getMongoClient().getDatabaseNames(), hasItem(databaseName)); // when db.dropDatabase(); // then assertThat(getMongoClient().getDatabaseNames(), not(hasItem(databaseName))); } @Test public void shouldGetCollectionNames() { database.dropDatabase(); String[] collectionNames = {"c1", "c2", "c3"}; for (final String name : collectionNames) { database.createCollection(name, new BasicDBObject()); } assertThat(database.getCollectionNames(), hasItems(collectionNames)); } @Test public void shouldGetCollectionGivenAStringName() { DBCollection collection = database.getCollectionFromString("foo"); assertEquals("foo", collection.getName()); collection = database.getCollectionFromString("foo.bar"); assertEquals("foo.bar", collection.getName()); collection = database.getCollectionFromString("foo.bar.zoo"); assertEquals("foo.bar.zoo", collection.getName()); collection = database.getCollectionFromString("foo.bar.zoo.dork"); assertEquals("foo.bar.zoo.dork", collection.getName()); } @Test(expected = MongoException.class) public void shouldReceiveAnErrorIfCreatingCappedCollectionWithoutSize() { database.createCollection("someName", new BasicDBObject("capped", true)); } @Test public void shouldDeferCollectionCreationIfOptionsIsNull() { collection.drop(); database.createCollection(collectionName, null); assertFalse(database.getCollectionNames().contains(collectionName)); } @Test public void shouldCreateCappedCollection() { collection.drop(); database.createCollection(collectionName, new BasicDBObject("capped", true) .append("size", 242880)); assertTrue(database.getCollection(collectionName).isCapped()); } @Test(expected = MongoCommandException.class) public void shouldErrorIfCreatingACollectionThatAlreadyExists() { // given database.createCollection(collectionName, new BasicDBObject()); // when database.createCollection(collectionName, new BasicDBObject()); } @Test public void shouldCreateCappedCollectionWithMaxNumberOfDocuments() { collection.drop(); DBCollection cappedCollectionWithMax = database.createCollection(collectionName, new BasicDBObject("capped", true) .append("size", 242880) .append("max", 10)); assertThat(cappedCollectionWithMax.getStats(), hasSubdocument(new BasicDBObject("capped", true).append("max", 10))); for (int i = 0; i < 11; i++) { cappedCollectionWithMax.insert(new BasicDBObject("x", i)); } assertThat(cappedCollectionWithMax.find().count(), is(10)); } @Test public void shouldCreateUncappedCollection() { collection.drop(); BasicDBObject creationOptions = new BasicDBObject("capped", false); database.createCollection(collectionName, creationOptions); assertFalse(database.getCollection(collectionName).isCapped()); } @Test(expected = MongoCommandException.class) public void shouldThrowErrorIfCreatingACappedCollectionWithANegativeSize() { collection.drop(); DBObject creationOptions = BasicDBObjectBuilder.start().add("capped", true) .add("size", -20).get(); database.createCollection(collectionName, creationOptions); } @Test public void shouldCreateCollectionWithTheSetCollation() { assumeThat(serverVersionAtLeast(3, 4), is(true)); // Given collection.drop(); Collation collation = Collation.builder() .locale("en") .caseLevel(true) .collationCaseFirst(CollationCaseFirst.OFF) .collationStrength(CollationStrength.IDENTICAL) .numericOrdering(true) .collationAlternate(CollationAlternate.SHIFTED) .collationMaxVariable(CollationMaxVariable.SPACE) .backwards(true) .build(); DBObject options = BasicDBObject.parse("{ collation: { locale: 'en', caseLevel: true, caseFirst: 'off', strength: 5," + "numericOrdering: true, alternate: 'shifted', maxVariable: 'space', backwards: true }}"); // When database.createCollection(collectionName, options); BsonDocument collectionCollation = getCollectionInfo(collectionName).getDocument("options").getDocument("collation"); // Then BsonDocument collationDocument = collation.asDocument(); for (String key: collationDocument.keySet()) { assertEquals(collationDocument.get(key), collectionCollation.get(key)); } // When - collation set on the database database.getCollection(collectionName).drop(); database.createCollection(collectionName, new BasicDBObject("collation", BasicDBObject.parse(collation.asDocument().toJson()))); collectionCollation = getCollectionInfo(collectionName).getDocument("options").getDocument("collation"); // Then collationDocument = collation.asDocument(); for (String key: collationDocument.keySet()) { assertEquals(collationDocument.get(key), collectionCollation.get(key)); } } @Test(expected = DuplicateKeyException.class) public void shouldGetDuplicateKeyException() { DBObject doc = new BasicDBObject("_id", 1); collection.insert(doc); collection.insert(doc, WriteConcern.ACKNOWLEDGED); } @Test public void shouldDoEval() { assumeThat(isAuthenticated(), is(false)); String code = "function(name, incAmount) {\n" + "var doc = db.myCollection.findOne( { name : name } );\n" + "doc = doc || { name : name , num : 0 , total : 0 , avg : 0 , _id: 1 };\n" + "doc.num++;\n" + "doc.total += incAmount;\n" + "doc.avg = doc.total / doc.num;\n" + "db.myCollection.save( doc );\n" + "return doc;\n" + "}"; database.doEval(code, "eliot", 5); assertEquals(database.getCollection("myCollection").findOne(), new BasicDBObject("_id", 1.0) .append("avg", 5.0) .append("num", 1.0) .append("name", "eliot") .append("total", 5.0)); } @Test(expected = MongoException.class) public void shouldThrowErrorwhileDoingEval() { String code = "function(a, b) {\n" + "var doc = db.myCollection.findOne( { name : b } );\n" + "}"; database.eval(code, 1); } @Test public void shouldInsertDocumentsUsingEval() { assumeThat(isAuthenticated(), is(false)); // when database.eval("db." + collectionName + ".insert({name: 'Bob'})"); // then assertThat(collection.find(new BasicDBObject("name", "Bob")).count(), is(1)); } @Test public void shouldGetStats() { assumeThat(isSharded(), is(false)); assertThat(database.getStats(), hasFields(new String[]{"collections", "avgObjSize", "indexes", "db", "indexSize", "storageSize"})); } @Test public void shouldExecuteCommand() { CommandResult commandResult = database.command(new BasicDBObject("isMaster", 1)); assertThat(commandResult, hasFields(new String[]{"ismaster", "maxBsonObjectSize", "ok"})); } @Test(expected = MongoExecutionTimeoutException.class) public void shouldTimeOutCommand() { assumeThat(isSharded(), is(false)); assumeTrue(serverVersionAtLeast(2, 6)); enableMaxTimeFailPoint(); try { database.command(new BasicDBObject("isMaster", 1).append("maxTimeMS", 1)); } finally { disableMaxTimeFailPoint(); } } @Test @Category(ReplicaSet.class) public void shouldExecuteCommandWithReadPreference() { assumeThat(isSharded(), is(false)); CommandResult commandResult = database.command(new BasicDBObject("dbStats", 1).append("scale", 1), secondary()); assertThat(commandResult, hasFields(new String[]{"collections", "avgObjSize", "indexes", "db", "indexSize", "storageSize"})); } @Test public void shouldNotThrowAnExceptionOnCommandFailure() { CommandResult commandResult = database.command(new BasicDBObject("collStats", "a" + System.currentTimeMillis())); assertThat(commandResult, hasFields(new String[]{"ok", "errmsg"})); } @Test public void shouldAddUser() { String userName = "jeff"; char[] password = "123".toCharArray(); boolean readOnly = true; try { database.removeUser(userName); } catch (Exception e) { // NOOP } WriteResult result = database.addUser(userName, password, readOnly); assertEquals(1, result.getN()); assertFalse(result.isUpdateOfExisting()); assertTrue(new UserExistsOperation(database.getName(), userName).execute(getBinding())); } @Test public void shouldUpdateUser() { String userName = "jeff"; char[] password = "123".toCharArray(); boolean readOnly = true; try { database.removeUser(userName); } catch (Exception e) { // NOOP } WriteResult result = database.addUser(userName, password, readOnly); assertEquals(1, result.getN()); assertFalse(result.isUpdateOfExisting()); char[] newPassword = "345".toCharArray(); boolean newReadOnly = false; result = database.addUser(userName, newPassword, newReadOnly); assertEquals(1, result.getN()); assertTrue(result.isUpdateOfExisting()); assertTrue(new UserExistsOperation(database.getName(), userName).execute(getBinding())); } @Test public void shouldRemoveUser() { String userName = "jeff"; char[] password = "123".toCharArray(); boolean readOnly = true; database.addUser(userName, password, readOnly); database.removeUser(userName); assertFalse(new UserExistsOperation(database.getName(), userName).execute(getBinding())); } @Test(expected = IllegalArgumentException.class) public void shouldThrowAnExceptionWhenDBNameContainsSpaces() { getMongoClient().getDB("foo bar"); } @Test(expected = IllegalArgumentException.class) public void shouldThrowAnExceptionWhenDBNameIsEmpty() { getMongoClient().getDB(""); } @Test public void shouldIgnoreCaseWhenCheckingIfACollectionExists() { // Given database.getCollection("foo1").drop(); assertFalse(database.collectionExists("foo1")); // When database.createCollection("foo1", new BasicDBObject()); // Then assertTrue(database.collectionExists("foo1")); assertTrue(database.collectionExists("FOO1")); assertTrue(database.collectionExists("fOo1")); // Finally database.getCollection("foo1").drop(); } @Test public void shouldReturnFailureWithErrorMessageWhenExecutingInvalidCommand() { assumeTrue(serverVersionAtLeast(2, 4) || !isSharded()); // When CommandResult commandResult = database.command(new BasicDBObject("NotRealCommandName", 1)); // Then assertThat(commandResult.ok(), is(false)); assertThat(commandResult.getErrorMessage(), containsString("no such")); } @Test public void shouldReturnOKWhenASimpleCommandExecutesSuccessfully() { // When CommandResult commandResult = database.command(new BasicDBObject("isMaster", 1)); // Then assertThat(commandResult.ok(), is(true)); assertThat((Boolean) commandResult.get("ismaster"), is(true)); } @Test @Category(ReplicaSet.class) public void shouldRunCommandAgainstSecondaryWhenOnlySecondaryReadPreferenceSpecified() throws UnknownHostException { assumeTrue(isDiscoverableReplicaSet()); // When CommandResult commandResult = database.command(new BasicDBObject("dbstats", 1), secondary()); // Then assertThat(commandResult.ok(), is(true)); assertThat((String) commandResult.get("serverUsed"), not(containsString(":27017"))); } @Test @Category(ReplicaSet.class) public void shouldRunStringCommandAgainstSecondaryWhenSecondaryReadPreferenceSpecified() throws UnknownHostException { assumeTrue(isDiscoverableReplicaSet()); // When CommandResult commandResult = database.command("dbstats", secondary()); // Then assertThat(commandResult.ok(), is(true)); assertThat((String) commandResult.get("serverUsed"), not(containsString(":27017"))); } @Test @Category(ReplicaSet.class) public void shouldRunCommandAgainstSecondaryWhenOnlySecondaryReadPreferenceSpecifiedAlongWithEncoder() throws UnknownHostException { assumeTrue(isDiscoverableReplicaSet()); // When CommandResult commandResult = database.command(new BasicDBObject("dbstats", 1), secondary(), DefaultDBEncoder.FACTORY.create()); // Then assertThat(commandResult.ok(), is(true)); assertThat((String) commandResult.get("serverUsed"), not(containsString(":27017"))); } BsonDocument getCollectionInfo(final String collectionName) { return new ListCollectionsOperation<BsonDocument>(getDefaultDatabaseName(), new BsonDocumentCodec()) .filter(new BsonDocument("name", new BsonString(collectionName))).execute(getBinding()).next().get(0); } }