// client.cpp
/*
* Copyright (C) 2010 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#include "mongo/platform/basic.h"
#include "mongo/client/dbclientcursor.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/db/catalog/database.h"
#include "mongo/db/client.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/dbtests/dbtests.h"
namespace ClientTests {
using std::unique_ptr;
using std::string;
using std::vector;
class Base {
public:
Base(string coll) : _ns("test." + coll) {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.dropDatabase("test");
}
virtual ~Base() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.dropCollection(_ns);
}
const char* ns() {
return _ns.c_str();
}
const string _ns;
};
class DropIndex : public Base {
public:
DropIndex() : Base("dropindex") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.insert(ns(), BSON("x" << 2));
ASSERT_EQUALS(1u, db.getIndexSpecs(ns()).size());
ASSERT_OK(dbtests::createIndex(&opCtx, ns(), BSON("x" << 1)));
ASSERT_EQUALS(2u, db.getIndexSpecs(ns()).size());
db.dropIndex(ns(), BSON("x" << 1));
ASSERT_EQUALS(1u, db.getIndexSpecs(ns()).size());
ASSERT_OK(dbtests::createIndex(&opCtx, ns(), BSON("x" << 1)));
ASSERT_EQUALS(2u, db.getIndexSpecs(ns()).size());
db.dropIndexes(ns());
ASSERT_EQUALS(1u, db.getIndexSpecs(ns()).size());
}
};
/**
* Check that nIndexes is incremented correctly when an index builds (and that it is not
* incremented when an index fails to build), system.indexes has an entry added (or not), and
* system.namespaces has a doc added (or not).
*/
class BuildIndex : public Base {
public:
BuildIndex() : Base("buildIndex") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
OldClientWriteContext ctx(&opCtx, ns());
DBDirectClient db(&opCtx);
db.insert(ns(), BSON("x" << 1 << "y" << 2));
db.insert(ns(), BSON("x" << 2 << "y" << 2));
Collection* collection = ctx.getCollection();
ASSERT(collection);
IndexCatalog* indexCatalog = collection->getIndexCatalog();
ASSERT_EQUALS(1, indexCatalog->numIndexesReady(&opCtx));
// _id index
ASSERT_EQUALS(1U, db.getIndexSpecs(ns()).size());
ASSERT_EQUALS(ErrorCodes::DuplicateKey,
dbtests::createIndex(&opCtx, ns(), BSON("y" << 1), true));
ASSERT_EQUALS(1, indexCatalog->numIndexesReady(&opCtx));
ASSERT_EQUALS(1U, db.getIndexSpecs(ns()).size());
ASSERT_OK(dbtests::createIndex(&opCtx, ns(), BSON("x" << 1), true));
ASSERT_EQUALS(2, indexCatalog->numIndexesReady(&opCtx));
ASSERT_EQUALS(2U, db.getIndexSpecs(ns()).size());
}
};
class CS_10 : public Base {
public:
CS_10() : Base("CS_10") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
const string longs(770, 'c');
for (int i = 0; i < 1111; ++i) {
db.insert(ns(), BSON("a" << i << "b" << longs));
}
ASSERT_OK(dbtests::createIndex(&opCtx, ns(), BSON("a" << 1 << "b" << 1)));
unique_ptr c = db.query(ns(), Query().sort(BSON("a" << 1 << "b" << 1)));
ASSERT_EQUALS(1111, c->itcount());
}
};
class PushBack : public Base {
public:
PushBack() : Base("PushBack") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
for (int i = 0; i < 10; ++i) {
db.insert(ns(), BSON("i" << i));
}
unique_ptr c = db.query(ns(), Query().sort(BSON("i" << 1)));
BSONObj o = c->next();
ASSERT(c->more());
ASSERT_EQUALS(9, c->objsLeftInBatch());
ASSERT(c->moreInCurrentBatch());
c->putBack(o);
ASSERT(c->more());
ASSERT_EQUALS(10, c->objsLeftInBatch());
ASSERT(c->moreInCurrentBatch());
o = c->next();
BSONObj o2 = c->next();
BSONObj o3 = c->next();
c->putBack(o3);
c->putBack(o2);
c->putBack(o);
for (int i = 0; i < 10; ++i) {
o = c->next();
ASSERT_EQUALS(i, o["i"].number());
}
ASSERT(!c->more());
ASSERT_EQUALS(0, c->objsLeftInBatch());
ASSERT(!c->moreInCurrentBatch());
c->putBack(o);
ASSERT(c->more());
ASSERT_EQUALS(1, c->objsLeftInBatch());
ASSERT(c->moreInCurrentBatch());
ASSERT_EQUALS(1, c->itcount());
}
};
class Create : public Base {
public:
Create() : Base("Create") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createCollection("unittests.clienttests.create", 4096, true);
BSONObj info;
ASSERT(db.runCommand("unittests",
BSON("collstats"
<< "clienttests.create"),
info));
}
};
class ConnectionStringTests {
public:
void run() {
{
ConnectionString s("a/b,c,d", ConnectionString::SET);
ASSERT_EQUALS(ConnectionString::SET, s.type());
ASSERT_EQUALS("a", s.getSetName());
vector v = s.getServers();
ASSERT_EQUALS(3U, v.size());
ASSERT_EQUALS("b", v[0].host());
ASSERT_EQUALS("c", v[1].host());
ASSERT_EQUALS("d", v[2].host());
}
}
};
class CreateSimpleV1Index : public Base {
public:
CreateSimpleV1Index() : Base("CreateSimpleV1Index") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(ns(), IndexSpec().addKey("aField").version(1));
}
};
class CreateSimpleNamedV1Index : public Base {
public:
CreateSimpleNamedV1Index() : Base("CreateSimpleNamedV1Index") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(ns(), IndexSpec().addKey("aField").version(1).name("aFieldV1Index"));
}
};
class CreateCompoundNamedV1Index : public Base {
public:
CreateCompoundNamedV1Index() : Base("CreateCompoundNamedV1Index") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(ns(),
IndexSpec()
.addKey("aField")
.addKey("bField", IndexSpec::kIndexTypeDescending)
.version(1)
.name("aFieldbFieldV1Index"));
}
};
class CreateUniqueSparseDropDupsIndexInBackground : public Base {
public:
CreateUniqueSparseDropDupsIndexInBackground()
: Base("CreateUniqueSparseDropDupsIndexInBackground") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(
ns(), IndexSpec().addKey("aField").background().unique().sparse().dropDuplicates());
}
};
class CreateComplexTextIndex : public Base {
public:
CreateComplexTextIndex() : Base("CreateComplexTextIndex") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(ns(),
IndexSpec()
.addKey("aField", IndexSpec::kIndexTypeText)
.addKey("bField", IndexSpec::kIndexTypeText)
.textWeights(BSON("aField" << 100))
.textDefaultLanguage("spanish")
.textLanguageOverride("lang")
.textIndexVersion(2));
}
};
class Create2DIndex : public Base {
public:
Create2DIndex() : Base("Create2DIndex") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(ns(),
IndexSpec()
.addKey("aField", IndexSpec::kIndexTypeGeo2D)
.geo2DBits(20)
.geo2DMin(-120.0)
.geo2DMax(120.0));
}
};
class CreateHaystackIndex : public Base {
public:
CreateHaystackIndex() : Base("CreateHaystackIndex") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(ns(),
IndexSpec()
.addKey("aField", IndexSpec::kIndexTypeGeoHaystack)
.addKey("otherField", IndexSpec::kIndexTypeDescending)
.geoHaystackBucketSize(1.0));
}
};
class Create2DSphereIndex : public Base {
public:
Create2DSphereIndex() : Base("Create2DSphereIndex") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(ns(),
IndexSpec()
.addKey("aField", IndexSpec::kIndexTypeGeo2DSphere)
.geo2DSphereIndexVersion(2));
}
};
class CreateHashedIndex : public Base {
public:
CreateHashedIndex() : Base("CreateHashedIndex") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(ns(), IndexSpec().addKey("aField", IndexSpec::kIndexTypeHashed));
}
};
class CreateIndexFailure : public Base {
public:
CreateIndexFailure() : Base("CreateIndexFailure") {}
void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
OperationContext& opCtx = *opCtxPtr;
DBDirectClient db(&opCtx);
db.createIndex(ns(), IndexSpec().addKey("aField"));
ASSERT_THROWS(db.createIndex(ns(), IndexSpec().addKey("aField").unique()), UserException);
}
};
class All : public Suite {
public:
All() : Suite("client") {}
void setupTests() {
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
add();
}
};
SuiteInstance all;
}