/*
* 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.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import static com.mongodb.ClusterFixture.serverVersionAtLeast;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeThat;
public class DBCursorOldTest extends DatabaseTestCase {
@Test
public void testGetServerAddressLoop() {
insertTestData(collection, 10);
DBCursor cur = collection.find();
while (cur.hasNext()) {
cur.next();
assertNotNull(cur.getServerAddress());
}
}
@Test
public void testGetServerAddressQuery() {
insertTestData(collection, 10);
DBCursor cur = collection.find();
cur.hasNext();
assertNotNull(cur.getServerAddress());
}
@Test
public void testGetServerAddressQuery1() {
insertTestData(collection, 10);
DBCursor cur = collection.find(new BasicDBObject("x", 9));
cur.hasNext();
assertNotNull(cur.getServerAddress());
}
@Test
public void testCount() {
assertEquals(collection.find().count(), 0);
BasicDBObject obj = new BasicDBObject();
obj.put("x", "foo");
collection.insert(obj);
assertEquals(1, collection.find().count());
}
@Test
public void testSnapshot() {
insertTestData(collection, 100);
assertEquals(100, collection.find().count());
assertEquals(100, collection.find().toArray().size());
assertEquals(100, collection.find().snapshot().count());
assertEquals(100, collection.find().snapshot().toArray().size());
assertEquals(100, collection.find().snapshot().limit(50).count());
assertEquals(50, collection.find().snapshot().limit(50).toArray().size());
}
@Test
public void testOptions() {
DBCursor dbCursor = collection.find();
assertEquals(0, dbCursor.getOptions());
dbCursor.setOptions(Bytes.QUERYOPTION_TAILABLE);
assertEquals(Bytes.QUERYOPTION_TAILABLE, dbCursor.getOptions());
dbCursor.addOption(Bytes.QUERYOPTION_SLAVEOK);
assertEquals(Bytes.QUERYOPTION_TAILABLE | Bytes.QUERYOPTION_SLAVEOK, dbCursor.getOptions());
dbCursor.resetOptions();
assertEquals(0, dbCursor.getOptions());
}
@Test
public void testTailable() {
DBCollection c = database.getCollection("tail1");
c.drop();
database.createCollection("tail1", new BasicDBObject("capped", true).append("size", 10000));
DBObject firstDBObject = new BasicDBObject("x", 1);
DBObject secondDBObject = new BasicDBObject("x", 2);
DBCursor cur = c.find()
.sort(new BasicDBObject("$natural", 1))
.addOption(Bytes.QUERYOPTION_TAILABLE);
c.save(firstDBObject, WriteConcern.ACKNOWLEDGED);
assertEquals(firstDBObject, cur.tryNext());
assertEquals(firstDBObject, cur.curr());
assertEquals(1, cur.numSeen());
assertEquals(null, cur.tryNext());
assertEquals(firstDBObject, cur.curr());
assertEquals(1, cur.numSeen());
c.save(secondDBObject, WriteConcern.ACKNOWLEDGED);
assertEquals(secondDBObject, cur.tryNext());
assertEquals(secondDBObject, cur.curr());
assertEquals(2, cur.numSeen());
assertEquals(null, cur.tryNext());
assertEquals(secondDBObject, cur.curr());
assertEquals(2, cur.numSeen());
}
@Test
public void testTailableImplicitAwaitOnHasNext() throws ExecutionException, TimeoutException, InterruptedException {
DBCollection c = database.getCollection("tail1");
c.drop();
database.createCollection("tail1", new BasicDBObject("capped", true).append("size", 10000));
for (int i = 0; i < 10; i++) {
c.save(new BasicDBObject("x", i), WriteConcern.ACKNOWLEDGED);
}
final DBCursor cur = c.find()
.sort(new BasicDBObject("$natural", 1))
.addOption(Bytes.QUERYOPTION_TAILABLE);
final CountDownLatch latch = new CountDownLatch(1);
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// the following call will block on the last hasNext
int i = 0;
while (cur.hasNext()) {
DBObject obj = cur.next();
i++;
if (i == 10) {
latch.countDown();
} else if (i > 10) {
return (Integer) obj.get("x");
}
}
return null;
}
};
ExecutorService es = Executors.newSingleThreadExecutor();
Future<Integer> future = es.submit(callable);
latch.await(5, SECONDS);
// this doc should unblock thread
c.save(new BasicDBObject("x", 10), WriteConcern.ACKNOWLEDGED);
assertEquals(10, (long) future.get(5, SECONDS));
}
@Test
public void testTailableImplicitAwaitOnNext() throws ExecutionException, TimeoutException, InterruptedException {
DBCollection c = database.getCollection("tail1");
c.drop();
database.createCollection("tail1", new BasicDBObject("capped", true).append("size", 10000));
for (int i = 0; i < 10; i++) {
c.save(new BasicDBObject("x", i), WriteConcern.ACKNOWLEDGED);
}
final DBCursor cur = c.find()
.sort(new BasicDBObject("$natural", 1))
.addOption(Bytes.QUERYOPTION_TAILABLE);
final CountDownLatch latch = new CountDownLatch(1);
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// the following call will block on the last hasNext
int i = 0;
while (i < 11) {
DBObject obj = cur.next();
i++;
if (i == 10) {
latch.countDown();
} else if (i > 10) {
return (Integer) obj.get("x");
}
}
return null;
}
};
ExecutorService es = Executors.newSingleThreadExecutor();
Future<Integer> future = es.submit(callable);
latch.await(5, SECONDS);
// this doc should unblock thread
c.save(new BasicDBObject("x", 10), WriteConcern.ACKNOWLEDGED);
assertEquals(10, (long) future.get(5, SECONDS));
}
@Test
public void shouldSupportTryNextOnTailableCursors() {
DBCollection c = database.getCollection("tail1");
c.drop();
database.createCollection("tail1", new BasicDBObject("capped", true).append("size", 10000));
c.save(new BasicDBObject("x", 1), WriteConcern.ACKNOWLEDGED);
DBCursor cur = c.find()
.sort(new BasicDBObject("$natural", 1))
.addOption(Bytes.QUERYOPTION_TAILABLE);
try {
cur.tryNext();
} catch (IllegalArgumentException e) {
fail();
}
}
@Test
public void shouldSupportTryNextOnTailableAwaitCursors() {
DBCollection c = database.getCollection("tail1");
c.drop();
database.createCollection("tail1", new BasicDBObject("capped", true).append("size", 10000));
c.save(new BasicDBObject("x", 1), WriteConcern.ACKNOWLEDGED);
DBCursor cur = c.find()
.sort(new BasicDBObject("$natural", 1))
.addOption(Bytes.QUERYOPTION_TAILABLE)
.addOption(Bytes.QUERYOPTION_AWAITDATA);
try {
cur.tryNext();
} catch (IllegalArgumentException e) {
fail();
}
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionOnTryNextForNonTailableCursors() {
DBCollection c = database.getCollection("tail1");
c.drop();
database.createCollection("tail1", new BasicDBObject("capped", true).append("size", 10000));
c.save(new BasicDBObject("x", 1), WriteConcern.ACKNOWLEDGED);
DBCursor cur = c.find()
.sort(new BasicDBObject("$natural", 1))
.addOption(Bytes.QUERYOPTION_AWAITDATA);
cur.tryNext();
}
@Test
public void testExplain() {
assumeThat(serverVersionAtLeast(3, 0), is(false));
insertTestData(collection, 100);
DBObject q = BasicDBObjectBuilder.start().push("x").add("$gt", 50).get();
assertEquals(49, collection.find(q).count());
assertEquals(49, collection.find(q).itcount());
assertEquals(49, collection.find(q).toArray().size());
assertEquals(49, collection.find(q).itcount());
assertEquals(20, collection.find(q).limit(20).itcount());
assertEquals(20, collection.find(q).limit(-20).itcount());
collection.createIndex(new BasicDBObject("x", 1));
assertEquals(49, collection.find(q).count());
assertEquals(49, collection.find(q).toArray().size());
assertEquals(49, collection.find(q).itcount());
assertEquals(20, collection.find(q).limit(20).itcount());
assertEquals(20, collection.find(q).limit(-20).itcount());
assertEquals(49, collection.find(q).explain().get("n"));
assertEquals(20, collection.find(q).limit(20).explain().get("n"));
assertEquals(20, collection.find(q).limit(-20).explain().get("n"));
}
@Test
public void testBatchWithLimit() {
insertTestData(collection, 100);
assertEquals(50, collection.find().limit(50).itcount());
assertEquals(50, collection.find().batchSize(5).limit(50).itcount());
}
@Test
public void testSpecial() {
insertTestData(collection, 3);
collection.createIndex(new BasicDBObject("x", 1));
for (final DBObject o : collection.find().sort(new BasicDBObject("x", 1)).addSpecial("$returnKey", 1)) {
assertTrue(o.get("_id") == null);
}
for (final DBObject o : collection.find().sort(new BasicDBObject("x", 1))) {
assertTrue(o.get("_id") != null);
}
}
@Test
public void testUpsert() {
collection.update(new BasicDBObject("page", "/"), new BasicDBObject("$inc", new BasicDBObject("count", 1)), true, false);
collection.update(new BasicDBObject("page", "/"), new BasicDBObject("$inc", new BasicDBObject("count", 1)), true, false);
assertEquals(1, collection.getCount());
assertEquals(2, collection.findOne().get("count"));
}
@Test
public void testLimitAndBatchSize() {
insertTestData(collection, 1000);
DBObject q = BasicDBObjectBuilder.start().push("x").add("$lt", 200).get();
DBCursor cur = collection.find(q);
assertEquals(0, cur.getCursorId());
assertEquals(200, cur.itcount());
cur = collection.find(q).limit(50);
assertEquals(0, cur.getCursorId());
assertEquals(50, cur.itcount());
cur = collection.find(q).batchSize(50);
assertEquals(0, cur.getCursorId());
assertEquals(200, cur.itcount());
cur = collection.find(q).batchSize(100).limit(50);
assertEquals(0, cur.getCursorId());
assertEquals(50, cur.itcount());
cur = collection.find(q).batchSize(-40);
assertEquals(0, cur.getCursorId());
assertEquals(40, cur.itcount());
cur = collection.find(q).limit(-100);
assertEquals(0, cur.getCursorId());
assertEquals(100, cur.itcount());
cur = collection.find(q).batchSize(-40).limit(20);
assertEquals(0, cur.getCursorId());
assertEquals(20, cur.itcount());
cur = collection.find(q).batchSize(-20).limit(100);
assertEquals(0, cur.getCursorId());
assertEquals(20, cur.itcount());
}
@Test
public void testCurrentObjectAndNumSeen() {
for (int i = 1; i < 100; i++) {
collection.save(new BasicDBObject("x", i));
}
DBCursor cur = collection.find().sort(new BasicDBObject("x", 1));
while (cur.hasNext()) {
DBObject current = cur.next();
int num = (Integer) current.get("x");
assertEquals(current, cur.curr());
assertEquals(num, cur.numSeen());
}
}
@Test
public void testSort() {
for (int i = 0; i < 1000; i++) {
collection.save(new BasicDBObject("x", i).append("y", 1000 - i));
}
//x ascending
DBCursor cur = collection.find().sort(new BasicDBObject("x", 1));
int curmax = -100;
while (cur.hasNext()) {
int val = (Integer) cur.next().get("x");
assertTrue(val > curmax);
curmax = val;
}
//x desc
cur = collection.find().sort(new BasicDBObject("x", -1));
curmax = 9999;
while (cur.hasNext()) {
int val = (Integer) cur.next().get("x");
assertTrue(val < curmax);
curmax = val;
}
//query and sort
cur = collection.find(QueryBuilder.start("x").greaterThanEquals(500).get()).sort(new BasicDBObject("y", 1));
assertEquals(500, cur.count());
curmax = -100;
while (cur.hasNext()) {
int val = (Integer) cur.next().get("y");
assertTrue(val > curmax);
curmax = val;
}
}
@Test(expected = NoSuchElementException.class)
public void testShouldThrowNoSuchElementException() {
DBCursor cursor = collection.find();
cursor.next();
}
private void insertTestData(final DBCollection dbCollection, final int numberOfDocuments) {
List<DBObject> documents = new ArrayList<DBObject>();
for (int i = 0; i < numberOfDocuments; i++) {
documents.add(new BasicDBObject("x", i));
}
dbCollection.insert(documents);
}
//TODO: why is this commented out?
// @Test
// public void testHasFinalizer() throws UnknownHostException, UnknownHostException {
// DBCollection c = database.getCollection("HasFinalizerTest");
// c.drop();
//
// for (int i = 0; i < 1000; i++) {
// c.save(new BasicDBObject("_id", i), WriteConcern.ACKNOWLEDGED);
// }
//
// // finalizer is on by default so after calling hasNext should report that it has one
// DBCursor cursor = c.find();
// assertFalse(cursor.hasFinalizer());
// cursor.hasNext();
// assertTrue(cursor.hasFinalizer());
// cursor.close();
//
// // no finalizer if there is no cursor, as there should not be for a query with only one result
// cursor = c.find(new BasicDBObject("_id", 1));
// cursor.hasNext();
// assertFalse(cursor.hasFinalizer());
// cursor.close();
//
// // no finalizer if there is no cursor, as there should not be for a query with negative batch size
// cursor = c.find();
// cursor.batchSize(-1);
// cursor.hasNext();
// assertFalse(cursor.hasFinalizer());
// cursor.close();
//
// // finally, no finalizer if disabled in mongo options
// MongoClientOptions mongoOptions = MongoClientOptions.builder().build();
// mongoOptions.cursorFinalizerEnabled = false;
// Mongo m = new MongoClient("127.0.0.1", mongoOptions);
// try {
// c = m.getDB(cleanupDB).getCollection("HasFinalizerTest");
// cursor = c.find();
// cursor.hasNext();
// assertFalse(cursor.hasFinalizer());
// cursor.close();
// } finally {
// m.close();
// }
// }
}