diff options
-rw-r--r-- | src/mongo/dbtests/mock/mock_dbclient_connection.cpp | 25 | ||||
-rw-r--r-- | src/mongo/dbtests/mock/mock_dbclient_connection.h | 10 | ||||
-rw-r--r-- | src/mongo/dbtests/mock/mock_dbclient_cursor.cpp | 34 | ||||
-rw-r--r-- | src/mongo/dbtests/mock/mock_dbclient_cursor.h | 40 | ||||
-rw-r--r-- | src/mongo/dbtests/mock/mock_remote_db_server.cpp | 11 | ||||
-rw-r--r-- | src/mongo/dbtests/mock/mock_remote_db_server.h | 14 | ||||
-rw-r--r-- | src/mongo/dbtests/mock/mock_replica_set.cpp | 19 | ||||
-rw-r--r-- | src/mongo/dbtests/mock/mock_replica_set.h | 9 | ||||
-rw-r--r-- | src/mongo/dbtests/mock_dbclient_conn_test.cpp | 48 | ||||
-rw-r--r-- | src/mongo/dbtests/mock_replica_set_test.cpp | 30 |
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()); + } } |