summaryrefslogtreecommitdiff
path: root/jstests/multiVersion/libs/dumprestore_helpers.js
blob: a2b7d22d20cb8ed1997789db003117b3c9911c6e (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
// dumprestore_helpers.js

load('./jstests/multiVersion/libs/verify_collection_data.js');

// Given a "test spec" object, runs the specified test.
//
// The "test spec" object has the format:
//
// {
//     'serverSourceVersion' : "latest",
//     'serverDestVersion' : "2.4",
//     'mongoDumpVersion' : "2.2",
//     'mongoRestoreVersion' : "latest",
//     'dumpDir' : dumpDir,
//     'testDbpath' : testDbpath,
//     'dumpType' : "mongos",
//     'restoreType' : "mongod" // "mongos" also supported
// }
//
// The first four fields are which versions of the various binaries to use in the test.
//
// The "dumpDir" field is the external directory to use as scratch space for database dumps.
//
// The "testDbpath" is the external directory to use as the server dbpath directory.
//
// For the "dumpType" and "restoreType" fields, the following values are supported:
//     - "mongod" - Do the dump or restore by connecting to a single mongod node
//     - "mongos" - Do the dump or restore by connecting to a sharded cluster
//
function multiVersionDumpRestoreTest(configObj) {
    // First sanity check the arguments in our configObj
    var requiredKeys = [
        'serverSourceVersion',
        'serverDestVersion',
        'mongoDumpVersion',
        'mongoRestoreVersion',
        'dumpDir',
        'testDbpath',
        'dumpType',
        'restoreType'
    ];

    var i;

    for (i = 0; i < requiredKeys.length; i++) {
        assert(configObj.hasOwnProperty(requiredKeys[i]),
               "Missing required key: " + requiredKeys[i] + " in config object");
    }

    resetDbpath(configObj.dumpDir);
    resetDbpath(configObj.testDbpath);
    if (configObj.dumpType === "mongos") {
        var shardingTestConfig = {
            sync: true,  // Mixed version clusters can't use replsets for config servers
            name: testBaseName + "_sharded_source",
            mongos: [{binVersion: configObj.serverSourceVersion}],
            shards: [{binVersion: configObj.serverSourceVersion}],
            config: [{binVersion: configObj.serverSourceVersion}]
        };
        var shardingTest = new ShardingTest(shardingTestConfig);
        var serverSource = shardingTest.s;
    } else {
        var serverSource = MongoRunner.runMongod(
            {binVersion: configObj.serverSourceVersion, dbpath: configObj.testDbpath});
    }
    var sourceDB = serverSource.getDB(testBaseName);

    // Create generators to create collections with our seed data
    // Testing with both a capped collection and a normal collection
    var cappedCollGen = new CollectionDataGenerator({"capped": true});
    var collGen = new CollectionDataGenerator({"capped": false});

    // Create collections using the different generators
    var sourceCollCapped = createCollectionWithData(sourceDB, "cappedColl", cappedCollGen);
    var sourceColl = createCollectionWithData(sourceDB, "coll", collGen);

    // Record the current collection states for later validation
    var cappedCollValid = new CollectionDataValidator();
    cappedCollValid.recordCollectionData(sourceCollCapped);
    var collValid = new CollectionDataValidator();
    collValid.recordCollectionData(sourceColl);

    // Dump using the specified version of mongodump from the running mongod or mongos instance.
    if (configObj.dumpType === "mongod") {
        MongoRunner.runMongoTool("mongodump",
                                 {
                                   out: configObj.dumpDir,
                                   binVersion: configObj.mongoDumpVersion,
                                   host: serverSource.host,
                                   db: testBaseName
                                 });
        MongoRunner.stopMongod(serverSource.port);
    } else { /* "mongos" */
        MongoRunner.runMongoTool("mongodump",
                                 {
                                   out: configObj.dumpDir,
                                   binVersion: configObj.mongoDumpVersion,
                                   host: serverSource.host,
                                   db: testBaseName
                                 });
        shardingTest.stop();
    }

    // Restore using the specified version of mongorestore
    if (configObj.restoreType === "mongod") {
        var serverDest = MongoRunner.runMongod({binVersion: configObj.serverDestVersion});

        MongoRunner.runMongoTool("mongorestore",
                                 {
                                   dir: configObj.dumpDir + "/" + testBaseName,
                                   binVersion: configObj.mongoRestoreVersion,
                                   host: serverDest.host,
                                   db: testBaseName
                                 });
    } else { /* "mongos" */
        var shardingTestConfig = {
            sync: true,  // Mixed version clusters can't use replsets for config servers
            name: testBaseName + "_sharded_dest",
            mongos: [{binVersion: configObj.serverDestVersion}],
            shards: [{binVersion: configObj.serverDestVersion}],
            config: [{binVersion: configObj.serverDestVersion}]
        };
        var shardingTest = new ShardingTest(shardingTestConfig);
        serverDest = shardingTest.s;
        MongoRunner.runMongoTool("mongorestore",
                                 {
                                   dir: configObj.dumpDir + "/" + testBaseName,
                                   binVersion: configObj.mongoRestoreVersion,
                                   host: serverDest.host,
                                   db: testBaseName
                                 });
    }

    var destDB = serverDest.getDB(testBaseName);

    // Get references to our destinations collections
    // XXX: These are in the global scope (no "var"), but they need to be global to be in scope for
    // the "assert.soon" calls below.
    destColl = destDB.getCollection("coll");
    destCollCapped = destDB.getCollection("cappedColl");

    // Wait until we actually have data or timeout
    assert.soon("destColl.findOne()", "no data after sleep");
    assert.soon("destCollCapped.findOne()", "no data after sleep");

    // Validate that our collections were properly restored
    assert(collValid.validateCollectionData(destColl));
    assert(cappedCollValid.validateCollectionData(destCollCapped));

    if (configObj.restoreType === "mongos") {
        shardingTest.stop();
    } else {
        MongoRunner.stopMongod(serverDest.port);
    }
}

// Given an object with list values, returns a cursor that returns an object for every combination
// of selections of the values in the lists.
//
// Usage:
// var permutationCursor = getPermutationIterator({"a":[0,1], "b":[2,3]});
// while (permutationCursor.hasNext()) {
//    var permutation = permutationCursor.next();
//    printjson(permutation);
// }
//
// This will print:
//
// { "a" : 0, "b" : 2 }
// { "a" : 1, "b" : 2 }
// { "a" : 0, "b" : 3 }
// { "a" : 1, "b" : 3 }
function getPermutationIterator(permsObj) {
    function getAllPermutations(permsObj) {
        // Split our permutations object into "first" and "rest"
        var gotFirst = false;
        var firstKey;
        var firstValues;
        var restObj = {};
        for (var key in permsObj) {
            if (permsObj.hasOwnProperty(key)) {
                if (gotFirst) {
                    restObj[key] = permsObj[key];
                } else {
                    firstKey = key;
                    firstValues = permsObj[key];
                    gotFirst = true;
                }
            }
        }

        // Our base case is an empty object, which just has a single permutation, "{}"
        if (!gotFirst) {
            return [{}];
        }

        // Iterate the possibilities for "first" and for each one recursively get all the
        // permutations for "rest"
        var resultPermObjs = [];
        var i = 0;
        var j = 0;
        for (i = 0; i < firstValues.length; i++) {
            var subPermObjs = getAllPermutations(restObj);
            for (j = 0; j < subPermObjs.length; j++) {
                subPermObjs[j][firstKey] = firstValues[i];
                resultPermObjs.push(subPermObjs[j]);
            }
        }
        return resultPermObjs;
    }

    var allPermutations = getAllPermutations(permsObj);
    var currentPermutation = 0;

    return {
        "next": function() {
            return allPermutations[currentPermutation++];
        },
        "hasNext": function() {
            return currentPermutation < allPermutations.length;
        }
    };
}

// Given a "test spec" object, runs all test combinations.
//
// The "test spec" object has the format:
//
// {
//     'serverSourceVersion' : [ "latest", "2.4" ],
//     'serverDestVersion' :[ "latest", "2.4" ],
//     'mongoDumpVersion' :[ "latest", "2.4" ],
//     'mongoRestoreVersion' :[ "latest", "2.4" ],
//     'dumpDir' : [ dumpDir ],
//     'testDbpath' : [ testDbpath ],
//     'dumpType' : [ "mongod", "mongos" ],
//     'restoreType' : [ "mongod", "mongos" ]
// }
//
// This function will run a test for each possible combination of the parameters.  See comments on
// "getPermutationIterator" above.
function runAllDumpRestoreTests(testCasePermutations) {
    var testCaseCursor = getPermutationIterator(testCasePermutations);
    while (testCaseCursor.hasNext()) {
        var testCase = testCaseCursor.next();
        print("Running multiversion mongodump mongorestore test:");
        printjson(testCase);
        multiVersionDumpRestoreTest(testCase);
    }
}