0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

Adding some pairing tests

This commit is contained in:
Aaron Staple 2008-12-05 16:03:35 -05:00
parent 932e7a3295
commit 243a3e6b2f
11 changed files with 334 additions and 6 deletions

View File

@ -119,6 +119,7 @@ public:
BSONObj contains more details e.g.:
{ "ismaster" : 1.0 , "msg" : "not paired" , "ok" : 1.0 }
*/
virtual
BSONObj cmdIsMaster(bool& isMaster);
};
@ -151,7 +152,8 @@ public:
If autoReconnect is true, you can try to use the DBClientConnection even when
false was returned -- it will try to connect again.
*/
bool connect(const char *serverHostname, string& errmsg);
virtual
bool connect(const char *serverHostname, string& errmsg);
/* send a query to the database.
ns: namespace to query, format is <dbname>.<collectname>[.<collectname>]*
@ -173,7 +175,8 @@ public:
BSONObj *fieldsToReturn = 0, int queryOptions = 0);
/*throws AssertionException*/
BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0);
virtual
BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0);
};
/* Use this class to connect to a replica pair of servers. The class will manage

View File

@ -41,3 +41,5 @@ public:
Command(const char *_name);
};
bool runCommandAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& anObjBuilder);

View File

@ -14,6 +14,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../stdafx.h"
#include "../grid/message.h"

View File

@ -16,7 +16,7 @@ OBJS=../stdafx.o ../util/sock.o ../grid/message.o ../util/mmap.o pdfile.o query.
DBGRID_OBJS=../stdafx.o json.o ../util/sock.o ../grid/message.o ../util/util.o jsobj.o ../client/dbclient.o ../dbgrid/dbgrid.o ../dbgrid/request.o ../client/connpool.o ../dbgrid/gridconfig.o commands.o ../dbgrid/dbgrid_commands.o ../dbgrid/griddatabase.o ../client/model.o ../util/background.o ../dbgrid/shard.o
DBTEST_OBJS= $(OBJS) ../dbtests/dbtests.o ../dbtests/btreetests.o
DBTEST_OBJS= $(OBJS) ../dbtests/dbtests.o ../dbtests/btreetests.o ../dbtests/pairingtests.o
GPP = g++

View File

@ -72,7 +72,7 @@ void ReplPair::arbitrate() {
return;
}
auto_ptr<DBClientConnection> conn( new DBClientConnection() );
auto_ptr<DBClientConnection> conn( newClientConnection() );
string errmsg;
if( !conn->connect(arbHost.c_str(), errmsg) ) {
setMaster(State_CantArb, "can't connect to arb");

View File

@ -16,6 +16,9 @@
#pragma once
#include "db.h"
#include "../client/dbclient.h"
extern int port;
extern const char *allDead;
@ -84,6 +87,11 @@ public:
/* peer unreachable, try our arbitrator */
void arbitrate();
virtual
DBClientConnection *newClientConnection() {
return new DBClientConnection();
}
};
extern ReplPair *replPair;

View File

@ -37,6 +37,7 @@
#include "stdafx.h"
#include "../grid/message.h"
#include "../db/commands.h"
#include "../db/dbmessage.h"
#include "../client/connpool.h"
@ -59,8 +60,6 @@ void getMore(Message& m, MessagingPort& p) {
dbcon.done();
}
bool runCommandAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& anObjBuilder);
/* got query operation from a database */
void queryOp(Message& m, MessagingPort& p) {
DbMessage d(m);

View File

@ -67,6 +67,7 @@ int main( int argc, char** argv ) {
UnitTest::Registry tests;
tests.add( btreeTests(), "btree" );
tests.add( pairingTests(), "pairing" );
return tests.run( argc, argv );
}

View File

@ -1,3 +1,23 @@
// dbtests.h : Test suite generator headers.
//
/**
* Copyright (C) 2008 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 <http://www.gnu.org/licenses/>.
*/
#include <unittest/UnitTest.hpp>
UnitTest::TestPtr btreeTests();
UnitTest::TestPtr pairingTests();

72
dbtests/mockdbclient.h Normal file
View File

@ -0,0 +1,72 @@
// mockdbclient.h - mocked out client for testing.
/**
* Copyright (C) 2008 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../client/dbclient.h"
#include "../db/commands.h"
class MockDBClientConnection : public DBClientConnection {
public:
MockDBClientConnection() : connect_() {}
virtual
BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0) {
return one_;
}
virtual
bool connect(const char *serverHostname, string& errmsg) {
return connect_;
}
virtual
BSONObj cmdIsMaster(bool& isMaster) {
return res_;
}
void one( const BSONObj &one ) { one_ = one; }
void connect( bool val ) { connect_ = val; }
void res( const BSONObj &val ) { res_ = val; }
private:
BSONObj one_;
bool connect_;
BSONObj res_;
};
class DirectDBClientConnection : public DBClientConnection {
public:
DirectDBClientConnection( ReplPair *rp ) : rp_( rp ) {
}
virtual BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0) {
SetGlobalReplPair s( rp_ );
BSONObjBuilder result;
result.append( "ok", runCommandAgainstRegistered( "admin.$cmd", query, result ) ? 1.0 : 0.0 );
return result.doneAndDecouple();
}
private:
ReplPair *rp_;
class SetGlobalReplPair {
public:
SetGlobalReplPair( ReplPair *rp ) {
backup_ = replPair;
replPair = rp;
}
~SetGlobalReplPair() {
replPair = backup_;
}
private:
ReplPair *backup_;
};
};

221
dbtests/pairingtests.cpp Normal file
View File

@ -0,0 +1,221 @@
// pairingtests.cpp : Pairing unit tests.
//
/**
* Copyright (C) 2008 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 <http://www.gnu.org/licenses/>.
*/
#include "stdafx.h"
#include "../db/replset.h"
#include "dbtests.h"
#include "mockdbclient.h"
namespace PairingTests {
namespace ReplPairTests {
class Create {
public:
void run() {
ReplPair rp1( "foo", "bar" );
checkFields( rp1, "foo", "foo", DBPort, "bar" );
ReplPair rp2( "foo:1", "bar" );
checkFields( rp2, "foo:1", "foo", 1, "bar" );
// FIXME Should we accept this input?
ReplPair rp3( "", "bar" );
checkFields( rp3, "", "", DBPort, "bar" );
ASSERT_EXCEPTION( ReplPair( "foo:", "bar" ),
UserAssertionException );
ASSERT_EXCEPTION( ReplPair( "foo:0", "bar" ),
UserAssertionException );
ASSERT_EXCEPTION( ReplPair( "foo:10000000", "bar" ),
UserAssertionException );
ASSERT_EXCEPTION( ReplPair( "foo", "" ),
UserAssertionException );
}
private:
void checkFields( const ReplPair &rp,
const string &remote,
const string &remoteHost,
int remotePort,
const string &arbHost ) {
ASSERT( rp.state == ReplPair::State_Negotiating );
ASSERT_EQUALS( rp.remote, remote );
ASSERT_EQUALS( rp.remoteHost, remoteHost );
ASSERT_EQUALS( rp.remotePort, remotePort );
ASSERT_EQUALS( rp.arbHost, arbHost );
}
};
class Dominant {
public:
Dominant() : oldPort_( port ) {
port = 10;
}
~Dominant() {
port = oldPort_;
}
void run() {
ASSERT( ReplPair( "b:9", "-" ).dominant( "b" ) );
ASSERT( !ReplPair( "b:10", "-" ).dominant( "b" ) );
ASSERT( ReplPair( "b", "-" ).dominant( "c" ) );
ASSERT( !ReplPair( "b", "-" ).dominant( "a" ) );
}
private:
int oldPort_;
};
class SetMaster {
public:
void run() {
ReplPair rp( "a", "b" );
rp.setMaster( ReplPair::State_CantArb, "foo" );
ASSERT( rp.state == ReplPair::State_CantArb );
ASSERT_EQUALS( rp.info, "foo" );
rp.setMaster( ReplPair::State_Confused, "foo" );
ASSERT( rp.state == ReplPair::State_Confused );
}
};
class Negotiate {
public:
void run() {
ReplPair rp( "a", "b" );
MockDBClientConnection cc;
cc.one( res( 0, 0 ) );
rp.negotiate( &cc );
ASSERT( rp.state == ReplPair::State_Confused );
rp.state = ReplPair::State_Negotiating;
cc.one( res( 1, 2 ) );
rp.negotiate( &cc );
ASSERT( rp.state == ReplPair::State_Negotiating );
cc.one( res( 1, ReplPair::State_Slave ) );
rp.negotiate( &cc );
ASSERT( rp.state == ReplPair::State_Slave );
cc.one( res( 1, ReplPair::State_Master ) );
rp.negotiate( &cc );
ASSERT( rp.state == ReplPair::State_Master );
}
private:
BSONObj res( int ok, int youAre ) {
BSONObjBuilder b;
b.appendInt( "ok", ok );
b.appendInt( "you_are", youAre );
return b.doneAndDecouple();
}
};
class Arbitrate {
public:
void run() {
ReplPair rp1( "a", "-" );
rp1.arbitrate();
ASSERT( rp1.state == ReplPair::State_Master );
TestableReplPair rp2( false, BSONObj() );
rp2.arbitrate();
ASSERT( rp2.state == ReplPair::State_CantArb );
BSONObjBuilder b;
b.append( "foo", 1 );
TestableReplPair rp3( true, b.doneAndDecouple() );
rp3.arbitrate();
ASSERT( rp3.state == ReplPair::State_Master );
}
private:
class TestableReplPair : public ReplPair {
public:
TestableReplPair( bool connect, const BSONObj &res ) :
ReplPair( "a", "z" ),
connect_( connect ),
res_( res ) {
}
virtual
DBClientConnection *newClientConnection() {
MockDBClientConnection * c = new MockDBClientConnection();
c->connect( connect_ );
c->res( res_ );
return c;
}
private:
bool connect_;
BSONObj res_;
};
};
} // namespace ReplPairTests
class DirectConnectBase {
protected:
static void negotiate( ReplPair &a, ReplPair &b ) {
a.negotiate( auto_ptr< DBClientConnection >( new DirectDBClientConnection( &b ) ).get() );
}
};
class Negotiate : public DirectConnectBase {
public:
void run() {
checkNegotiation( "a", "-", ReplPair::State_Negotiating, ReplPair::State_Master,
"b", "-", ReplPair::State_Negotiating, ReplPair::State_Slave );
checkNegotiation( "b", "-", ReplPair::State_Negotiating, ReplPair::State_Slave,
"a", "-", ReplPair::State_Negotiating, ReplPair::State_Master );
checkNegotiation( "a", "-", ReplPair::State_Negotiating, ReplPair::State_Slave,
"b", "-", ReplPair::State_Master, ReplPair::State_Master );
checkNegotiation( "b", "-", ReplPair::State_Master, ReplPair::State_Master,
"a", "-", ReplPair::State_Negotiating, ReplPair::State_Slave );
checkNegotiation( "a", "-", ReplPair::State_Negotiating, ReplPair::State_Slave,
"b", "-", ReplPair::State_Slave, ReplPair::State_Master );
// FIXME Move from negotiating to master?
checkNegotiation( "a", "-", ReplPair::State_Slave, ReplPair::State_Slave,
"b", "-", ReplPair::State_Negotiating, ReplPair::State_Master );
}
private:
void checkNegotiation( const char *host1, const char *arb1, int state1, int newState1,
const char *host2, const char *arb2, int state2, int newState2 ) {
ReplPair one( host1, arb1 );
one.state = state1;
ReplPair two( host2, arb2 );
two.state = state2;
negotiate( one, two );
ASSERT( one.state == newState1 );
ASSERT( two.state == newState2 );
}
};
class All : public UnitTest::Suite {
public:
All() {
add< ReplPairTests::Create >();
add< ReplPairTests::Dominant >();
add< ReplPairTests::SetMaster >();
add< ReplPairTests::Negotiate >();
add< ReplPairTests::Arbitrate >();
add< Negotiate >();
}
};
} // namespace PairingTests
UnitTest::TestPtr pairingTests() {
return UnitTest::createSuite< PairingTests::All >();
}