/**
 * Tests that having journaled write operations since the last checkpoint triggers an error when
 * --wiredTigerEngineConfigString log=(recover=error) is specified in combination with --nojournal.
 * Also verifies that deleting the journal/ directory allows those operations to safely be ignored.
 */
(function() {
'use strict';

// Skip this test if not running with the "wiredTiger" storage engine.
if (jsTest.options().storageEngine && jsTest.options().storageEngine !== 'wiredTiger') {
    jsTest.log('Skipping test because storageEngine is not "wiredTiger"');
    return;
}

// Skip this test until we figure out why journaled writes are replayed after last checkpoint.
TestData.skipCollectionAndIndexValidation = true;

var dbpath = MongoRunner.dataPath + 'wt_nojournal_skip_recovery';
resetDbpath(dbpath);

// Start a mongod with journaling enabled.
var conn = MongoRunner.runMongod({
    dbpath: dbpath,
    noCleanData: true,
    journal: '',
    // Wait an hour between checkpoints to ensure one isn't created after the fsync command is
    // executed and before the mongod is terminated. This is necessary to ensure that exactly 90
    // documents with the 'journaled' field exist in the collection.
    wiredTigerEngineConfigString: 'checkpoint=(wait=3600)'
});
assert.neq(null, conn, 'mongod was unable to start up');

// Execute unjournaled inserts, but periodically do a journaled insert. Triggers a checkpoint
// prior to the mongod being terminated.
var awaitShell = startParallelShell(function() {
    for (let loopNum = 1; true; ++loopNum) {
        var bulk = db.nojournal.initializeUnorderedBulkOp();
        for (var i = 0; i < 100; ++i) {
            bulk.insert({unjournaled: i});
        }
        assert.commandWorked(bulk.execute({j: false}));
        assert.commandWorked(db.nojournal.insert({journaled: loopNum}, {writeConcern: {j: true}}));

        // Create a checkpoint slightly before the mongod is terminated.
        if (loopNum === 90) {
            assert.commandWorked(db.adminCommand({fsync: 1}));
        }
    }
}, conn.port);

// After some journaled write operations have been performed against the mongod, send a SIGKILL
// to the process to trigger an unclean shutdown.
assert.soon(
    function() {
        var count = conn.getDB('test').nojournal.count({journaled: {$exists: true}});
        if (count >= 100) {
            MongoRunner.stopMongod(conn, 9, {allowedExitCode: MongoRunner.EXIT_SIGKILL});
            return true;
        }
        return false;
    },
    'the parallel shell did not perform at least 100 journaled inserts',
    5 * 60 * 1000 /*timeout ms*/);

var exitCode = awaitShell({checkExitSuccess: false});
assert.neq(0, exitCode, 'expected shell to exit abnormally due to mongod being terminated');

// Restart the mongod with journaling disabled, but configure it to error if the database needs
// recovery.
assert.throws(() => MongoRunner.runMongod({
    dbpath: dbpath,
    noCleanData: true,
    nojournal: '',
    wiredTigerEngineConfigString: 'log=(recover=error)',
}),
              [],
              'mongod should not have started up because it requires recovery');

// Remove the journal files.
assert(removeFile(dbpath + '/journal'), 'failed to remove the journal directory');

// Restart the mongod with journaling disabled again.
conn = MongoRunner.runMongod({
    dbpath: dbpath,
    noCleanData: true,
    nojournal: '',
    wiredTigerEngineConfigString: 'log=(recover=error)',
});
assert.neq(null, conn, 'mongod was unable to start up after removing the journal directory');

var count = conn.getDB('test').nojournal.count({journaled: {$exists: true}});
assert.lte(90, count, 'missing documents that were present in the last checkpoint');
assert.gte(90,
           count,
           'journaled write operations since the last checkpoint should not have been' +
               ' replayed');

MongoRunner.stopMongod(conn);
})();
