1
0
Fork 0
arangodb/tests/js/server/replication/replication-sync.js

2016 lines
56 KiB
JavaScript

/* jshint globalstrict:false, strict:false, unused: false */
/* global arango, assertEqual, assertTrue, assertFalse, arango, ARGUMENTS */
// //////////////////////////////////////////////////////////////////////////////
// / @brief test the sync method of the replication
// /
// / @file
// /
// / DISCLAIMER
// /
// / Copyright 2010-2012 triagens GmbH, Cologne, Germany
// /
// / Licensed under the Apache License, Version 2.0 (the "License");
// / you may not use this file except in compliance with the License.
// / You may obtain a copy of the License at
// /
// / http://www.apache.org/licenses/LICENSE-2.0
// /
// / Unless required by applicable law or agreed to in writing, software
// / distributed under the License is distributed on an "AS IS" BASIS,
// / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// / See the License for the specific language governing permissions and
// / limitations under the License.
// /
// / Copyright holder is triAGENS GmbH, Cologne, Germany
// /
// / @author Jan Steemann
// / @author Copyright 2013, triAGENS GmbH, Cologne, Germany
// //////////////////////////////////////////////////////////////////////////////
const jsunity = require('jsunity');
const arangodb = require('@arangodb');
const deriveTestSuite = require('@arangodb/test-helper').deriveTestSuite;
const db = arangodb.db;
const _ = require('lodash');
const replication = require('@arangodb/replication');
const internal = require('internal');
const masterEndpoint = arango.getEndpoint();
const slaveEndpoint = ARGUMENTS[0];
var mmfilesEngine = false;
if (db._engine().name === 'mmfiles') {
mmfilesEngine = true;
}
const cn = 'UnitTestsReplication';
const sysCn = '_UnitTestsReplication';
const connectToMaster = function () {
arango.reconnect(masterEndpoint, db._name(), 'root', '');
db._flushCache();
};
const connectToSlave = function () {
arango.reconnect(slaveEndpoint, db._name(), 'root', '');
db._flushCache();
};
const collectionChecksum = function (name) {
return db._collection(name).checksum(true, true).checksum;
};
const collectionCount = function (name) {
return db._collection(name).count();
};
const compare = function (masterFunc, slaveInitFunc, slaveCompareFunc, incremental, system) {
var state = {};
db._flushCache();
masterFunc(state);
db._flushCache();
connectToSlave();
slaveInitFunc(state);
internal.wait(0.1, false);
replication.syncCollection(system ? sysCn : cn, {
endpoint: masterEndpoint,
verbose: true,
includeSystem: true,
incremental
});
db._flushCache();
slaveCompareFunc(state);
};
// //////////////////////////////////////////////////////////////////////////////
// / @brief Base Test Config. Identitical part for _system and other DB
// //////////////////////////////////////////////////////////////////////////////
function BaseTestConfig () {
'use strict';
return {
// //////////////////////////////////////////////////////////////////////////////
// / @brief test existing collection
// //////////////////////////////////////////////////////////////////////////////
testExistingPatchBrokenSlaveCounters1: function () {
// can only use this with failure tests enabled and RocksDB engine
if (db._engine().name !== "rocksdb") {
return;
}
let r = arango.GET("/_db/" + db._name() + "/_admin/debug/failat");
if (String(r) === "false") {
return;
}
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
// collection present on slave now
var c = db._collection(cn);
assertEqual(5000, c.count());
assertEqual(5000, c.toArray().length);
arango.PUT_RAW("/_admin/debug/failat/RocksDBCommitCounts", "");
c.insert({});
arango.DELETE_RAW("/_admin/debug/failat", "");
assertEqual(5000, c.count());
assertEqual(5001, c.toArray().length);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
// now validate counters
let c = db._collection(cn);
assertEqual(5000, c.toArray().length);
assertEqual(5000, c.count());
},
true
);
},
testExistingPatchBrokenSlaveCounters2: function () {
// can only use this with failure tests enabled and RocksDB engine
if (db._engine().name !== "rocksdb") {
return;
}
let r = arango.GET("/_db/" + db._name() + "/_admin/debug/failat");
if (String(r) === "false") {
return;
}
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 10000; ++i) {
docs.push({ value: i, _key: "test" + i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(10000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
// collection present on slave now
var c = db._collection(cn);
for (let i = 0; i < 10000; i += 10) {
c.remove("test" + i);
}
assertEqual(9000, c.count());
assertEqual(9000, c.toArray().length);
arango.PUT_RAW("/_admin/debug/failat/RocksDBCommitCounts", "");
for (let i = 0; i < 100; ++i) {
c.insert({ _key: "testmann" + i });
}
arango.DELETE_RAW("/_admin/debug/failat", "");
assertEqual(9000, c.count());
assertEqual(9100, c.toArray().length);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
// now validate counters
let c = db._collection(cn);
assertEqual(10000, c.count());
assertEqual(10000, c.toArray().length);
},
true
);
},
testExistingIndexId: function () {
connectToMaster();
compare(
function (state) {
const c = db._create(cn);
state.indexDef = {type: 'skiplist', id: '1234567', fields: ['value']};
c.ensureIndex(state.indexDef);
state.masterProps = c.index(state.indexDef.id);
},
function (state) {
// already create the collection and index on the slave
const c = db._create(cn);
c.ensureIndex(state.indexDef);
},
function (state) {
const c = db._collection(cn);
const i = c.index(state.indexDef.id);
assertEqual(state.masterProps.id, i.id);
assertEqual(state.masterProps.name, i.name);
},
true
);
},
testExistingIndexIdConflict: function () {
connectToMaster();
compare(
function (state) {
const c = db._create(cn);
state.indexDef = {type: 'hash', id: '1234567', fields: ['value']};
c.ensureIndex(state.indexDef);
state.masterProps = c.index(state.indexDef.id);
},
function (state) {
// already create the collection and index on the slave
const c = db._create(cn);
const def = {type: 'skiplist', id: '1234567', fields: ['value2']};
c.ensureIndex(def);
},
function (state) {
const c = db._collection(cn);
const i = c.index(state.indexDef.id);
assertEqual(state.indexDef.type, i.type);
assertEqual(state.masterProps.id, i.id);
assertEqual(state.masterProps.name, i.name);
},
true
);
},
testExistingSystemIndexIdConflict: function () {
connectToMaster();
compare(
function (state) {
const c = db._create(sysCn, {isSystem: true});
state.indexDef = {type: 'hash', id: '1234567', fields: ['value']};
c.ensureIndex(state.indexDef);
state.masterProps = c.index(state.indexDef.id);
},
function (state) {
// already create the index on the slave
const c = db._create(sysCn, {isSystem: true});
const def = {type: 'skiplist', id: '1234567', fields: ['value2']};
c.ensureIndex(def);
},
function (state) {
const c = db._collection(sysCn);
const i = c.index(state.indexDef.id);
assertEqual(state.indexDef.type, i.type);
assertEqual(state.masterProps.id, i.id);
assertEqual(state.masterProps.name, i.name);
},
true, true
);
},
testExistingIndexName: function () {
connectToMaster();
compare(
function (state) {
const c = db._create(cn);
state.indexDef = {type: 'skiplist', name: 'foo', fields: ['value']};
c.ensureIndex(state.indexDef);
state.masterProps = c.index(state.indexDef.name);
},
function (state) {
// already create the collection and index on the slave
const c = db._create(cn);
c.ensureIndex(state.indexDef);
},
function (state) {
const c = db._collection(cn);
const i = c.index(state.indexDef.name);
assertEqual(state.masterProps.id, i.id);
assertEqual(state.masterProps.name, i.name);
},
true
);
},
testExistingIndexNameConflict: function () {
connectToMaster();
compare(
function (state) {
const c = db._create(cn);
state.indexDef = {type: 'hash', name: 'foo', fields: ['value']};
c.ensureIndex(state.indexDef);
state.masterProps = c.index(state.indexDef.name);
},
function (state) {
// already create the collection and index on the slave
const c = db._create(cn);
const def = {type: 'skiplist', name: 'foo', fields: ['value2']};
c.ensureIndex(def);
},
function (state) {
const c = db._collection(cn);
const i = c.index(state.indexDef.name);
assertEqual(state.indexDef.type, i.type);
},
true
);
},
testExistingSystemIndexNameConflict: function () {
connectToMaster();
compare(
function (state) {
const c = db._create(sysCn, {isSystem: true});
state.indexDef = {type: 'hash', name: 'foo', fields: ['value3']};
c.ensureIndex(state.indexDef);
state.masterProps = c.index(state.indexDef.name);
},
function (state) {
// already create the index on the slave
const c = db._create(sysCn, {isSystem: true});
const def = {type: 'skiplist', name: 'foo', fields: ['value4']};
c.ensureIndex(def);
},
function (state) {
const c = db._collection(sysCn);
const i = c.index(state.indexDef.name);
assertEqual(state.indexDef.type, i.type);
},
true, true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test existing collection
// //////////////////////////////////////////////////////////////////////////////
testRemoveSomeWithIncremental: function () {
connectToMaster();
var st;
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ _key: 'test' + i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
st = _.clone(state); // save state
},
function (state) {
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
connectToSlave();
assertEqual(5000, collectionCount(cn));
var c = db._collection(cn);
// remove some random documents
for (var i = 0; i < 50; ++i) {
c.remove(c.any());
}
assertEqual(4950, collectionCount(cn));
// and sync again
replication.syncCollection(cn, {
endpoint: masterEndpoint,
verbose: true,
incremental: true
});
assertEqual(st.count, collectionCount(cn));
assertEqual(st.checksum, collectionChecksum(cn));
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test existing collection
// //////////////////////////////////////////////////////////////////////////////
testInsertSomeWithIncremental: function () {
connectToMaster();
var st;
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ _key: 'test' + i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
st = _.clone(state); // save state
},
function (state) {
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
connectToSlave();
let c = db._collection(cn);
// insert some random documents
let docs = [];
for (let i = 0; i < 100; ++i) {
docs.push({ foo: 'bar' + i });
}
c.insert(docs);
assertEqual(5100, collectionCount(cn));
// and sync again
replication.syncCollection(cn, {
endpoint: masterEndpoint,
verbose: true,
incremental: true
});
assertEqual(st.count, collectionCount(cn));
assertEqual(st.checksum, collectionChecksum(cn));
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test existing collection
// //////////////////////////////////////////////////////////////////////////////
testInsertHugeIncrementalMoreOnMaster: function () {
connectToMaster();
var st;
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ _key: 'test' + i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
st = _.clone(state); // save state
},
function (state) {
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
connectToMaster();
var c = db._collection(cn);
let docs = [];
// insert some documents 'before'
for (let i = 0; i < 110000; ++i) {
docs.push({ _key: 'a' + i });
if (docs.length === 5000) {
c.insert(docs);
docs = [];
}
}
// insert some documents 'after'
for (let i = 0; i < 110000; ++i) {
docs.push({ _key: 'z' + i });
if (docs.length === 5000) {
c.insert(docs);
docs = [];
}
}
// update the state
st.checksum = collectionChecksum(cn);
st.count = collectionCount(cn);
assertEqual(225000, collectionCount(cn));
connectToSlave();
// and sync again
replication.syncCollection(cn, {
endpoint: masterEndpoint,
verbose: true,
incremental: true
});
assertEqual(st.count, collectionCount(cn));
assertEqual(st.checksum, collectionChecksum(cn));
},
testInsertHugeIncrementalMoreOnSlave: function () {
connectToMaster();
var st;
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ _key: 'test' + i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
st = _.clone(state); // save state
},
function (state) {
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
connectToSlave();
var c = db._collection(cn);
let docs = [];
// insert some documents 'before'
for (let i = 0; i < 110000; ++i) {
docs.push({ _key: 'a' + i });
if (docs.length === 5000) {
c.insert(docs);
docs = [];
}
}
// insert some documents 'after'
for (let i = 0; i < 110000; ++i) {
docs.push({ _key: 'z' + i });
if (docs.length === 5000) {
c.insert(docs);
docs = [];
}
}
assertEqual(225000, collectionCount(cn));
// and sync again
replication.syncCollection(cn, {
endpoint: masterEndpoint,
verbose: true,
incremental: true
});
assertEqual(st.count, collectionCount(cn));
assertEqual(st.checksum, collectionChecksum(cn));
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test existing collection
// //////////////////////////////////////////////////////////////////////////////
testInsertHugeIncrementalLessOnMaster: function () {
connectToMaster();
var st;
compare(
function (state) {
let c = db._create(cn);
let docs = [];
// insert some documents 'before'
for (let i = 0; i < 110000; ++i) {
docs.push({ _key: 'a' + i });
if (docs.length === 5000) {
c.insert(docs);
docs = [];
}
}
// insert some documents 'after'
for (let i = 0; i < 110000; ++i) {
docs.push({ _key: 'z' + i });
if (docs.length === 5000) {
c.insert(docs);
docs = [];
}
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(220000, state.count);
st = _.clone(state); // save state
},
function (state) {
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
connectToMaster();
var c = db._collection(cn);
let docs = [];
// remove some documents from the 'front'
for (let i = 0; i < 50000; ++i) {
docs.push({ _key: 'a' + i });
if (docs.length === 5000) {
c.remove(docs);
docs = [];
}
}
// remove some documents from the 'back'
for (let i = 0; i < 50000; ++i) {
docs.push({ _key: 'z' + i });
if (docs.length === 5000) {
c.remove(docs);
docs = [];
}
}
// update the state
st.checksum = collectionChecksum(cn);
st.count = collectionCount(cn);
assertEqual(120000, collectionCount(cn));
connectToSlave();
// and sync again
replication.syncCollection(cn, {
endpoint: masterEndpoint,
verbose: true,
incremental: true
});
assertEqual(st.count, collectionCount(cn));
assertEqual(st.checksum, collectionChecksum(cn));
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test collection properties
// //////////////////////////////////////////////////////////////////////////////
testProperties: function () {
connectToMaster();
compare(
function (state) {
var c = db._create(cn);
c.properties({
indexBuckets: 32,
waitForSync: true,
journalSize: 16 * 1024 * 1024
});
},
function (state) {
// don't create the collection on the slave
},
function (state) {
var c = db._collection(cn);
var p = c.properties();
assertTrue(p.waitForSync);
if (mmfilesEngine) {
assertEqual(32, p.indexBuckets);
assertEqual(16 * 1024 * 1024, p.journalSize);
}
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test collection properties
// //////////////////////////////////////////////////////////////////////////////
testPropertiesOther: function () {
connectToMaster();
compare(
function (state) {
var c = db._create(cn);
c.properties({
indexBuckets: 32,
waitForSync: true,
journalSize: 16 * 1024 * 1024
});
},
function (state) {
// create the collection on the slave, but with default properties
db._create(cn);
},
function (state) {
var c = db._collection(cn);
var p = c.properties();
assertTrue(p.waitForSync);
if (mmfilesEngine) {
assertEqual(32, p.indexBuckets);
assertEqual(16 * 1024 * 1024, p.journalSize);
}
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with indexes
// //////////////////////////////////////////////////////////////////////////////
testCreateIndexes: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
'value1': i,
'value2': 'test' + i
});
}
c.insert(docs);
c.ensureIndex({
type: 'hash',
fields: ['value1', 'value2']
});
c.ensureIndex({
type: 'skiplist',
fields: ['value1']
});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
// create it with different values
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
'value1': i,
'value2': 'test' + i
});
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var idx = db._collection(cn).getIndexes();
assertEqual(3, idx.length); // primary + hash + skiplist
for (var i = 1; i < idx.length; ++i) {
assertFalse(idx[i].unique);
assertFalse(idx[i].sparse);
if (idx[i].type === 'hash') {
assertEqual('hash', idx[i].type);
assertEqual(['value1', 'value2'], idx[i].fields);
} else {
assertEqual('skiplist', idx[i].type);
assertEqual(['value1'], idx[i].fields);
}
}
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with views
// //////////////////////////////////////////////////////////////////////////////
testSyncView: function () {
connectToMaster();
// create view & collection on master
db._flushCache();
db._create(cn);
db._createView(cn + 'View', 'arangosearch');
db._flushCache();
connectToSlave();
internal.wait(0.1, false);
// sync on slave
replication.sync({ endpoint: masterEndpoint });
db._flushCache();
{
// check state is the same
let view = db._view(cn + 'View');
assertTrue(view !== null);
let props = view.properties();
assertTrue(props.hasOwnProperty('links'));
assertEqual(Object.keys(props.links).length, 0);
}
connectToMaster();
// update view properties
{
let view = db._view(cn + 'View');
let links = {};
links[cn] = {
includeAllFields: true,
fields: {
text: { analyzers: ['text_en'] }
}
};
view.properties({ links });
}
db._flushCache();
connectToSlave();
replication.sync({ endpoint: masterEndpoint });
{
let view = db._view(cn + 'View');
assertTrue(view !== null);
let props = view.properties();
assertTrue(props.hasOwnProperty('links'));
assertEqual(Object.keys(props.links).length, 1);
assertTrue(props.links.hasOwnProperty(cn));
}
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with edges
// //////////////////////////////////////////////////////////////////////////////
testEdges: function () {
connectToMaster();
compare(
function (state) {
var c = db._createEdgeCollection(cn);
var i;
for (i = 0; i < 100; ++i) {
c.save(cn + '/test' + i, cn + '/test' + (i % 10), {
_key: 'test' + i,
'value1': i,
'value2': 'test' + i
});
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(100, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
var c = db._collection(cn);
c.truncate(); // but empty it
for (var i = 0; i < 100; ++i) {
c.save(cn + '/test' + i, cn + '/test' + (i % 10), {
_key: 'test' + i,
'value1': i,
'value2': 'test' + i
});
}
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var c = db._collection(cn);
assertEqual(3, c.type());
for (var i = 0; i < 100; ++i) {
var doc = c.document('test' + i);
assertEqual(cn + '/test' + i, doc._from);
assertEqual(cn + '/test' + (i % 10), doc._to);
assertEqual(i, doc.value1);
assertEqual('test' + i, doc.value2);
}
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with edges differences
// //////////////////////////////////////////////////////////////////////////////
testEdgesDifferences: function () {
connectToMaster();
compare(
function (state) {
var c = db._createEdgeCollection(cn);
var i;
for (i = 0; i < 100; ++i) {
c.save(cn + '/test' + i, cn + '/test' + (i % 10), {
_key: 'test' + i,
'value1': i,
'value2': 'test' + i
});
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(100, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
var c = db._collection(cn);
c.truncate(); // but empty it
for (var i = 0; i < 200; ++i) {
c.save(
cn + '/test' + (i + 1),
cn + '/test' + (i % 11), {
_key: 'test' + i,
'value1': i,
'value2': 'test' + i
}
);
}
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var c = db._collection(cn);
assertEqual(3, c.type());
for (var i = 0; i < 100; ++i) {
var doc = c.document('test' + i);
assertEqual(cn + '/test' + i, doc._from);
assertEqual(cn + '/test' + (i % 10), doc._to);
assertEqual(i, doc.value1);
assertEqual('test' + i, doc.value2);
}
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test non-present collection
// //////////////////////////////////////////////////////////////////////////////
testNonPresent: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) { },
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
false
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test non-present collection
// //////////////////////////////////////////////////////////////////////////////
testNonPresentIncremental: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) { },
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test existing collection
// //////////////////////////////////////////////////////////////////////////////
testExisting: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
var c = db._collection(cn);
c.truncate(); // but empty it
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
false
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test existing collection
// //////////////////////////////////////////////////////////////////////////////
testExistingIncremental: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
var c = db._collection(cn);
c.truncate(); // but empty it
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - but empty on master
// //////////////////////////////////////////////////////////////////////////////
testExistingEmptyOnMaster: function () {
connectToMaster();
compare(
function (state) {
db._create(cn);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(0, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
false
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - but empty on master
// //////////////////////////////////////////////////////////////////////////////
testExistingEmptyOnMasterIncremental: function () {
connectToMaster();
compare(
function (state) {
db._create(cn);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(0, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - less on the slave
// //////////////////////////////////////////////////////////////////////////////
testExistingDocumentsLess: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
var c = db._collection(cn);
c.truncate(); // but empty it
for (var i = 0; i < 500; ++i) {
c.save({
'value': i
});
}
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
false
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - less on the slave
// //////////////////////////////////////////////////////////////////////////////
testExistingDocumentsLessIncremental: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
var c = db._collection(cn);
c.truncate(); // but empty it
for (var i = 0; i < 500; ++i) {
c.save({
'value': i
});
}
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - more on the slave
// //////////////////////////////////////////////////////////////////////////////
testMoreDocuments: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
false
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - more on the slave
// //////////////////////////////////////////////////////////////////////////////
testMoreDocumentsIncremental: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 6000; ++i) {
docs.push({ value: i });
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - same on the slave
// //////////////////////////////////////////////////////////////////////////////
testSameDocuments: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
value: i
});
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
value: i
});
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
false
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - same on the slave
// //////////////////////////////////////////////////////////////////////////////
testSameDocumentsIncremental: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
value: i
});
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
value: i
});
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - same on the slave but different keys
// //////////////////////////////////////////////////////////////////////////////
testSameSameButDifferentKeys: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
value: i
});
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
value: i
});
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
false
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - same on the slave but different keys
// //////////////////////////////////////////////////////////////////////////////
testSameSameButDifferentKeysIncremental: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
value: i
});
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
value: i
});
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - same on the slave but different values
// //////////////////////////////////////////////////////////////////////////////
testSameSameButDifferentValues: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
value1: i,
value2: 'test' + i
});
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
value1: 'test' + i,
value2: i
});
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
false
);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief test with existing documents - same on the slave but different values
// //////////////////////////////////////////////////////////////////////////////
testSameSameButDifferentValuesIncremental: function () {
connectToMaster();
compare(
function (state) {
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
value1: i,
value2: 'test' + i
});
}
c.insert(docs);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function (state) {
// already create the collection on the slave
replication.syncCollection(cn, {
endpoint: masterEndpoint,
incremental: false
});
let c = db._collection(cn);
c.truncate(); // but empty it
let docs = [];
for (let i = 0; i < 5000; ++i) {
docs.push({
_key: 'test' + i,
value1: 'test' + i,
value2: i
});
}
c.insert(docs);
},
function (state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
},
true
);
}
};
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief test suite on _system
// //////////////////////////////////////////////////////////////////////////////
function ReplicationSuite () {
'use strict';
let suite = {
// //////////////////////////////////////////////////////////////////////////////
// / @brief set up
// //////////////////////////////////////////////////////////////////////////////
setUp: function () {
connectToMaster();
try {
db._dropView(cn + 'View');
} catch (ignored) {}
db._drop(cn);
db._drop(sysCn, {isSystem: true});
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief tear down
// //////////////////////////////////////////////////////////////////////////////
tearDown: function () {
connectToMaster();
try {
db._dropView(cn + 'View');
} catch (ignored) {}
db._drop(cn);
db._drop(sysCn, {isSystem: true});
connectToSlave();
db._drop(cn);
db._drop(sysCn, {isSystem: true});
}
};
deriveTestSuite(BaseTestConfig(), suite, '_Repl');
return suite;
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief test suite on other database
// //////////////////////////////////////////////////////////////////////////////
function ReplicationOtherDBSuite () {
'use strict';
const dbName = 'UnitTestDB';
let suite = {
// //////////////////////////////////////////////////////////////////////////////
// / @brief set up
// //////////////////////////////////////////////////////////////////////////////
setUp: function () {
connectToMaster();
try {
db._dropDatabase(dbName);
} catch (e) {
}
db._createDatabase(dbName);
connectToSlave();
try {
db._dropDatabase(dbName);
} catch (e) {
}
db._createDatabase(dbName);
db._useDatabase(dbName);
connectToMaster();
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief tear down
// //////////////////////////////////////////////////////////////////////////////
tearDown: function () {
db._useDatabase('_system');
connectToMaster();
try {
db._dropDatabase(dbName);
} catch (e) {
}
connectToSlave();
try {
db._dropDatabase(dbName);
} catch (e) {
}
}
};
deriveTestSuite(BaseTestConfig(), suite, '_OtherRepl');
return suite;
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief test suite for incremental
// //////////////////////////////////////////////////////////////////////////////
function ReplicationIncrementalKeyConflict () {
'use strict';
return {
// //////////////////////////////////////////////////////////////////////////////
// / @brief set up
// //////////////////////////////////////////////////////////////////////////////
setUp: function () {
connectToMaster();
db._drop(cn);
},
// //////////////////////////////////////////////////////////////////////////////
// / @brief tear down
// //////////////////////////////////////////////////////////////////////////////
tearDown: function () {
connectToMaster();
db._drop(cn);
connectToSlave();
db._drop(cn);
},
testKeyConflicts: function () {
var c = db._create(cn);
c.ensureIndex({
type: 'hash',
fields: ['value'],
unique: true
});
c.insert({
_key: 'x',
value: 1
});
c.insert({
_key: 'y',
value: 2
});
c.insert({
_key: 'z',
value: 3
});
connectToSlave();
replication.syncCollection(cn, {
endpoint: masterEndpoint,
verbose: true
});
db._flushCache();
c = db._collection(cn);
assertEqual(3, c.count());
assertEqual(1, c.document('x').value);
assertEqual(2, c.document('y').value);
assertEqual(3, c.document('z').value);
assertEqual('hash', c.getIndexes()[1].type);
assertTrue(c.getIndexes()[1].unique);
connectToMaster();
db._flushCache();
c = db._collection(cn);
c.remove('z');
c.insert({
_key: 'w',
value: 3
});
assertEqual(3, c.count());
assertEqual(3, c.document('w').value);
assertEqual(1, c.document('x').value);
assertEqual(2, c.document('y').value);
connectToSlave();
replication.syncCollection(cn, {
endpoint: masterEndpoint,
verbose: true,
incremental: true
});
db._flushCache();
c = db._collection(cn);
assertEqual(3, c.count());
assertEqual(3, c.document('w').value);
assertEqual(1, c.document('x').value);
assertEqual(2, c.document('y').value);
assertEqual('hash', c.getIndexes()[1].type);
assertTrue(c.getIndexes()[1].unique);
},
testKeyConflictsManyDocuments: function () {
var c = db._create(cn);
var i;
c.ensureIndex({
type: 'hash',
fields: ['value'],
unique: true
});
for (i = 0; i < 10000; ++i) {
c.insert({
_key: 'test' + i,
value: i
});
}
connectToSlave();
replication.syncCollection(cn, {
endpoint: masterEndpoint,
verbose: true
});
db._flushCache();
c = db._collection(cn);
assertEqual(10000, c.count());
assertEqual('hash', c.getIndexes()[1].type);
assertTrue(c.getIndexes()[1].unique);
connectToMaster();
db._flushCache();
c = db._collection(cn);
c.remove('test0');
c.remove('test1');
c.remove('test9998');
c.remove('test9999');
c.insert({
_key: 'test0',
value: 9999
});
c.insert({
_key: 'test1',
value: 9998
});
c.insert({
_key: 'test9998',
value: 1
});
c.insert({
_key: 'test9999',
value: 0
});
assertEqual(10000, c.count());
connectToSlave();
replication.syncCollection(cn, {
endpoint: masterEndpoint,
verbose: true,
incremental: true
});
db._flushCache();
c = db._collection(cn);
assertEqual(10000, c.count());
assertEqual('hash', c.getIndexes()[1].type);
assertTrue(c.getIndexes()[1].unique);
}
};
}
// //////////////////////////////////////////////////////////////////////////////
// / @brief executes the test suite
// //////////////////////////////////////////////////////////////////////////////
jsunity.run(ReplicationSuite);
jsunity.run(ReplicationOtherDBSuite);
jsunity.run(ReplicationIncrementalKeyConflict);
return jsunity.done();