1
// This file contains test helpers to manage and validate collection state. This is useful for
2
// round trip testing of entire collections.
4
// There are three stages represented in this file:
5
// 1. Data generation - CollectionDataGenerator class. This contains helpers to generate test data
7
// 2. Data persistence - createCollectionWithData function. This class takes a
8
// CollectionDataGenerator and inserts the generated data into the given
10
// 3. Data validation - CollectionDataValidator class. This class contains functions for saving
11
// the state of a collection and comparing a collection's state to the
12
// previously saved state.
15
// 1. Create a CollectionDataGenerator
16
// 2. Save collection data using the createCollectionWithData function
17
// 3. Record collection state in an instance of the CollectionDataValidator class
18
// 4. Do round trip or other testing
19
// 5. Validate that collection has not changed using the CollectionDataValidator class
21
load( './jstests/multiVersion/libs/data_generators.js' )
23
// Function to actually add the data generated by the given dataGenerator to a collection
24
createCollectionWithData = function (db, collectionName, dataGenerator) {
26
// Drop collection if exists
27
// TODO: add ability to control this
28
db.getCollection(collectionName).drop();
30
print("db.createCollection(\"" + collectionName + "\", " +
31
JSON.stringify(dataGenerator.collectionMetadata.get()) + ");");
32
assert.eq(db.createCollection(collectionName, dataGenerator.collectionMetadata.get()).ok, 1);
34
var collection = db.getCollection(collectionName);
37
while (dataGenerator.indexes.hasNext()) {
38
var nextIndex = dataGenerator.indexes.next();
39
print("collection.ensureIndex(" + JSON.stringify(nextIndex.spec) + ", " +
40
JSON.stringify(nextIndex.options) + ");");
41
var ensureIndexResult = collection.ensureIndex(nextIndex.spec, nextIndex.options);
42
// XXX: Is this the real way to check for errors?
43
assert(ensureIndexResult === undefined, JSON.stringify(ensureIndexResult));
47
// Make sure we actually added all the indexes we thing we added. +1 for the _id index.
48
assert.eq(db.system.indexes.find({"ns" : db.toString() + "." + collection.getName()}).count(),
52
while (dataGenerator.data.hasNext()) {
53
var nextDoc = dataGenerator.data.next();
54
// Use _id as our ordering field just so we don't have to deal with sorting. This only
55
// matters here since we can use indexes
56
nextDoc._id = numInserted;
57
print("collection.insert(" + JSON.stringify(nextDoc) + ");");
58
var insertResult = collection.insert(nextDoc);
59
assert(db.getLastError() == null);
63
assert.eq(collection.find().count(), numInserted, "counts not equal after inserts");
65
return db.getCollection(collectionName);
68
// Class to save the state of a collection and later compare the current state of a collection to
70
function CollectionDataValidator() {
72
var initialized = false;
73
var collectionStats = {};
75
var collectionData = [];
77
// Saves the current state of the collection passed in
78
this.recordCollectionData = function (collection) {
80
// Save the indexes for this collection for later comparison
81
indexData = collection.getDB().system.indexes.find({"ns" : collection.getFullName()}).sort({"name":1}).toArray();
83
// Save the data for this collection for later comparison
84
collectionData = collection.find().sort({"_id":1}).toArray();
86
// Save the metadata for this collection for later comparison.
87
// NOTE: We do this last since the data and indexes affect this output
88
collectionStats = collection.stats();
90
// XXX: in 2.4 avgObjSize was a double, but in 2.6 it is an int
91
collectionStats['avgObjSize'] = Math.floor(collectionStats['avgObjSize']);
98
this.validateCollectionData = function (collection) {
101
throw "validateCollectionWithAllData called, but data is not initialized";
104
// Get the metadata for this collection
105
var newCollectionStats = collection.stats();
107
// XXX: in 2.4 avgObjSize was a double, but in 2.6 it is an int
108
newCollectionStats['avgObjSize'] = Math.floor(newCollectionStats['avgObjSize']);
110
assert.docEq(collectionStats, newCollectionStats, "collection metadata not equal");
112
// Get the indexes for this collection
113
var newIndexData = collection.getDB().system.indexes.find({"ns" : collection.getFullName()}).sort({"name":1}).toArray();
114
for (var i = 0; i < newIndexData.length; i++) {
115
assert.docEq(indexData[i], newIndexData[i], "indexes not equal");
118
// Save the data for this collection for later comparison
119
var newCollectionData = collection.find().sort({"_id":1}).toArray();
120
for (var i = 0; i < newCollectionData.length; i++) {
121
assert.docEq(collectionData[i], newCollectionData[i], "data not equal");
127
// Tests of the functions and classes in this file
128
function collectionDataValidatorTests() {
130
// TODO: These tests are hackish and depend on implementation details, but they are good enough
131
// for now to convince us that the CollectionDataValidator is actually checking something
136
myGenerator = new CollectionDataGenerator({ "capped" : true });
137
collection = createCollectionWithData(db, "test", myGenerator);
138
myValidator = new CollectionDataValidator();
139
myValidator.recordCollectionData(collection);
140
db.test.dropIndex(db.system.indexes.findOne({"key.a": { "$exists" : true } }).key);
141
assert.throws(myValidator.validateCollectionData, [collection], "Validation function should have thrown since we modified the collection");
144
myGenerator = new CollectionDataGenerator({ "capped" : true });
145
collection = createCollectionWithData(db, "test", myGenerator);
146
myValidator = new CollectionDataValidator();
147
myValidator.recordCollectionData(collection);
148
db.test.update({_id:0}, {dummy:1});
149
assert.throws(myValidator.validateCollectionData, [collection], "Validation function should have thrown since we modified the collection");
152
myGenerator = new CollectionDataGenerator({ "capped" : true });
153
collection = createCollectionWithData(db, "test", myGenerator);
154
myValidator = new CollectionDataValidator();
155
myValidator.recordCollectionData(collection);
156
assert(myValidator.validateCollectionData(collection), "Validation function failed");
158
myGenerator = new CollectionDataGenerator({ "capped" : false });
159
collection = createCollectionWithData(db, "test", myGenerator);
160
myValidator = new CollectionDataValidator();
161
myValidator.recordCollectionData(collection);
162
db.test.dropIndex(db.system.indexes.findOne({"key.a": { "$exists" : true } }).key);
163
assert.throws(myValidator.validateCollectionData, [collection], "Validation function should have thrown since we modified the collection");
166
myGenerator = new CollectionDataGenerator({ "capped" : false });
167
collection = createCollectionWithData(db, "test", myGenerator);
168
myValidator = new CollectionDataValidator();
169
myValidator.recordCollectionData(collection);
170
db.test.update({_id:0}, {dummy:1});
171
assert.throws(myValidator.validateCollectionData, [collection], "Validation function should have thrown since we modified the collection");
174
myGenerator = new CollectionDataGenerator({ "capped" : false });
175
collection = createCollectionWithData(db, "test", myGenerator);
176
myValidator = new CollectionDataValidator();
177
myValidator.recordCollectionData(collection);
178
assert(myValidator.validateCollectionData(collection), "Validation function failed");
180
print("collection data validator tests passed!");