summaryrefslogtreecommitdiff
path: root/jstests/core/collmod_convert_to_unique_violations_size_limit.js
blob: 06b71afa35409f5aa1e6fe65cd477ad67460acfc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
 * Tests that the CannotConvertIndexToUnique error returned contains correct information about
 * violations found when collMod fails to convert an index to unique and the size of the violations
 * is large.
 *
 * @tags: [
 *  # Cannot implicitly shard accessed collections because of collection existing when none
 *  # expected.
 *  assumes_no_implicit_collection_creation_after_drop,  # common tag in collMod tests.
 *  requires_fcv_60,
 *  requires_non_retryable_commands, # common tag in collMod tests.
 *  # TODO(SERVER-61181): Fix validation errors under ephemeralForTest.
 *  incompatible_with_eft,
 *  # TODO(SERVER-61182): Fix WiredTigerKVEngine::alterIdentMetadata() under inMemory.
 *  requires_persistence,
 *  assumes_unsharded_collection,
 *  tenant_migration_incompatible,
 * ]
 */
(function() {
'use strict';

const collModIndexUniqueEnabled = assert
                                      .commandWorked(db.getMongo().adminCommand(
                                          {getParameter: 1, featureFlagCollModIndexUnique: 1}))
                                      .featureFlagCollModIndexUnique.value;

if (!collModIndexUniqueEnabled) {
    jsTestLog('Skipping test because the collMod unique index feature flag is disabled.');
    return;
}

function sortViolationsArray(arr) {
    // Sorting unsorted arrays of unsorted arrays -- Sort subarrays, then sort main array by first
    // key of subarray.
    for (let i = 0; i < arr.length; i++) {
        arr[i].ids = arr[i].ids.sort();
    }
    return arr.sort(function(a, b) {
        if (a.ids[0] < b.ids[0]) {
            return -1;
        }
        if (a.ids[0] > b.ids[0]) {
            return 1;
        }
        return 0;
    });
}

// Checks that the violations match what we expect.
function assertFailedWithViolations(result, expectedViolations, sizeLimitViolation) {
    assert.commandFailedWithCode(result, ErrorCodes.CannotConvertIndexToUnique);
    if (sizeLimitViolation) {
        assert.eq(
            result.errmsg,
            "Cannot convert the index to unique. Too many conflicting documents were detected. " +
                "Please resolve them and rerun collMod.");
    } else {
        assert.eq(
            result.errmsg,
            "Cannot convert the index to unique. Please resolve conflicting documents before " +
                "running collMod again.");
    }
    assert.eq(bsonWoCompare(sortViolationsArray(result.violations),
                            sortViolationsArray(expectedViolations)),
              0,
              "result violations " + result.violations + " does not match expected violations " +
                  expectedViolations);
}

const collName = 'collmod_convert_to_unique_violations_size_limit';
const coll = db.getCollection(collName);
coll.drop();
assert.commandWorked(db.createCollection(collName));

// Creates regular indexes and try to use collMod to convert them to unique indexes.
assert.commandWorked(coll.createIndex({a: 1}));

// Inserts 8 duplicate documents with 1MB large _id to exceed the 8MB size limit.
let ids = [];
let id;
const nDocs = 8;
for (let i = 0; i < nDocs; ++i) {
    id = "x".repeat(1024 * 1024) + i;
    assert.commandWorked(coll.insert({_id: id, a: 1}));

    // Only first 7 violations will be reported because 8th violation is over 8MB limit.
    if (i < nDocs - 1) {
        ids[i] = id;
    }
}

// Sets 'prepareUnique' before converting the index to unique.
assert.commandWorked(
    db.runCommand({collMod: collName, index: {keyPattern: {a: 1}, prepareUnique: true}}));

// Expects dryRun: true and unique: true conversion to fail with size exceeding violation.
assertFailedWithViolations(
    db.runCommand({collMod: collName, index: {keyPattern: {a: 1}, unique: true}, dryRun: true}),
    [{ids}],
    true);

// Expects unique: true conversion to fail with size exceeding violation.
assertFailedWithViolations(
    db.runCommand({collMod: collName, index: {keyPattern: {a: 1}, unique: true}}), [{ids}], true);

// Removes last violation.
assert.commandWorked(coll.deleteOne({_id: id}));

// Expects dryRun: true and unique: true conversion to fail without size exceeding violation.
assertFailedWithViolations(
    db.runCommand({collMod: collName, index: {keyPattern: {a: 1}, unique: true}, dryRun: true}),
    [{ids}],
    false);

// Expects unique: true conversion to fail without size exceeding violation.
assertFailedWithViolations(
    db.runCommand({collMod: collName, index: {keyPattern: {a: 1}, unique: true}}), [{ids}], false);
})();