// Tests that concurrent change streams requests that would create the database will take locks in
// an order that avoids a deadlock.
// This test was designed to reproduce SERVER-34333.
// This test uses the WiredTiger storage engine, which does not support running without journaling.
// @tags: [requires_replication, requires_majority_read_concern]
import {ReplSetTest} from "jstests/libs/replsettest.js";

const rst = new ReplSetTest({nodes: 1});
rst.startSet();
rst.initiate();
const db = rst.getPrimary().getDB("test");

let unique_dbName = jsTestName();
const sleepShell = startParallelShell(() => {
    assert.commandFailedWithCode(db.adminCommand({sleep: 1, lock: "w", seconds: 600}),
                                 ErrorCodes.Interrupted);
}, rst.getPrimary().port);
assert.soon(
    () =>
        db.getSiblingDB("admin").currentOp({"command.sleep": 1, active: true}).inprog.length === 1);
const sleepOps = db.getSiblingDB("admin").currentOp({"command.sleep": 1, active: true}).inprog;
assert.eq(sleepOps.length, 1);
const sleepOpId = sleepOps[0].opid;

// Start two concurrent shells which will both attempt to create the database which does not yet
// exist.
const openChangeStreamCode = `const cursor = db.getSiblingDB("${unique_dbName}").test.watch();`;
const changeStreamShell1 = startParallelShell(openChangeStreamCode, rst.getPrimary().port);
const changeStreamShell2 = startParallelShell(openChangeStreamCode, rst.getPrimary().port);

// Wait until we can see both change streams have started and are waiting to acquire the lock
// held by the sleep command.
assert.soon(
    () => db.currentOp({"command.aggregate": "test", waitingForLock: true}).inprog.length === 2);
assert.commandWorked(db.adminCommand({killOp: 1, op: sleepOpId}));

sleepShell();

// Before the fix for SERVER-34333, the operations in these shells would be deadlocked with each
// other and never complete.
changeStreamShell1();
changeStreamShell2();

rst.stopSet();