// test that nodes still respond to heartbeats (SERVER-12264) and auth requests (SERVER-12359)
// during the compact command

if (false) { // disabled until SERVER-12697 is resolved
// this function will wait until compact has acquired the WriteLock and then return
awaitCompact = function() {
    print("waiting for compact to acquire lock");
    assert.soon(function() {
        var curop = compactingSlave.getDB('compact').currentOp();
        printjson(curop);
        for (index in curop.inprog) {
            entry = curop.inprog[index];
            if (entry.query.hasOwnProperty("compact") && entry.query.compact === "foo"
                && entry.hasOwnProperty("locks") && entry.locks.hasOwnProperty("^compact")
                && entry.locks["^compact"] === "W") {
                return true;
            }
        }
        return false;
    }, "compact didn't start in 30 seconds", 30*1000, 100);
};

// set up replSet
var replTest = new ReplSetTest({name: 'compact', nodes: 3, keyFile: "jstests/libs/key1"});
replTest.startSet();
replTest.initiate();
var master = replTest.getMaster();

// populate data
for (i=0; i<1000; i++) {
    var bulkInsertArr = [];
    for (j=0; j<1000; j++) {
        bulkInsertArr.push({x:i, y:j});
    }
    master.getDB("compact").foo.insert(bulkInsertArr);
}

// takes a while to replicate all this data...
replTest.awaitReplication(1000*60*10);

// run compact in parallel
var compactingSlave = replTest.liveNodes.slaves[0];
print("starting first compact on port: " + compactingSlave);
var cmd = "printjson(db.getSiblingDB('compact').runCommand({'compact': 'foo', 'paddingFactor': 2}));";
var compactor = startParallelShell(cmd, compactingSlave.port);

// wait for compact to have lock and then see if heartbeats work
awaitCompact();
for (i=0; i<5; i++) {
    var start = new Date();
    var result = compactingSlave.getDB("admin").runCommand({"replSetHeartbeat": "compact",
                                                            "v": NumberInt(1),
                                                            "pv": NumberInt(1),
                                                            "checkEmpty": false,
                                                            "fromId": NumberInt(0)
                                                            });
    var end = new Date();
    assert.eq(result.ok, 1, "heartbeat didn't return properly");
    // wait for 10 seconds because that's how long it takes for a node to be considered down
    assert.lt(end - start, 10 * 1000, "heartbeat didn't return quickly enough");
}
print("heartbeat worked during compact");

// wait for the first compact to finish
compactor();

// setup auth and auth to all
master.getDB("admin").createUser({user:"admin", pwd:"hunter2", roles:["root"]}, {w:2});
// have to wait til auth info replicates, but can't awaitReplication() because some expect auth...
assert.soon(function() {
    return master.getDB("admin").auth({user:"admin", pwd:"hunter2"})
           && compactingSlave.getDB("admin").auth({user:"admin", pwd:"hunter2"})
           && replTest.liveNodes.slaves[1].getDB("admin").auth({user:"admin", pwd:"hunter2"})
});

// auth and run compact in parallel
print("starting second compact");
cmd = "printjson(db.getSiblingDB('admin').auth('admin','hunter2'));"
      + " printjson(db.getSiblingDB('compact').runCommand({'compact': 'foo', 'paddingFactor': 2}));";
var compactor2 = startParallelShell(cmd, compactingSlave.port);

// wait for compact to have lock and then check if auth works
awaitCompact();
for (i=0; i<5; i++) {
    var start = new Date();
    var result = compactingSlave.getDB("admin").auth({user:"admin", pwd:"hunter"+i});
    var end = new Date();
    assert.lt(end - start, 2 * 1000, "auth didn't return quickly enough");
}
print("auth worked during compact");

// wait for the second compact to finish
print("finished!");
replTest.stopSet();
}
