/**
 * Builds an index including a 2dsphere on a collection containing a document which does not conform
 * to the 2dsphere requirements. After this document has been skipped during the collection scan
 * phase but before the index is committed, updates this document to conform to the 2dsphere as well
 * as to flip the index to multikey.
 *
 * @tags: [
 *   requires_replication,
 * ]
 */
import {configureFailPoint} from "jstests/libs/fail_point_util.js";
import {funWithArgs} from "jstests/libs/parallel_shell_helpers.js";
import {ReplSetTest} from "jstests/libs/replsettest.js";

const replTest = new ReplSetTest({
    nodes: [
        {},
        {
            // Disallow elections on secondary.
            rsConfig: {
                priority: 0,
            },
        },
    ],
    nodeOptions: {setParameter: {logComponentVerbosity: tojson({index: 2})}}
});
replTest.startSet();
replTest.initiate();

const primary = replTest.getPrimary();
const coll = primary.getDB('test')[jsTestName()];

assert.commandWorked(coll.insert([
    {
        _id: 0,
        a: {loc: {type: 'Point', coordinates: [-73.97, 40.77]}, num: 0},
    },
    {
        _id: 1,
        a: {
            // Cannot be indexed as a 2dsphere.
            loc: {
                type: 'Polygon',
                coordinates: [
                    // One square.
                    [[9, 9], [9, 11], [11, 11], [11, 9], [9, 9]],
                    // Another disjoint square.
                    [[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]
                ]
            },
            num: 1,
        }
    }
]));

const secondary = replTest.getSecondary();
const fpSecondaryDrain = configureFailPoint(secondary, 'hangAfterIndexBuildFirstDrain');

// We don't want the primary to observe a non-conforming document, as that would abort the build.
// Hang before collection scan starts.
const fpPrimarySetup = configureFailPoint(primary, 'hangAfterInitializingIndexBuild');

const indexKeyPattern = {
    'a.loc': '2dsphere',
    'a.num': 1
};
const awaitCreateIndex =
    startParallelShell(funWithArgs(function(collName, keyPattern) {
                           assert.commandWorked(db[collName].createIndex(keyPattern));
                       }, coll.getName(), indexKeyPattern), primary.port);
fpSecondaryDrain.wait();

// Two documents are scanned but only one key is inserted.
checkLog.containsJson(secondary, 20391, {namespace: coll.getFullName(), totalRecords: 2});
checkLog.containsJson(secondary, 20685, {namespace: coll.getFullName(), keysInserted: 1});

// Allows 'a.loc' to be indexed as a 2dsphere and flips the index to multikey.
assert.commandWorked(coll.update({_id: 1}, {
    a: {loc: {type: 'Point', coordinates: [-73.88, 40.78]}, num: [1, 1]},
}));

fpSecondaryDrain.off();
fpPrimarySetup.off();
awaitCreateIndex();

// The skipped document is resolved, and causes the index to flip to multikey.
// "Index set to multi key ..."
checkLog.containsJson(
    secondary, 4718705, {namespace: coll.getFullName(), keyPattern: indexKeyPattern});

replTest.stopSet();
