summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/dbtests/mock/mock_dbclient_connection.cpp25
-rw-r--r--src/mongo/dbtests/mock/mock_dbclient_connection.h10
-rw-r--r--src/mongo/dbtests/mock/mock_dbclient_cursor.cpp34
-rw-r--r--src/mongo/dbtests/mock/mock_dbclient_cursor.h40
-rw-r--r--src/mongo/dbtests/mock/mock_remote_db_server.cpp11
-rw-r--r--src/mongo/dbtests/mock/mock_remote_db_server.h14
-rw-r--r--src/mongo/dbtests/mock/mock_replica_set.cpp19
-rw-r--r--src/mongo/dbtests/mock/mock_replica_set.h9
-rw-r--r--src/mongo/dbtests/mock_dbclient_conn_test.cpp48
-rw-r--r--src/mongo/dbtests/mock_replica_set_test.cpp30
10 files changed, 227 insertions, 13 deletions
diff --git a/src/mongo/dbtests/mock/mock_dbclient_connection.cpp b/src/mongo/dbtests/mock/mock_dbclient_connection.cpp
index 69f7779bafc..a8d76723ed9 100644
--- a/src/mongo/dbtests/mock/mock_dbclient_connection.cpp
+++ b/src/mongo/dbtests/mock/mock_dbclient_connection.cpp
@@ -15,6 +15,7 @@
#include "mongo/dbtests/mock/mock_dbclient_connection.h"
+#include "mongo/dbtests/mock/mock_dbclient_cursor.h"
#include "mongo/util/net/sock.h"
#include "mongo/util/time_support.h"
@@ -24,11 +25,13 @@ using std::string;
using std::vector;
namespace mongo_test {
- MockDBClientConnection::MockDBClientConnection(MockRemoteDBServer* remoteServer):
+ MockDBClientConnection::MockDBClientConnection(MockRemoteDBServer* remoteServer,
+ bool autoReconnect):
_remoteServerInstanceID(remoteServer->getInstanceID()),
_remoteServer(remoteServer),
_isFailed(false),
- _sockCreationTime(mongo::curTimeMicros64()) {
+ _sockCreationTime(mongo::curTimeMicros64()),
+ _autoReconnect(autoReconnect) {
}
MockDBClientConnection::~MockDBClientConnection() {
@@ -36,6 +39,8 @@ namespace mongo_test {
bool MockDBClientConnection::runCommand(const string& dbname, const BSONObj& cmdObj,
BSONObj &info, int options, const mongo::AuthenticationTable* auth) {
+ checkConnection();
+
try {
return _remoteServer->runCommand(_remoteServerInstanceID, dbname, cmdObj,
info, options, auth);
@@ -55,9 +60,15 @@ namespace mongo_test {
const BSONObj* fieldsToReturn,
int queryOptions,
int batchSize) {
+ checkConnection();
+
try {
- return _remoteServer->query(_remoteServerInstanceID, ns, query, nToReturn,
- nToSkip, fieldsToReturn, queryOptions, batchSize);
+ mongo::BSONArray result(_remoteServer->query(_remoteServerInstanceID, ns, query,
+ nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize));
+
+ std::auto_ptr<mongo::DBClientCursor> cursor;
+ cursor.reset(new MockDBClientCursor(this, result));
+ return cursor;
}
catch (const mongo::SocketException&) {
_isFailed = true;
@@ -140,4 +151,10 @@ namespace mongo_test {
double MockDBClientConnection::getSoTimeout() const {
return 0;
}
+
+ void MockDBClientConnection::checkConnection() {
+ if (_isFailed && _autoReconnect) {
+ _remoteServerInstanceID = _remoteServer->getInstanceID();
+ }
+ }
}
diff --git a/src/mongo/dbtests/mock/mock_dbclient_connection.h b/src/mongo/dbtests/mock/mock_dbclient_connection.h
index e09736f7ecb..4fed28b36ca 100644
--- a/src/mongo/dbtests/mock/mock_dbclient_connection.h
+++ b/src/mongo/dbtests/mock/mock_dbclient_connection.h
@@ -37,8 +37,11 @@ namespace mongo_test {
* @param remoteServer the remote server to connect to. The caller is
* responsible for making sure that the life of remoteServer is
* longer than this connection.
+ * @param autoReconnect will automatically re-establish connection the
+ * next time an operation is requested when the last operation caused
+ * this connection to fall into a failed state.
*/
- MockDBClientConnection(MockRemoteDBServer* remoteServer);
+ MockDBClientConnection(MockRemoteDBServer* remoteServer, bool autoReconnect = false);
virtual ~MockDBClientConnection();
//
@@ -94,9 +97,12 @@ namespace mongo_test {
bool lazySupported() const;
private:
- const MockRemoteDBServer::InstanceID _remoteServerInstanceID;
+ void checkConnection();
+
+ MockRemoteDBServer::InstanceID _remoteServerInstanceID;
MockRemoteDBServer* _remoteServer;
bool _isFailed;
uint64_t _sockCreationTime;
+ bool _autoReconnect;
};
}
diff --git a/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp b/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp
new file mode 100644
index 00000000000..a18f63eba75
--- /dev/null
+++ b/src/mongo/dbtests/mock/mock_dbclient_cursor.cpp
@@ -0,0 +1,34 @@
+//@file dbclientmockcursor.h
+
+/* Copyright 2012 10gen 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.
+ */
+
+#include "mongo/dbtests/mock/mock_dbclient_cursor.h"
+
+namespace mongo_test {
+ MockDBClientCursor::MockDBClientCursor(mongo::DBClientBase* client,
+ const mongo::BSONArray& resultSet):
+ mongo::DBClientCursor(client, "", 0, 0, 0) {
+ _cursor.reset(new mongo::DBClientMockCursor(resultSet));
+ }
+
+ bool MockDBClientCursor::more() {
+ return _cursor->more();
+ }
+
+ mongo::BSONObj MockDBClientCursor::next() {
+ return _cursor->next();
+ }
+}
diff --git a/src/mongo/dbtests/mock/mock_dbclient_cursor.h b/src/mongo/dbtests/mock/mock_dbclient_cursor.h
new file mode 100644
index 00000000000..3779592a014
--- /dev/null
+++ b/src/mongo/dbtests/mock/mock_dbclient_cursor.h
@@ -0,0 +1,40 @@
+//@file dbclientmockcursor.h
+
+/* Copyright 2012 10gen 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.
+ */
+
+#pragma once
+
+#include "mongo/client/dbclientcursor.h"
+#include "mongo/client/dbclientmockcursor.h"
+
+namespace mongo_test {
+
+ /**
+ * Simple adapter class for mongo::DBClientMockCursor to mongo::DBClientCursor.
+ * Only supports more and next, the behavior of other operations are undefined.
+ */
+ class MockDBClientCursor: public mongo::DBClientCursor {
+ public:
+ MockDBClientCursor(mongo::DBClientBase* client,
+ const mongo::BSONArray& mockCollection);
+
+ bool more();
+ mongo::BSONObj next();
+
+ private:
+ boost::scoped_ptr<mongo::DBClientMockCursor> _cursor;
+ };
+}
diff --git a/src/mongo/dbtests/mock/mock_remote_db_server.cpp b/src/mongo/dbtests/mock/mock_remote_db_server.cpp
index b4296515bf8..8f4fb0953c8 100644
--- a/src/mongo/dbtests/mock/mock_remote_db_server.cpp
+++ b/src/mongo/dbtests/mock/mock_remote_db_server.cpp
@@ -106,6 +106,11 @@ namespace mongo_test {
_cmdMap[cmdName].reset(new CircularBSONIterator(replySequence));
}
+ void MockRemoteDBServer::setQueryReply(const mongo::BSONArray& resultSet) {
+ scoped_spinlock sLock(_lock);
+ _queryReply = mongo::BSONArray(resultSet.copy());
+ }
+
bool MockRemoteDBServer::runCommand(MockRemoteDBServer::InstanceID id,
const string& dbname,
const BSONObj& cmdObj,
@@ -147,7 +152,7 @@ namespace mongo_test {
return info["ok"].trueValue();
}
- std::auto_ptr<mongo::DBClientCursor> MockRemoteDBServer::query(
+ mongo::BSONArray MockRemoteDBServer::query(
MockRemoteDBServer::InstanceID id,
const string& ns,
mongo::Query query,
@@ -164,11 +169,9 @@ namespace mongo_test {
checkIfUp(id);
- std::auto_ptr<mongo::DBClientCursor> cursor;
-
scoped_spinlock sLock(_lock);
_queryCount++;
- return cursor;
+ return _queryReply;
}
mongo::ConnectionString::ConnectionType MockRemoteDBServer::type() const {
diff --git a/src/mongo/dbtests/mock/mock_remote_db_server.h b/src/mongo/dbtests/mock/mock_remote_db_server.h
index 72b28473304..6c050da8648 100644
--- a/src/mongo/dbtests/mock/mock_remote_db_server.h
+++ b/src/mongo/dbtests/mock/mock_remote_db_server.h
@@ -110,6 +110,14 @@ namespace mongo_test {
void setCommandReply(const std::string& cmdName,
const std::vector<mongo::BSONObj>& replySequence);
+ /**
+ * Sets the reply of the query.
+ *
+ * @param resultSet the array of results where each element in the array
+ * would represent a single document in the resulting cursor.
+ */
+ void setQueryReply(const mongo::BSONArray& resultSet);
+
//
// DBClientBase methods
//
@@ -118,7 +126,7 @@ namespace mongo_test {
mongo::BSONObj &info, int options = 0,
const mongo::AuthenticationTable* auth = NULL);
- std::auto_ptr<mongo::DBClientCursor> query(InstanceID id,
+ mongo::BSONArray query(InstanceID id,
const std::string &ns,
mongo::Query query = mongo::Query(),
int nToReturn = 0,
@@ -199,7 +207,11 @@ namespace mongo_test {
std::string _hostName;
long long _delayMilliSec;
+ //
+ // Mock replies
+ //
CmdToReplyObj _cmdMap;
+ mongo::BSONArray _queryReply;
//
// Op Counters
diff --git a/src/mongo/dbtests/mock/mock_replica_set.cpp b/src/mongo/dbtests/mock/mock_replica_set.cpp
index d01000b2afe..ead132d9b29 100644
--- a/src/mongo/dbtests/mock/mock_replica_set.cpp
+++ b/src/mongo/dbtests/mock/mock_replica_set.cpp
@@ -42,7 +42,17 @@ namespace mongo_test {
verify(servers.size() == 1);
const string serverName = servers.front().toString(true);
- return new MockDBClientConnection(_replSet->getNode(serverName));
+
+ MockRemoteDBServer* node = _replSet->getNode(serverName);
+
+ if (node->isRunning()) {
+ // Follow ConnectionString::connect to set autoReconnect to true
+ return new MockDBClientConnection(node, true);
+ }
+
+ // mimic ConnectionString::connect for MASTER type connection to return NULL
+ // if the destination is unreachable
+ return NULL;
}
MockReplicaSet::MockReplicaSet(const string& setName, size_t nodes):
@@ -143,6 +153,13 @@ namespace mongo_test {
_nodeMap[hostName]->shutdown();
}
+ void MockReplicaSet::kill(const vector<string>& hostList) {
+ for (vector<string>::const_iterator iter = hostList.begin();
+ iter != hostList.end(); ++iter) {
+ kill(*iter);
+ }
+ }
+
void MockReplicaSet::restore(const string& hostName) {
verify(_nodeMap.count(hostName) == 1);
_nodeMap[hostName]->reboot();
diff --git a/src/mongo/dbtests/mock/mock_replica_set.h b/src/mongo/dbtests/mock/mock_replica_set.h
index 4951b0eddda..8fb98255123 100644
--- a/src/mongo/dbtests/mock/mock_replica_set.h
+++ b/src/mongo/dbtests/mock/mock_replica_set.h
@@ -68,13 +68,20 @@ namespace mongo_test {
MockRemoteDBServer* getNode(const std::string& hostName);
/**
- * Kills a node.
+ * Kills a node belonging to this set.
*
* @param hostName the name of the replica node to kill.
*/
void kill(const std::string& hostName);
/**
+ * Kills a set of host belonging to this set.
+ *
+ * @param hostList the list of host names of the servers to kill.
+ */
+ void kill(const std::vector<std::string>& hostList);
+
+ /**
* Reboots a node.
*
* @param hostName the name of the host to reboot.
diff --git a/src/mongo/dbtests/mock_dbclient_conn_test.cpp b/src/mongo/dbtests/mock_dbclient_conn_test.cpp
index 1bd152d1f0d..68b6f7d9e75 100644
--- a/src/mongo/dbtests/mock_dbclient_conn_test.cpp
+++ b/src/mongo/dbtests/mock_dbclient_conn_test.cpp
@@ -63,6 +63,54 @@ namespace mongo_test {
}
}
+ TEST(MockDBClientConnTest, SetQueryReply) {
+ MockRemoteDBServer server("test");
+
+ {
+ MockDBClientConnection conn(&server);
+ std::auto_ptr<mongo::DBClientCursor> cursor = conn.query("test.user");
+ ASSERT(!cursor->more());
+ }
+
+ {
+ mongo::BSONArrayBuilder arrBuilder;
+ arrBuilder.append(BSON("x" << 1));
+ arrBuilder.append(BSON("y" << 2));
+ server.setQueryReply(arrBuilder.arr());
+ }
+
+ {
+ MockDBClientConnection conn(&server);
+ std::auto_ptr<mongo::DBClientCursor> cursor = conn.query("test.user");
+
+ ASSERT(cursor->more());
+ BSONObj firstDoc = cursor->next();
+ ASSERT_EQUALS(1, firstDoc["x"].numberInt());
+
+ ASSERT(cursor->more());
+ BSONObj secondDoc = cursor->next();
+ ASSERT_EQUALS(2, secondDoc["y"].numberInt());
+
+ ASSERT(!cursor->more());
+ }
+
+ // Make sure that repeated calls will still give you the same result
+ {
+ MockDBClientConnection conn(&server);
+ std::auto_ptr<mongo::DBClientCursor> cursor = conn.query("test.user");
+
+ ASSERT(cursor->more());
+ BSONObj firstDoc = cursor->next();
+ ASSERT_EQUALS(1, firstDoc["x"].numberInt());
+
+ ASSERT(cursor->more());
+ BSONObj secondDoc = cursor->next();
+ ASSERT_EQUALS(2, secondDoc["y"].numberInt());
+
+ ASSERT(!cursor->more());
+ }
+ }
+
TEST(MockDBClientConnTest, SetCmdReply) {
MockRemoteDBServer server("test");
server.setCommandReply("serverStatus", BSON("ok" << 1 << "host" << "local"));
diff --git a/src/mongo/dbtests/mock_replica_set_test.cpp b/src/mongo/dbtests/mock_replica_set_test.cpp
index f15fe8b8cc6..abbf23ac19a 100644
--- a/src/mongo/dbtests/mock_replica_set_test.cpp
+++ b/src/mongo/dbtests/mock_replica_set_test.cpp
@@ -27,6 +27,7 @@ using mongo::ConnectionString;
using std::set;
using std::string;
+using std::vector;
namespace mongo_test {
TEST(MockReplicaSetTest, SetName) {
@@ -239,5 +240,34 @@ namespace mongo_test {
ASSERT(expectedMembers == memberList);
}
+
+ TEST(MockReplicaSetTest, KillNode) {
+ MockReplicaSet replSet("n", 3);
+ const string priHostName(replSet.getPrimary());
+ replSet.kill(priHostName);
+
+ ASSERT(!replSet.getNode(priHostName)->isRunning());
+
+ const vector<string> secondaries = replSet.getSecondaries();
+ for (vector<string>::const_iterator iter = secondaries.begin();
+ iter != secondaries.end(); ++iter) {
+ ASSERT(replSet.getNode(*iter)->isRunning());
+ }
+ }
+
+ TEST(MockReplicaSetTest, KillMultipleNode) {
+ MockReplicaSet replSet("n", 3);
+
+ const vector<string> secondaries = replSet.getSecondaries();
+ replSet.kill(replSet.getSecondaries());
+
+ for (vector<string>::const_iterator iter = secondaries.begin();
+ iter != secondaries.end(); ++iter) {
+ ASSERT(!replSet.getNode(*iter)->isRunning());
+ }
+
+ const string priHostName(replSet.getPrimary());
+ ASSERT(replSet.getNode(priHostName)->isRunning());
+ }
}