Files
mongo/jstests/sharding/read_pref.js
Kaloian Manassiev c078dc37a9 SERVER-21050 Cleanup ReplSetTest
This is just a cleanup work to hide some of the private state of
ReplSetTest so it is easier to encapsulate and add new logic. Also enables
strict mode.
2015-12-08 13:15:06 -05:00

207 lines
6.8 KiB
JavaScript
Executable File

/**
* Integration test for read preference and tagging. The more comprehensive unit test
* can be found in dbtests/replica_set_monitor_test.cpp.
*/
var PRI_TAG = { dc: 'ny' };
var SEC_TAGS = [
{ dc: 'sf', s: "1" },
{ dc: 'ma', s: "2" },
{ dc: 'eu', s: "3" },
{ dc: 'jp', s: "4" }
];
var NODES = SEC_TAGS.length + 1;
var doTest = function(useDollarQuerySyntax) {
var st = new ShardingTest({ shards: {
rs0: { nodes: NODES, oplogSize: 10, useHostName: true }
}});
var replTest = st.rs0;
var primaryNode = replTest.getPrimary();
// The $-prefixed query syntax is only legal for compatibility mode reads, not for the
// find/getMore commands.
if (useDollarQuerySyntax && st.s.getDB("test").getMongo().useReadCommands()) {
return;
}
var setupConf = function(){
var replConf = primaryNode.getDB( 'local' ).system.replset.findOne();
replConf.version = (replConf.version || 0) + 1;
var secIdx = 0;
for ( var x = 0; x < NODES; x++ ){
var node = replConf.members[x];
if ( node.host == primaryNode.name ){
node.tags = PRI_TAG;
}
else {
node.tags = SEC_TAGS[secIdx++];
node.priority = 0;
}
}
try {
primaryNode.getDB( 'admin' ).runCommand({ replSetReconfig: replConf });
} catch (x) {
jsTest.log('Exception expected because reconfiguring would close all conn, got ' + x);
}
return replConf;
};
var checkTag = function( nodeToCheck, tag ){
for ( var idx = 0; idx < NODES; idx++ ){
var node = replConf.members[idx];
if ( node.host == nodeToCheck ){
jsTest.log( 'node[' + node.host + '], Tag: ' + tojson( node['tags'] ));
jsTest.log( 'tagToCheck: ' + tojson( tag ));
var nodeTag = node['tags'];
for ( var key in tag ){
assert.eq( tag[key], nodeTag[key] );
}
return;
}
}
assert( false, 'node ' + nodeToCheck + ' not part of config!' );
};
var replConf = setupConf();
var conn = st.s;
// Wait until the ReplicaSetMonitor refreshes its view and see the tags
ReplSetTest.awaitRSClientHosts( conn, primaryNode,
{ ok: true, tags: PRI_TAG }, replTest.name );
replTest.awaitReplication();
jsTest.log('New rs config: ' + tojson(primaryNode.getDB('local').system.replset.findOne()));
jsTest.log( 'connpool: ' + tojson(conn.getDB('admin').runCommand({ connPoolStats: 1 })));
var coll = conn.getDB( 'test' ).user;
assert.soon(function() {
var res = coll.insert({ x: 1 }, { writeConcern: { w: NODES }});
if (!res.hasWriteError()) {
return true;
}
var err = res.getWriteError().errmsg;
// Transient transport errors may be expected b/c of the replSetReconfig
if (err.indexOf("transport error") == -1) {
throw err;
}
return false;
});
var getExplain = function(readPrefMode, readPrefTags) {
if (useDollarQuerySyntax) {
var readPrefObj = {
mode: readPrefMode
};
if (readPrefTags) {
readPrefObj.tags = readPrefTags;
}
return coll.find({ $query: {}, $readPreference: readPrefObj,
$explain: true }).limit(-1).next();
}
else {
return coll.find().readPref(readPrefMode, readPrefTags).explain("executionStats");
}
};
var getExplainServer = function(explain) {
assert.eq("SINGLE_SHARD", explain.queryPlanner.winningPlan.stage);
var serverInfo = explain.queryPlanner.winningPlan.shards[0].serverInfo;
return serverInfo.host + ":" + serverInfo.port.toString();
};
// Read pref should work without slaveOk
var explain = getExplain("secondary");
var explainServer = getExplainServer(explain);
assert.neq( primaryNode.name, explainServer );
conn.setSlaveOk();
// It should also work with slaveOk
explain = getExplain("secondary");
explainServer = getExplainServer(explain);
assert.neq( primaryNode.name, explainServer );
// Check that $readPreference does not influence the actual query
assert.eq( 1, explain.executionStats.nReturned );
explain = getExplain("secondaryPreferred", [{ s: "2" }]);
explainServer = getExplainServer(explain);
checkTag( explainServer, { s: "2" });
assert.eq( 1, explain.executionStats.nReturned );
// Cannot use tags with primaryOnly
assert.throws( function() {
getExplain("primary", [{ s: "2" }]);
});
// Ok to use empty tags on primaryOnly
explain = getExplain("primary", [{}]);
explainServer = getExplainServer(explain);
assert.eq(primaryNode.name, explainServer);
explain = getExplain("primary", []);
explainServer = getExplainServer(explain);
assert.eq(primaryNode.name, explainServer);
// Check that mongos will try the next tag if nothing matches the first
explain = getExplain("secondary", [{ z: "3" }, { dc: "jp" }]);
explainServer = getExplainServer(explain);
checkTag( explainServer, { dc: "jp" });
assert.eq( 1, explain.executionStats.nReturned );
// Check that mongos will fallback to primary if none of tags given matches
explain = getExplain("secondaryPreferred", [{ z: "3" }, { dc: "ph" }]);
explainServer = getExplainServer(explain);
// Call getPrimary again since the primary could have changed after the restart.
assert.eq(replTest.getPrimary().name, explainServer);
assert.eq( 1, explain.executionStats.nReturned );
// Kill all members except one
var stoppedNodes = [];
for ( var x = 0; x < NODES - 1; x++ ){
replTest.stop( x );
stoppedNodes.push( replTest.nodes[x] );
}
// Wait for ReplicaSetMonitor to realize nodes are down
ReplSetTest.awaitRSClientHosts( conn, stoppedNodes, { ok: false }, replTest.name );
// Wait for the last node to be in steady state -> secondary (not recovering)
var lastNode = replTest.nodes[NODES - 1];
ReplSetTest.awaitRSClientHosts( conn, lastNode,
{ ok: true, secondary: true }, replTest.name );
jsTest.log( 'connpool: ' + tojson(conn.getDB('admin').runCommand({ connPoolStats: 1 })));
// Test to make sure that connection is ok, in prep for priOnly test
explain = getExplain("nearest");
explainServer = getExplainServer(explain);
assert.eq( explainServer, replTest.nodes[NODES - 1].name );
assert.eq( 1, explain.executionStats.nReturned );
// Should assert if request with priOnly but no primary
assert.throws( function(){
getExplain("primary");
});
st.stop();
};
doTest(false);
doTest(true);