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

2193 lines
64 KiB
JavaScript

/*jshint globalstrict:false, strict:false, unused: false */
/*global fail, assertEqual, assertNotEqual, assertTrue, assertFalse, assertNull, arango, ARGUMENTS */
////////////////////////////////////////////////////////////////////////////////
/// @brief test 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 errors = arangodb.errors;
const db = arangodb.db;
const replication = require("@arangodb/replication");
const compareTicks = require("@arangodb/replication-common").compareTicks;
const console = require("console");
const internal = require("internal");
const masterEndpoint = arango.getEndpoint();
const slaveEndpoint = ARGUMENTS[0];
const mmfilesEngine = (db._engine().name === "mmfiles");
const cn = "UnitTestsReplication";
const cn2 = "UnitTestsReplication2";
const systemCn = "_UnitTestsReplicationSys";
// these must match the values in the Makefile!
const replicatorUser = "replicator-user";
const replicatorPassword = "replicator-password";
const connectToMaster = function() {
arango.reconnect(masterEndpoint, db._name(), replicatorUser, replicatorPassword);
};
const connectToSlave = function() {
arango.reconnect(slaveEndpoint, db._name(), "root", "");
};
const collectionChecksum = function(name) {
var c = db._collection(name).checksum(true, true);
return c.checksum;
};
const collectionCount = function(name) {
return db._collection(name).count();
};
const compare = function(masterFunc, slaveFunc, applierConfiguration) {
var state = {};
db._flushCache();
masterFunc(state);
connectToSlave();
replication.applier.stop();
while (replication.applier.state().state.running) {
internal.wait(0.1, false);
}
var includeSystem = true;
var restrictType = "";
var restrictCollections = [];
if (typeof applierConfiguration === 'object') {
if (applierConfiguration.hasOwnProperty("includeSystem")) {
includeSystem = applierConfiguration.includeSystem;
}
if (applierConfiguration.hasOwnProperty("restrictType")) {
restrictType = applierConfiguration.restrictType;
}
if (applierConfiguration.hasOwnProperty("restrictCollections")) {
restrictCollections = applierConfiguration.restrictCollections;
}
}
var syncResult = replication.sync({
endpoint: masterEndpoint,
username: replicatorUser,
password: replicatorPassword,
verbose: true,
includeSystem: includeSystem,
restrictType: restrictType,
restrictCollections: restrictCollections,
waitForSyncTimeout: 120
});
db._flushCache();
slaveFunc(state);
assertTrue(syncResult.hasOwnProperty('lastLogTick'));
applierConfiguration = applierConfiguration || {};
applierConfiguration.endpoint = masterEndpoint;
applierConfiguration.username = replicatorUser;
applierConfiguration.password = replicatorPassword;
applierConfiguration.includeSystem = includeSystem;
if (!applierConfiguration.hasOwnProperty('chunkSize')) {
applierConfiguration.chunkSize = 16384;
}
replication.applier.properties(applierConfiguration);
replication.applier.start(syncResult.lastLogTick);
var printed = false;
while (true) {
var slaveState = replication.applier.state();
if (slaveState.state.lastError.errorNum > 0) {
console.warn("slave has errored:", JSON.stringify(slaveState.state.lastError));
break;
}
if (!slaveState.state.running) {
console.warn("slave is not running");
break;
}
if (compareTicks(slaveState.state.lastAppliedContinuousTick, syncResult.lastLogTick) >= 0 ||
compareTicks(slaveState.state.lastProcessedContinuousTick, syncResult.lastLogTick) >= 0) {
console.debug("slave has caught up. syncResult.lastLogTick:", syncResult.lastLogTick, "slaveState.lastAppliedContinuousTick:", slaveState.state.lastAppliedContinuousTick, "slaveState.lastProcessedContinuousTick:", slaveState.state.lastProcessedContinuousTick, "slaveState:", slaveState);
break;
}
if (!printed) {
console.debug("waiting for slave to catch up");
printed = true;
}
internal.wait(0.5, false);
}
db._flushCache();
slaveFunc(state);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Base Test Config. Identitical part for _system and other DB
////////////////////////////////////////////////////////////////////////////////
function BaseTestConfig() {
'use strict';
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid credentials
////////////////////////////////////////////////////////////////////////////////
testInvalidCredentials1: function() {
var configuration = {
endpoint: masterEndpoint,
username: replicatorUser,
password: replicatorPassword + "xx" // invalid
};
try {
replication.applier.properties(configuration);
} catch (err) {
assertEqual(errors.ERROR_HTTP_UNAUTHORIZED.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid credentials
////////////////////////////////////////////////////////////////////////////////
testInvalidCredentials2: function() {
var configuration = {
endpoint: masterEndpoint,
username: replicatorUser + "xx", // invalid
password: replicatorPassword
};
try {
replication.applier.properties(configuration);
} catch (err) {
assertEqual(errors.ERROR_HTTP_UNAUTHORIZED.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test invalid credentials
////////////////////////////////////////////////////////////////////////////////
testInvalidCredentials3: function() {
var configuration = {
endpoint: masterEndpoint,
username: "root",
password: "abc"
};
try {
replication.applier.properties(configuration);
} catch (err) {
assertEqual(errors.ERROR_HTTP_UNAUTHORIZED.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test trx with multiple collections
////////////////////////////////////////////////////////////////////////////////
testTrxMultiCollections: function() {
connectToMaster();
compare(
function() {
db._create(cn);
db._create(cn2);
db[cn].insert({ _key: "foo", value: 1 });
db[cn2].insert({ _key: "bar", value: "A" });
db._executeTransaction({
collections: {
write: [ cn, cn2 ]
},
action: function(params) {
var c = require("internal").db._collection(params.cn);
var c2 = require("internal").db._collection(params.cn2);
c.replace("foo", { value: 2 });
c.insert({ _key: "foo2", value: 3 });
c2.replace("bar", { value: "B" });
c2.insert({ _key: "bar2", value: "C" });
},
params: { cn, cn2 }
});
},
function() {
assertEqual(2, db[cn].count());
assertEqual(2, db[cn].document("foo").value);
assertEqual(3, db[cn].document("foo2").value);
assertEqual(2, db[cn2].count());
assertEqual("B", db[cn2].document("bar").value);
assertEqual("C", db[cn2].document("bar2").value);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test few documents
////////////////////////////////////////////////////////////////////////////////
testFew: function() {
connectToMaster();
compare(
function(state) {
var c = db._create(cn);
for (var i = 0; i < 5000; ++i) {
c.save({
"value": i
});
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(5000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test many documents
////////////////////////////////////////////////////////////////////////////////
testMany: function() {
connectToMaster();
compare(
function(state) {
var c = db._create(cn),
i;
for (i = 0; i < 50000; ++i) {
c.save({
"value": i
});
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(50000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test many documents
////////////////////////////////////////////////////////////////////////////////
testManyMore: function() {
connectToMaster();
compare(
function(state) {
var c = db._create(cn),
i;
for (i = 0; i < 150000; ++i) {
c.save({
"value": i
});
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(150000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test big markers
////////////////////////////////////////////////////////////////////////////////
testBigMarkersObject: function() {
connectToMaster();
compare(
function(state) {
var c = db._create(cn),
i;
var doc = {};
for (i = 0; i < 1000; ++i) {
doc["test" + i] = "the quick brown foxx jumped over the LAZY dog";
}
for (i = 0; i < 100; ++i) {
c.save({
"value": i,
"values": doc
});
}
var d = c.any();
assertEqual(1000, Object.keys(d.values).length);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(100, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test big markers
////////////////////////////////////////////////////////////////////////////////
testBigMarkersArray: function() {
connectToMaster();
compare(
function(state) {
var c = db._create(cn),
i;
var doc = [];
for (i = 0; i < 1000; ++i) {
doc.push("the quick brown foxx jumped over the LAZY dog");
}
for (i = 0; i < 100; ++i) {
c.save({
"value": i,
"values": doc
});
}
var d = c.any();
assertEqual(1000, d.values.length);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(100, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test heterogenous markers
////////////////////////////////////////////////////////////////////////////////
testHeterogenousMarkers: function() {
connectToMaster();
compare(
function(state) {
var c = db._create(cn),
i;
for (i = 0; i < 1000; ++i) {
var doc = {};
doc["test" + i] = "the quick brown foxx jumped over the LAZY dog";
c.save({
"value": i,
"values": doc
});
}
var d = c.any();
assertEqual(1, Object.keys(d.values).length);
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(1000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test empty markers
////////////////////////////////////////////////////////////////////////////////
testEmptyMarkers: function() {
connectToMaster();
compare(
function(state) {
var c = db._create(cn),
i;
for (i = 0; i < 1000; ++i) {
c.save({});
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(1000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test documents
////////////////////////////////////////////////////////////////////////////////
testDocuments1: function() {
compare(
function(state) {
var c = db._create(cn),
i;
for (i = 0; i < 1000; ++i) {
c.save({
"value": i,
"foo": true,
"bar": [i, false],
"value2": null,
"mydata": {
"test": ["abc", "def"]
}
});
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(1000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test documents
////////////////////////////////////////////////////////////////////////////////
testDocuments2: function() {
compare(
function(state) {
var c = db._create(cn),
i;
for (i = 0; i < 1000; ++i) {
c.save({
"abc": true,
"_key": "test" + i
});
if (i % 3 === 0) {
c.remove("test" + i);
} else if (i % 5 === 0) {
c.update("test" + i, {
"def": "hifh"
});
}
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(666, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test documents
////////////////////////////////////////////////////////////////////////////////
testDocuments3: function() {
compare(
function(state) {
var c = db._create(cn),
i;
for (i = 0; i < 50000; ++i) {
c.save({
"_key": "test" + i,
"foo": "bar",
"baz": "bat"
});
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(50000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test documents
////////////////////////////////////////////////////////////////////////////////
testDocuments4: function() {
compare(
function(state) {
var c = db._create(cn),
i;
for (i = 0; i < 50000; ++i) {
c.save({
"_key": "test" + i,
"foo": "bar",
"baz": "bat"
});
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(50000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}, {
chunkSize: 512
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test documents
////////////////////////////////////////////////////////////////////////////////
testDocuments5: function() {
compare(
function(state) {
var c = db._create(cn),
i;
for (i = 0; i < 100; ++i) {
c.save({
"abc": true,
"_key": "test" + i
});
if (i % 3 === 0) {
c.remove("test" + i);
} else if (i % 5 === 0) {
c.update("test" + i, {
"def": "hifh"
});
}
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(66, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test edges
////////////////////////////////////////////////////////////////////////////////
testEdges: function() {
compare(
function(state) {
var v = db._create(cn),
i;
var e = db._createEdgeCollection(cn2);
for (i = 0; i < 1000; ++i) {
v.save({
"_key": "test" + i
});
}
for (i = 0; i < 5000; i += 10) {
e.save(cn + "/test" + i, cn + "/test" + i, {
"foo": "bar",
"value": i
});
}
state.checksum1 = collectionChecksum(cn);
state.count1 = collectionCount(cn);
assertEqual(1000, state.count1);
state.checksum2 = collectionChecksum(cn2);
state.count2 = collectionCount(cn2);
assertEqual(500, state.count2);
},
function(state) {
assertEqual(state.count1, collectionCount(cn));
assertEqual(state.checksum1, collectionChecksum(cn));
assertEqual(state.count2, collectionCount(cn2));
assertEqual(state.checksum2, collectionChecksum(cn2));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test transactions
////////////////////////////////////////////////////////////////////////////////
testTransactionInsert: function() {
compare(
function(state) {
db._create(cn);
db._executeTransaction({
collections: {
write: cn
},
action: function(params) {
var c = require("internal").db._collection(params.cn);
for (var i = 0; i < 1000; ++i) {
c.save({
"_key": "test" + i
});
}
},
params: { cn }
});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(1000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test transactions
////////////////////////////////////////////////////////////////////////////////
testTransactionInsertFail: function() {
compare(
function(state) {
var c = db._create(cn);
try {
db._executeTransaction({
collections: {
write: cn
},
action: function(params) {
var c = require("@arangodb").db._collection(params.cn);
for (var i = 0; i < 1000; ++i) {
c.save({
"_key": "test" + i
});
}
throw "rollback!";
},
params: { cn }
});
fail();
} catch (err) {}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(0, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test transactions
////////////////////////////////////////////////////////////////////////////////
testTransactionRemove: function() {
compare(
function(state) {
var c = db._create(cn);
for (var i = 0; i < 1000; ++i) {
c.save({
"_key": "test" + i
});
}
db._executeTransaction({
collections: {
write: cn
},
action: function(params) {
var c = require("@arangodb").db._collection(params.cn);
for (var i = 0; i < 1000; ++i) {
c.remove("test" + i);
}
},
params: { cn }
});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(0, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test transactions
////////////////////////////////////////////////////////////////////////////////
testTransactionRemoveFail: function() {
compare(
function(state) {
var c = db._create(cn);
for (var i = 0; i < 1000; ++i) {
c.save({
"_key": "test" + i
});
}
try {
db._executeTransaction({
collections: {
write: cn
},
action: function(params) {
var c = require("@arangodb").db._collection(params.cn);
for (var i = 0; i < 1000; ++i) {
c.remove("test" + i);
}
throw "peng!";
},
params: { cn }
});
} catch (err) {
}
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(1000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test transactions
////////////////////////////////////////////////////////////////////////////////
testTransactionMultiOps: function() {
compare(
function(state) {
db._create(cn);
db._executeTransaction({
collections: {
write: cn
},
action: function(params) {
var c = require("internal").db._collection(params.cn),
i;
for (i = 0; i < 1000; ++i) {
c.save({
"_key": "test" + i
});
}
for (i = 0; i < 1000; ++i) {
c.update("test" + i, {
"foo": "bar" + i
});
}
for (i = 0; i < 1000; ++i) {
c.update("test" + i, {
"foo": "baz" + i
});
}
for (i = 0; i < 1000; i += 10) {
c.remove("test" + i);
}
},
params: {
"cn": cn
},
});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(900, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test big transaction
////////////////////////////////////////////////////////////////////////////////
testTransactionBig: function() {
compare(
function(state) {
db._create(cn);
db._executeTransaction({
collections: {
write: cn
},
action: function(params) {
var c = require("internal").db._collection(params.cn),
i;
for (i = 0; i < 50000; ++i) {
c.save({
"_key": "test" + i,
value: i
});
c.update("test" + i, {
value: i + 1
});
if (i % 5 === 0) {
c.remove("test" + i);
}
}
},
params: {
"cn": cn
},
});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(40000, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}, {
chunkSize: 2048
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test delayed transaction
////////////////////////////////////////////////////////////////////////////////
testTransactionDelayed: function() {
compare(
function(state) {
db._create(cn);
db._executeTransaction({
collections: {
write: cn
},
action: function(params) {
var c = require("internal").db._collection(params.cn),
i;
var wait = require("internal").wait;
for (i = 0; i < 10; ++i) {
c.save({
"_key": "test" + i,
value: i
});
c.update("test" + i, {
value: i + 1
});
wait(1, false);
}
},
params: {
"cn": cn
},
});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(10, state.count);
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
}, {
chunkSize: 2048
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test transactions
////////////////////////////////////////////////////////////////////////////////
testTransactionMulti: function() {
compare(
function(state) {
db._create(cn);
db._create(cn2);
db._executeTransaction({
collections: {
write: [cn, cn2]
},
action: function(params) {
var c1 = require("internal").db._collection(params.cn);
var c2 = require("internal").db._collection(params.cn2);
var i;
for (i = 0; i < 1000; ++i) {
c1.save({
"_key": "test" + i
});
c2.save({
"_key": "test" + i,
"foo": "bar"
});
}
for (i = 0; i < 1000; ++i) {
c1.update("test" + i, {
"foo": "bar" + i
});
}
for (i = 0; i < 1000; ++i) {
c1.update("test" + i, {
"foo": "baz" + i
});
c2.update("test" + i, {
"foo": "baz" + i
});
}
for (i = 0; i < 1000; i += 10) {
c1.remove("test" + i);
c2.remove("test" + i);
}
},
params: {
"cn": cn,
"cn2": cn2
},
});
state.checksum1 = collectionChecksum(cn);
state.checksum2 = collectionChecksum(cn2);
state.count1 = collectionCount(cn);
state.count2 = collectionCount(cn2);
assertEqual(900, state.count1);
assertEqual(900, state.count2);
},
function(state) {
assertEqual(state.count1, collectionCount(cn));
assertEqual(state.count2, collectionCount(cn2));
assertEqual(state.checksum1, collectionChecksum(cn));
assertEqual(state.checksum2, collectionChecksum(cn2));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test transactions
////////////////////////////////////////////////////////////////////////////////
testTransactionAbort: function() {
compare(
function(state) {
db._create(cn);
db._create(cn2);
db._collection(cn).save({
foo: "bar"
});
db._collection(cn2).save({
bar: "baz"
});
try {
db._executeTransaction({
collections: {
write: [cn, cn2]
},
action: function(params) {
var c1 = require("internal").db._collection(params.cn);
var c2 = require("internal").db._collection(params.cn2);
var i;
for (i = 0; i < 1000; ++i) {
c1.save({
"_key": "test" + i
});
c2.save({
"_key": "test" + i,
"foo": "bar"
});
}
for (i = 0; i < 1000; ++i) {
c1.update("test" + i, {
"foo": "bar" + i
});
}
for (i = 0; i < 1000; ++i) {
c1.update("test" + i, {
"foo": "baz" + i
});
c2.update("test" + i, {
"foo": "baz" + i
});
}
for (i = 0; i < 1000; i += 10) {
c1.remove("test" + i);
c2.remove("test" + i);
}
throw "rollback!";
},
params: {
"cn": cn,
"cn2": cn2
},
});
fail();
} catch (err) {}
state.checksum1 = collectionChecksum(cn);
state.checksum2 = collectionChecksum(cn2);
state.count1 = collectionCount(cn);
state.count2 = collectionCount(cn2);
assertEqual(1, state.count1);
assertEqual(1, state.count2);
},
function(state) {
assertEqual(state.count1, collectionCount(cn));
assertEqual(state.count2, collectionCount(cn2));
assertEqual(state.checksum1, collectionChecksum(cn));
assertEqual(state.checksum2, collectionChecksum(cn2));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test rename collection
////////////////////////////////////////////////////////////////////////////////
testRenameCollection1: function() {
compare(
function(state) {
var c = db._create(cn, {
isVolatile: mmfilesEngine,
waitForSync: false,
doCompact: false,
journalSize: 1048576,
keyOptions: {
allowUserKeys: false
},
});
c.rename(cn2);
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
try {
db._collection(cn).properties();
fail();
} catch (err) {
// original collection was renamed
}
var properties = db._collection(cn2).properties();
assertEqual(cn2, db._collection(cn2).name());
if (mmfilesEngine) {
assertTrue(properties.isVolatile);
assertFalse(properties.doCompact);
assertEqual(1048576, properties.journalSize);
}
assertFalse(properties.waitForSync);
assertFalse(properties.deleted);
assertFalse(properties.keyOptions.allowUserKeys);
assertEqual("traditional", properties.keyOptions.type);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test rename collection
////////////////////////////////////////////////////////////////////////////////
testRenameCollection2: function() {
compare(
function(state) {
var c = db._create(cn);
c.rename(cn2);
c.rename(cn);
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
try {
db._collection(cn2).properties();
fail();
} catch (err) {
// collection was renamed
}
assertEqual(cn, db._collection(cn).name());
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test change collection
////////////////////////////////////////////////////////////////////////////////
testChangeCollection1: function() {
compare(
function(state) {
var c = db._create(cn, {
waitForSync: false,
doCompact: false,
journalSize: 1048576
});
var properties = c.properties();
assertFalse(properties.waitForSync);
if (mmfilesEngine) {
assertFalse(properties.doCompact);
assertEqual(1048576, properties.journalSize);
}
properties = c.properties({
waitForSync: true,
doCompact: true,
journalSize: 2097152
});
assertTrue(properties.waitForSync);
if (mmfilesEngine) {
assertTrue(properties.doCompact);
assertEqual(2097152, properties.journalSize);
assertTrue(properties.hasOwnProperty("indexBuckets"));
}
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
var properties = db._collection(cn).properties();
assertEqual(cn, db._collection(cn).name());
assertTrue(properties.waitForSync);
if (mmfilesEngine) {
assertTrue(properties.doCompact);
assertEqual(2097152, properties.journalSize);
assertTrue(properties.hasOwnProperty("indexBuckets"));
assertEqual(properties.indexBuckets, properties.indexBuckets);
}
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test change collection
////////////////////////////////////////////////////////////////////////////////
testChangeCollection2: function() {
compare(
function(state) {
var c = db._create(cn, {
waitForSync: true,
doCompact: true,
journalSize: 2097152
});
var properties = c.properties();
assertTrue(properties.waitForSync);
if (mmfilesEngine) {
assertTrue(properties.doCompact);
assertEqual(2097152, properties.journalSize);
}
properties = c.properties({
waitForSync: false,
doCompact: false,
journalSize: 1048576
});
assertFalse(properties.waitForSync);
if (mmfilesEngine) {
assertFalse(properties.doCompact);
assertEqual(1048576, properties.journalSize);
assertTrue(properties.hasOwnProperty("indexBuckets"));
}
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
var properties = db._collection(cn).properties();
assertEqual(cn, db._collection(cn).name());
assertFalse(properties.waitForSync);
if (mmfilesEngine) {
assertFalse(properties.doCompact);
assertEqual(1048576, properties.journalSize);
assertTrue(properties.hasOwnProperty("indexBuckets"));
assertEqual(properties.indexBuckets, properties.indexBuckets);
}
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test change collection
////////////////////////////////////////////////////////////////////////////////
testChangeCollectionIndexBuckets: function() {
if (mmfilesEngine) {
compare(
function(state) {
var c = db._create(cn, {
indexBuckets: 4
});
var properties = c.properties();
assertEqual(4, properties.indexBuckets);
properties = c.properties({
indexBuckets: 8
});
assertEqual(8, properties.indexBuckets);
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
var properties = db._collection(cn).properties();
assertEqual(8, properties.indexBuckets);
}
);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test create collection
////////////////////////////////////////////////////////////////////////////////
testCreateCollection1: function() {
compare(
function(state) {
var c = db._create(cn, {
isVolatile: mmfilesEngine,
waitForSync: false,
doCompact: false,
journalSize: 1048576
});
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
var properties = db._collection(cn).properties();
assertEqual(cn, db._collection(cn).name());
assertFalse(properties.waitForSync);
assertFalse(properties.deleted);
if (mmfilesEngine) {
assertTrue(properties.isVolatile);
assertFalse(properties.doCompact);
assertEqual(1048576, properties.journalSize);
assertTrue(properties.hasOwnProperty("indexBuckets"));
}
assertTrue(properties.keyOptions.allowUserKeys);
assertEqual("traditional", properties.keyOptions.type);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test create collection
////////////////////////////////////////////////////////////////////////////////
testCreateCollection2: function() {
compare(
function(state) {
var c = db._create(cn, {
keyOptions: {
type: "autoincrement",
allowUserKeys: false
},
isVolatile: false,
waitForSync: true,
doCompact: true,
journalSize: 2097152
});
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
var properties = db._collection(cn).properties();
assertEqual(cn, db._collection(cn).name());
assertFalse(properties.isVolatile);
assertTrue(properties.waitForSync);
assertFalse(properties.deleted);
if (mmfilesEngine) {
assertTrue(properties.doCompact);
assertEqual(2097152, properties.journalSize);
assertTrue(properties.hasOwnProperty("indexBuckets"));
}
assertFalse(properties.keyOptions.allowUserKeys);
assertEqual("autoincrement", properties.keyOptions.type);
}
);
},
testCreateCollectionKeygenUuid: function() {
compare(
function(state) {
var c = db._create(cn, {
keyOptions: {
type: "uuid",
allowUserKeys: false
}
});
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
var properties = db._collection(cn).properties();
assertEqual(cn, db._collection(cn).name());
assertFalse(properties.keyOptions.allowUserKeys);
assertEqual("uuid", properties.keyOptions.type);
}
);
},
testCreateCollectionKeygenPadded: function() {
compare(
function(state) {
var c = db._create(cn, {
keyOptions: {
type: "padded",
allowUserKeys: false
}
});
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
var properties = db._collection(cn).properties();
assertEqual(cn, db._collection(cn).name());
assertFalse(properties.keyOptions.allowUserKeys);
assertEqual("padded", properties.keyOptions.type);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test create collection
////////////////////////////////////////////////////////////////////////////////
testCreateCollectionIndexBuckets1: function() {
if (mmfilesEngine) {
compare(
function(state) {
var c = db._create(cn, {
indexBuckets: 16
});
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
var properties = db._collection(cn).properties();
assertEqual(cn, db._collection(cn).name());
assertEqual(16, properties.indexBuckets);
}
);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test create collection
////////////////////////////////////////////////////////////////////////////////
testCreateCollectionIndexBuckets2: function() {
if (mmfilesEngine) {
compare(
function(state) {
var c = db._create(cn, {
indexBuckets: 8
});
state.cid = c._id;
state.properties = c.properties();
},
function(state) {
var properties = db._collection(cn).properties();
assertEqual(cn, db._collection(cn).name());
assertEqual(8, properties.indexBuckets);
}
);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test drop collection
////////////////////////////////////////////////////////////////////////////////
testDropCollection: function() {
compare(
function(state) {
var c = db._create(cn);
c.drop();
},
function(state) {
assertNull(db._collection(cn));
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test hash index
////////////////////////////////////////////////////////////////////////////////
testHashIndex: function() {
compare(
function(state) {
var c = db._create(cn),
i;
c.ensureHashIndex("a", "b");
for (i = 0; i < 1000; ++i) {
c.save({
"_key": "test" + i,
"a": parseInt(i / 2),
"b": i
});
}
c.save({});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(1001, state.count);
state.idx = c.getIndexes()[1];
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var idx = db._collection(cn).getIndexes()[1];
assertEqual(state.idx.id, idx.id);
assertEqual("hash", state.idx.type);
assertFalse(state.idx.unique);
assertFalse(state.idx.sparse);
assertEqual(["a", "b"], state.idx.fields);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test hash index
////////////////////////////////////////////////////////////////////////////////
testSparseHashIndex: function() {
compare(
function(state) {
var c = db._create(cn),
i;
c.ensureHashIndex("a", "b", {
sparse: true
});
for (i = 0; i < 1000; ++i) {
c.save({
"_key": "test" + i,
"a": parseInt(i / 2),
"b": i
});
}
c.save({});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(1001, state.count);
state.idx = c.getIndexes()[1];
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var idx = db._collection(cn).getIndexes()[1];
assertEqual(state.idx.id, idx.id);
assertEqual("hash", state.idx.type);
assertFalse(state.idx.unique);
assertTrue(state.idx.sparse);
assertEqual(["a", "b"], state.idx.fields);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unique constraint
////////////////////////////////////////////////////////////////////////////////
testUniqueConstraint: function() {
compare(
function(state) {
var c = db._create(cn),
i;
c.ensureUniqueConstraint("a");
for (i = 0; i < 1000; ++i) {
try {
c.save({
"_key": "test" + i,
"a": parseInt(i / 2)
});
} catch (err) {}
}
c.save({});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(501, state.count);
state.idx = c.getIndexes()[1];
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var idx = db._collection(cn).getIndexes()[1];
assertEqual(state.idx.id, idx.id);
assertEqual("hash", state.idx.type);
assertTrue(state.idx.unique);
assertFalse(state.idx.sparse);
assertEqual(["a"], state.idx.fields);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unique constraint
////////////////////////////////////////////////////////////////////////////////
testSparseUniqueConstraint: function() {
compare(
function(state) {
var c = db._create(cn),
i;
c.ensureUniqueConstraint("a", {
sparse: true
});
for (i = 0; i < 1000; ++i) {
try {
c.save({
"_key": "test" + i,
"a": parseInt(i / 2)
});
} catch (err) {}
}
c.save({});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(501, state.count);
state.idx = c.getIndexes()[1];
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var idx = db._collection(cn).getIndexes()[1];
assertEqual(state.idx.id, idx.id);
assertEqual("hash", state.idx.type);
assertTrue(state.idx.unique);
assertTrue(state.idx.sparse);
assertEqual(["a"], state.idx.fields);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test skiplist
////////////////////////////////////////////////////////////////////////////////
testSkiplist: function() {
compare(
function(state) {
var c = db._create(cn),
i;
c.ensureSkiplist("a", "b");
for (i = 0; i < 1000; ++i) {
c.save({
"_key": "test" + i,
"a": parseInt(i / 2),
"b": i
});
}
c.save({});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(1001, state.count);
state.idx = c.getIndexes()[1];
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var idx = db._collection(cn).getIndexes()[1];
assertEqual(state.idx.id, idx.id);
assertEqual("skiplist", state.idx.type);
assertFalse(state.idx.unique);
assertFalse(state.idx.sparse);
assertEqual(["a", "b"], state.idx.fields);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test skiplist
////////////////////////////////////////////////////////////////////////////////
testSparseSkiplist: function() {
compare(
function(state) {
var c = db._create(cn),
i;
c.ensureSkiplist("a", "b", {
sparse: true
});
for (i = 0; i < 1000; ++i) {
c.save({
"_key": "test" + i,
"a": parseInt(i / 2),
"b": i
});
}
c.save({});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(1001, state.count);
state.idx = c.getIndexes()[1];
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var idx = db._collection(cn).getIndexes()[1];
assertEqual(state.idx.id, idx.id);
assertEqual("skiplist", state.idx.type);
assertFalse(state.idx.unique);
assertTrue(state.idx.sparse);
assertEqual(["a", "b"], state.idx.fields);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unique skiplist
////////////////////////////////////////////////////////////////////////////////
testUniqueSkiplist: function() {
compare(
function(state) {
var c = db._create(cn),
i;
c.ensureUniqueSkiplist("a");
for (i = 0; i < 1000; ++i) {
try {
c.save({
"_key": "test" + i,
"a": parseInt(i / 2)
});
} catch (err) {}
}
c.save({});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(501, state.count);
state.idx = c.getIndexes()[1];
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var idx = db._collection(cn).getIndexes()[1];
assertEqual(state.idx.id, idx.id);
assertEqual("skiplist", state.idx.type);
assertTrue(state.idx.unique);
assertFalse(state.idx.sparse);
assertEqual(["a"], state.idx.fields);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test unique skiplist
////////////////////////////////////////////////////////////////////////////////
testUniqueSparseSkiplist: function() {
compare(
function(state) {
var c = db._create(cn),
i;
c.ensureUniqueSkiplist("a", {
sparse: true
});
for (i = 0; i < 1000; ++i) {
try {
c.save({
"_key": "test" + i,
"a": parseInt(i / 2)
});
} catch (err) {}
}
c.save({});
state.checksum = collectionChecksum(cn);
state.count = collectionCount(cn);
assertEqual(501, state.count);
state.idx = c.getIndexes()[1];
},
function(state) {
assertEqual(state.count, collectionCount(cn));
assertEqual(state.checksum, collectionChecksum(cn));
var idx = db._collection(cn).getIndexes()[1];
assertEqual(state.idx.id, idx.id);
assertEqual("skiplist", state.idx.type);
assertTrue(state.idx.unique);
assertTrue(state.idx.sparse);
assertEqual(["a"], state.idx.fields);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test system collection
////////////////////////////////////////////////////////////////////////////////
testSystemCollectionWithDefaults: function() {
compare(
function(state) {
var c = db._create(systemCn, {
isSystem: true
});
c.save({
_key: "UnitTester",
testValue: 42
});
},
function(state) {
var doc = db[systemCn].document("UnitTester");
assertEqual(42, doc.testValue);
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test system collection
////////////////////////////////////////////////////////////////////////////////
testSystemCollectionExcludeSystem: function() {
compare(
function(state) {
var c = db._create(systemCn, {
isSystem: true
});
c.save({
_key: "UnitTester",
testValue: 42
});
},
function(state) {
assertNull(db._collection(systemCn));
}, {
includeSystem: false
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test system collection
////////////////////////////////////////////////////////////////////////////////
testSystemCollectionExcludeCollection: function() {
compare(
function(state) {
var c = db._create(systemCn, {
isSystem: true
});
c.save({
_key: "UnitTester",
testValue: 42
});
},
function(state) {
assertNull(db._collection(systemCn));
}, {
includeSystem: true,
restrictType: "exclude",
restrictCollections: [systemCn]
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test system collection
////////////////////////////////////////////////////////////////////////////////
testSystemCollectionIncludeCollection: function() {
compare(
function(state) {
var c = db._create(systemCn, {
isSystem: true
});
c.save({
_key: "UnitTester",
testValue: 42
});
},
function(state) {
var doc = db[systemCn].document("UnitTester");
assertEqual(42, doc.testValue);
}, {
includeSystem: true,
restrictType: "include",
restrictCollections: [systemCn]
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test include/exclude collection
////////////////////////////////////////////////////////////////////////////////
testCollectionIncludeCollection: function() {
compare(
function(state) {
var c1 = db._create(cn);
var c2 = db._create(cn2);
c1.save({
_key: "UnitTester",
testValue: 42
});
c2.save({
_key: "UnitTester",
testValue: 23
});
},
function(state) {
var doc = db[cn].document("UnitTester");
assertEqual(42, doc.testValue);
assertNull(db._collection(cn2));
}, {
restrictType: "include",
restrictCollections: [cn]
}
);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test include/exclude collection
////////////////////////////////////////////////////////////////////////////////
testCollectionExcludeCollection: function() {
compare(
function(state) {
var c1 = db._create(cn);
var c2 = db._create(cn2);
c1.save({
_key: "UnitTester",
testValue: 42
});
c2.save({
_key: "UnitTester",
testValue: 23
});
},
function(state) {
var doc = db[cn].document("UnitTester");
assertEqual(42, doc.testValue);
assertNull(db._collection(cn2));
}, {
restrictType: "exclude",
restrictCollections: [cn2]
}
);
},
testViewBasic: function() {
compare(
function(state) {
try {
db._create(cn);
let view = db._createView("UnitTestsSyncView", "arangosearch", {});
let links = {};
links[cn] = {
includeAllFields: true,
fields: {
text: { analyzers: [ "text_en" ] }
}
};
view.properties({"links": links});
state.arangoSearchEnabled = true;
} catch (err) { }
},
function(state) {
if (!state.arangoSearchEnabled) {
return;
}
let view = db._view("UnitTestsSyncView");
assertTrue(view !== null);
let props = view.properties();
assertEqual(Object.keys(props.links).length, 1);
assertTrue(props.hasOwnProperty("links"));
assertTrue(props.links.hasOwnProperty(cn));
}
);
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite on _system
////////////////////////////////////////////////////////////////////////////////
function ReplicationSuite() {
'use strict';
let suite = BaseTestConfig();
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
suite.setUp = function() {
connectToSlave();
try {
replication.applier.stop();
replication.applier.forget();
}
catch (err) {
}
connectToMaster();
db._drop(cn);
db._drop(cn2);
db._drop(systemCn, { isSystem: true });
};
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
suite.tearDown = function() {
connectToMaster();
db._drop(cn);
db._drop(cn2);
db._drop(systemCn, { isSystem: true });
connectToSlave();
replication.applier.stop();
replication.applier.forget();
db._drop(cn);
db._drop(cn2);
db._drop(systemCn, { isSystem: true });
};
return suite;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite on other DB
////////////////////////////////////////////////////////////////////////////////
function ReplicationOtherDBSuite() {
let suite = BaseTestConfig();
const testDB = "UnitTestDB";
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
suite.setUp = function() {
db._useDatabase("_system");
// Slave side code
connectToSlave();
try {
replication.applier.stop();
replication.applier.forget();
}
catch (err) {
}
try {
db._dropDatabase(testDB);
} catch (e) {
}
db._createDatabase(testDB);
assertNotEqual(-1, db._databases().indexOf(testDB));
// Master side code
connectToMaster();
try {
db._dropDatabase(testDB);
} catch (e) {
}
db._createDatabase(testDB);
assertNotEqual(-1, db._databases().indexOf(testDB));
// We now have an empty testDB
db._useDatabase(testDB);
// Use it and setup replication
};
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
suite.tearDown = function() {
// Just drop the databases
connectToMaster();
db._useDatabase("_system");
try {
db._dropDatabase(testDB);
} catch (e) {}
assertEqual(-1, db._databases().indexOf(testDB));
connectToSlave();
// We need to stop applier in testDB
db._useDatabase(testDB);
replication.applier.stop();
replication.applier.forget();
db._useDatabase("_system");
try {
db._dropDatabase(testDB);
} catch (e) {}
assertEqual(-1, db._databases().indexOf(testDB));
};
return suite;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(ReplicationSuite);
jsunity.run(ReplicationOtherDBSuite);
return jsunity.done();