/*
* 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 org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
import static com.mongodb.ClusterFixture.disableMaxTimeFailPoint;
import static com.mongodb.ClusterFixture.enableMaxTimeFailPoint;
import static com.mongodb.ClusterFixture.isSharded;
import static com.mongodb.ClusterFixture.serverVersionAtLeast;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeThat;
public class DBCursorTest extends DatabaseTestCase {
private static final int NUMBER_OF_DOCUMENTS = 10;
private DBCursor cursor;
@Before
public void setUp() {
super.setUp();
for (int i = 0; i < NUMBER_OF_DOCUMENTS; i++) {
collection.insert(new BasicDBObject("_id", i).append("x", i));
}
collection.createIndex(new BasicDBObject("x", 1));
cursor = collection.find();
}
@After
public void after() {
if (cursor != null) {
cursor.close();
}
}
@Test
public void testNextHasNext() {
cursor.sort(new BasicDBObject("_id", 1));
int i = 0;
while (cursor.hasNext()) {
DBObject cur = cursor.next();
assertEquals(i, cur.get("_id"));
i++;
}
try {
cursor.next();
fail();
} catch (NoSuchElementException e) {
// all good
}
}
@Test
public void testCurr() {
assertNull(cursor.curr());
DBObject next = cursor.next();
assertEquals(next, cursor.curr());
next = cursor.next();
assertEquals(next, cursor.curr());
}
@Test
public void testMarkPartial() {
DBCursor markPartialCursor = collection.find(new BasicDBObject(), new BasicDBObject("_id", 1));
assertTrue(markPartialCursor.next().isPartialObject());
}
@Test
public void testMarkPartialForEmptyObjects() {
DBCursor cursor = collection.find(new BasicDBObject(), new BasicDBObject("_id", 0));
for (final DBObject document : cursor) {
assertTrue(document.isPartialObject());
}
}
@Test
public void testIterator() {
cursor.sort(new BasicDBObject("_id", 1));
Iterator<DBObject> iter = cursor.iterator();
int i = 0;
while (iter.hasNext()) {
DBObject cur = iter.next();
assertEquals(i, cur.get("_id"));
i++;
}
}
@Test
public void testCopy() {
DBCursor cursorCopy = cursor.copy();
assertEquals(cursor.getCollection(), cursorCopy.getCollection());
assertEquals(cursor.getQuery(), cursorCopy.getQuery());
}
@Test(expected = UnsupportedOperationException.class)
public void testRemove() {
cursor.remove();
}
@Test
public void testLimit() {
DBCollection c = collection;
collection.drop();
for (int i = 0; i < 100; i++) {
c.save(new BasicDBObject("x", i));
}
DBCursor dbCursor = c.find();
try {
assertEquals(0, dbCursor.getLimit());
assertEquals(0, dbCursor.getBatchSize());
assertEquals(100, dbCursor.toArray().size());
} finally {
cursor.close();
}
dbCursor = c.find().limit(50);
try {
assertEquals(50, dbCursor.getLimit());
assertEquals(50, dbCursor.toArray().size());
} finally {
cursor.close();
}
dbCursor = c.find().limit(-50);
try {
assertEquals(-50, dbCursor.getLimit());
assertEquals(50, dbCursor.toArray().size());
} finally {
cursor.close();
}
}
@Test
public void testBatchSize() {
DBCollection c = collection;
collection.drop();
for (int i = 0; i < 100; i++) {
c.save(new BasicDBObject("x", i));
}
DBCursor dbCursor = c.find().batchSize(0);
try {
assertEquals(0, dbCursor.getBatchSize());
assertEquals(100, dbCursor.toArray().size());
} finally {
cursor.close();
}
dbCursor = c.find().batchSize(50);
try {
assertEquals(50, dbCursor.getBatchSize());
assertEquals(100, dbCursor.toArray().size());
} finally {
cursor.close();
}
dbCursor = c.find().batchSize(-50);
try {
assertEquals(-50, dbCursor.getBatchSize());
assertEquals(50, dbCursor.toArray().size());
} finally {
cursor.close();
}
}
@Test
public void testSkip() {
DBCursor cursor = collection.find().skip(2);
try {
assertEquals(8, cursor.toArray().size());
} finally {
cursor.close();
}
}
@Test
public void testGetCursorId() {
DBCursor cursor = collection.find().batchSize(2);
assertEquals(0, cursor.getCursorId());
cursor.hasNext();
assertThat(cursor.getCursorId(), is(not(0L)));
cursor = collection.find();
assertEquals(0, cursor.getCursorId());
cursor.hasNext();
assertThat(cursor.getCursorId(), is(0L));
}
@Test
public void testGetServerAddress() {
DBCursor cursor = collection.find().limit(2);
assertEquals(null, cursor.getServerAddress());
cursor.hasNext();
assertTrue(getClient().getServerAddressList().contains(cursor.getServerAddress()));
}
@Test
public void getNumSeen() {
DBCursor cursor = collection.find();
assertEquals(0, cursor.numSeen());
cursor.hasNext();
assertEquals(0, cursor.numSeen());
cursor.next();
assertEquals(1, cursor.numSeen());
cursor.next();
assertEquals(2, cursor.numSeen());
}
@Test
public void testLength() {
assertEquals(NUMBER_OF_DOCUMENTS, cursor.length());
}
@Test
public void testToArray() {
assertEquals(NUMBER_OF_DOCUMENTS, cursor.toArray().size());
assertEquals(NUMBER_OF_DOCUMENTS, cursor.toArray().size());
}
@Test
public void testToArrayWithMax() {
assertEquals(9, cursor.toArray(9).size());
assertEquals(NUMBER_OF_DOCUMENTS, cursor.toArray().size());
}
@Test
public void testIterationCount() {
assertEquals(NUMBER_OF_DOCUMENTS, cursor.itcount());
}
@Test
public void testCount() {
assertEquals(NUMBER_OF_DOCUMENTS, cursor.count());
assertEquals(1, collection.find(new BasicDBObject("_id", 1)).count());
}
@Test
public void testGetKeysWanted() {
assertNull(cursor.getKeysWanted());
DBObject keys = new BasicDBObject("x", 1);
DBCursor cursorWithKeys = collection.find(new BasicDBObject(), keys);
assertEquals(keys, cursorWithKeys.getKeysWanted());
}
@Test
public void testGetQuery() {
assertEquals(new BasicDBObject(), cursor.getQuery());
DBObject query = new BasicDBObject("x", 1);
DBCursor cursorWithQuery = collection.find(query);
assertEquals(query, cursorWithQuery.getQuery());
}
@Test
public void testReadPreference() {
assertEquals(ReadPreference.primary(), cursor.getReadPreference());
cursor.setReadPreference(ReadPreference.secondary());
assertEquals(ReadPreference.secondary(), cursor.getReadPreference());
}
@Test
public void testConstructor() {
DBObject query = new BasicDBObject("x", 1);
DBObject keys = new BasicDBObject("x", 1).append("y", 1);
DBCursor local = new DBCursor(collection, query, keys, ReadPreference.secondary());
assertEquals(ReadPreference.secondary(), local.getReadPreference());
assertEquals(query, local.getQuery());
assertEquals(keys, local.getKeysWanted());
}
@Test
public void testMaxScan() {
countResults(new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.addSpecial("$maxScan", 4), 4);
countResults(new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary()).maxScan(4), 4);
}
@Test
public void testMax() {
countResults(new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.addSpecial("$max", new BasicDBObject("x", 4)), 4);
countResults(new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.max(new BasicDBObject("x", 4)), 4);
}
@Test
public void testMin() {
countResults(new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.addSpecial("$min", new BasicDBObject("x", 4)), 6);
countResults(new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.min(new BasicDBObject("x", 4)), 6);
}
@Test
public void testReturnKey() {
DBCursor cursor = new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.addSpecial("$returnKey", true);
try {
while (cursor.hasNext()) {
Assert.assertNull(cursor.next()
.get("_id"));
}
} finally {
cursor.close();
}
cursor = new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.returnKey();
try {
while (cursor.hasNext()) {
Assert.assertNull(cursor.next()
.get("_id"));
}
} finally {
cursor.close();
}
}
@Test
public void testShowDiskLoc() {
String fieldName = serverVersionAtLeast(3, 2) ? "$recordId" : "$diskLoc";
DBCursor cursor = new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.addSpecial("$showDiskLoc", true);
try {
while (cursor.hasNext()) {
DBObject next = cursor.next();
assertNotNull(next.toString(), next.get(fieldName));
}
} finally {
cursor.close();
}
cursor = new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.showDiskLoc();
try {
while (cursor.hasNext()) {
DBObject next = cursor.next();
assertNotNull(next.toString(), next.get(fieldName));
}
} finally {
cursor.close();
}
}
@Test
public void testSnapshot() {
DBCursor cursor = new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.addSpecial("$snapshot", true);
try {
while (cursor.hasNext()) {
cursor.next();
}
} finally {
cursor.close();
}
}
private void countResults(final DBCursor cursor, final int expected) {
int count = 0;
while (cursor.hasNext()) {
cursor.next();
count++;
}
cursor.close();
assertEquals(expected, count);
}
@Test
public void testSettingACommentInsertsCommentIntoProfileCollectionWhenProfilingIsTurnedOn() {
assumeThat(isSharded(), is(false));
// given
String expectedComment = "test comment";
DBCollection profileCollection = database.getCollection("system.profile");
profileCollection.drop();
database.command(new BasicDBObject("profile", 2));
try {
// when
DBCursor cursor = new DBCursor(collection, new BasicDBObject(), new BasicDBObject(), ReadPreference.primary())
.comment(expectedComment);
while (cursor.hasNext()) {
cursor.next();
}
// then
assertEquals(1, profileCollection.count());
DBObject profileDocument = profileCollection.findOne();
if (serverVersionAtLeast(3, 2)) {
assertEquals(expectedComment, ((DBObject) profileDocument.get("query")).get("comment"));
} else {
assertEquals(expectedComment, ((DBObject) profileDocument.get("query")).get("$comment"));
}
} finally {
database.command(new BasicDBObject("profile", 0));
profileCollection.drop();
}
}
@Test
public void testShouldReturnOnlyTheFieldThatWasInTheIndexUsedForTheFindWhenReturnKeyIsUsed() {
// Given
// put some documents into the collection
for (int i = 0; i < NUMBER_OF_DOCUMENTS; i++) {
collection.insert(new BasicDBObject("y", i).append("someOtherKey", "someOtherValue"));
}
//set an index on the field "y"
collection.createIndex(new BasicDBObject("y", 1));
// When
// find a document by using a search on the field in the index
DBCursor cursor = collection.find(new BasicDBObject("y", 7))
.returnKey();
// Then
DBObject foundItem = cursor.next();
assertThat("There should only be one field in the resulting document", foundItem.keySet().size(), is(1));
assertThat("This should be the 'y' field with its value", (Integer) foundItem.get("y"), is(7));
}
@Test
public void testMaxTimeForIterator() {
assumeThat(serverVersionAtLeast(2, 6), is(true));
enableMaxTimeFailPoint();
DBCursor cursor = new DBCursor(collection, new BasicDBObject("x", 1), new BasicDBObject(), ReadPreference.primary());
cursor.maxTime(1, TimeUnit.SECONDS);
try {
cursor.hasNext();
fail("Show have thrown");
} catch (MongoExecutionTimeoutException e) {
assertEquals(50, e.getCode());
} finally {
disableMaxTimeFailPoint();
}
}
@Test
public void testMaxTimeForIterable() {
assumeThat(isSharded(), is(false));
assumeThat(serverVersionAtLeast(2, 6), is(true));
enableMaxTimeFailPoint();
DBCursor cursor = new DBCursor(collection, new BasicDBObject("x", 1), new BasicDBObject(), ReadPreference.primary());
cursor.maxTime(1, TimeUnit.SECONDS);
try {
cursor.iterator().hasNext();
fail("Show have thrown");
} catch (MongoExecutionTimeoutException e) {
assertEquals(50, e.getCode());
} finally {
disableMaxTimeFailPoint();
}
}
@Test
public void testMaxTimeForOne() {
assumeThat(isSharded(), is(false));
assumeThat(serverVersionAtLeast(2, 6), is(true));
enableMaxTimeFailPoint();
DBCursor cursor = new DBCursor(collection, new BasicDBObject("x", 1), new BasicDBObject(), ReadPreference.primary());
cursor.maxTime(1, TimeUnit.SECONDS);
try {
cursor.one();
fail("Show have thrown");
} catch (MongoExecutionTimeoutException e) {
assertEquals(50, e.getCode());
} finally {
disableMaxTimeFailPoint();
}
}
@Test
public void testMaxTimeForCount() {
assumeThat(isSharded(), is(false));
assumeThat(serverVersionAtLeast(2, 6), is(true));
enableMaxTimeFailPoint();
DBCursor cursor = new DBCursor(collection, new BasicDBObject("x", 1), new BasicDBObject(), ReadPreference.primary());
cursor.maxTime(1, TimeUnit.SECONDS);
try {
cursor.count();
fail("Show have thrown");
} catch (MongoExecutionTimeoutException e) {
assertEquals(50, e.getCode());
} finally {
disableMaxTimeFailPoint();
}
}
@Test
public void testMaxTimeForSize() {
assumeThat(isSharded(), is(false));
assumeThat(serverVersionAtLeast(2, 6), is(true));
enableMaxTimeFailPoint();
DBCursor cursor = new DBCursor(collection, new BasicDBObject("x", 1), new BasicDBObject(), ReadPreference.primary());
cursor.maxTime(1, TimeUnit.SECONDS);
try {
cursor.size();
fail("Show have thrown");
} catch (MongoExecutionTimeoutException e) {
assertEquals(50, e.getCode());
} finally {
disableMaxTimeFailPoint();
}
}
@Test(expected = UnsupportedOperationException.class)
public void exhaustOptionShouldThrowUnsupportedOperationException() {
DBCursor cursor = new DBCursor(collection, new BasicDBObject("x", 1), new BasicDBObject(), ReadPreference.primary());
cursor.addOption(Bytes.QUERYOPTION_EXHAUST);
}
@Test
public void testPropertyMutability() {
DBCursor cursor = new DBCursor(collection, new BasicDBObject("x", 1), new BasicDBObject("y", 1), ReadPreference.primary());
cursor.getQuery().put("z", 2);
cursor.getKeysWanted().put("v", 1);
assertTrue(cursor.getQuery().containsField("z"));
assertTrue(cursor.getKeysWanted().containsField("v"));
}
@Test
public void testClose() {
cursor.next();
cursor.close();
try {
cursor.next();
fail();
} catch (IllegalStateException e) {
// all good
}
}
}