1
0
Fork 0
arangodb/tests/js/common/replication/replication.js

2592 lines
79 KiB
JavaScript

/*jshint globalstrict:false, strict:false */
/*global assertEqual, assertTrue, assertMatch, assertNotEqual
assertUndefined, assertFalse, fail, REPLICATION_LOGGER_LAST */
////////////////////////////////////////////////////////////////////////////////
/// @brief test the replication functions
///
/// @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
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var arangodb = require("@arangodb");
var errors = arangodb.errors;
var db = arangodb.db;
var internal = require("internal");
var replication = require("@arangodb/replication");
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function ReplicationLoggerSuite () {
'use strict';
var cn = "UnitTestsReplication";
var cn2 = "UnitTestsReplication2";
var getLastLogTick = function () {
while (true) {
var s = replication.logger.state();
if (s.state.lastLogTick === s.state.lastUncommittedLogTick) {
return s.state.lastLogTick;
}
internal.wait(0.05, false);
}
};
var getLogEntries = function (tick, type) {
var result = [ ];
getLastLogTick();
var exclude = function(name) {
return (name.substr(0, 11) === '_statistics' ||
name === '_apps' ||
name === '_foxxlog' ||
name === '_jobs' ||
name === '_queues' ||
name === '_sessions');
};
var entries = REPLICATION_LOGGER_LAST(tick, "9999999999999999999");
if (Array.isArray(type)) {
entries.forEach(function(e) {
if ((e.type === 2300 || e.type === 2302) && e.cname && exclude(e.cname)) {
// exclude statistics markers here
return;
}
if (type.indexOf(e.type) !== -1) {
result.push(e);
}
});
}
else {
entries.forEach(function(e) {
if ((e.type === 2300 || e.type === 2302) && e.cname && exclude(e.cname)) {
// exclude statistics markers here
return;
}
if (type === undefined || e.type === type) {
result.push(e);
}
});
}
return result;
};
var compareTicks = function (l, r) {
var i;
if (l.length !== r.length) {
return l.length - r.length < 0 ? -1 : 1;
}
// length is equal
for (i = 0; i < l.length; ++i) {
if (l[i] !== r[i]) {
return l[i] < r[i] ? -1 : 1;
}
}
return 0;
};
var waitForTick = function (value) {
while (true) {
var state = replication.logger.state().state;
if (compareTicks(state.lastLogTick, value) > 0) {
break;
}
internal.wait(0.1, false);
}
};
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
db._drop(cn);
db._drop(cn2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief get ticks
////////////////////////////////////////////////////////////////////////////////
testGetLoggerTicks : function () {
var state, tick;
getLastLogTick();
state = replication.logger.state().state;
assertTrue(state.running);
tick = state.lastLogTick;
assertTrue(typeof tick === 'string');
assertMatch(/^\d+$/, state.lastLogTick);
tick = state.lastUncommittedLogTick;
assertTrue(typeof tick === 'string');
assertMatch(/^\d+$/, state.lastLogTick);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief get state
////////////////////////////////////////////////////////////////////////////////
testGetLoggerState : function () {
var state, tick, server;
getLastLogTick();
state = replication.logger.state().state;
assertTrue(state.running);
tick = state.lastLogTick;
assertTrue(typeof tick === 'string');
assertNotEqual("", state.time);
assertMatch(/^\d+-\d+-\d+T\d+:\d+:\d+Z$/, state.time);
// query the state again
state = replication.logger.state().state;
assertTrue(state.running);
if (db._engine().name !== "rocksdb") {
assertEqual(tick, state.lastLogTick);
}
assertTrue(typeof state.lastLogTick === 'string');
assertMatch(/^\d+$/, state.lastLogTick);
assertTrue(state.totalEvents >= 0);
server = replication.logger.state().server;
assertEqual(server.version, db._version());
assertNotEqual("", server.serverId);
assertMatch(/^\d+$/, server.serverId);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test logging disabled
////////////////////////////////////////////////////////////////////////////////
testDisabledLogger : function () {
var state, tick, events;
state = replication.logger.state().state;
assertTrue(state.running);
tick = state.lastLogTick;
assertTrue(typeof tick === 'string');
assertMatch(/^\d+$/, state.lastLogTick);
events = state.totalEvents;
assertTrue(state.totalEvents >= 0);
// do something that will cause logging (if it was enabled...)
var c = db._create(cn);
c.save({ "test" : 1 });
waitForTick(tick);
state = replication.logger.state().state;
assertTrue(state.running);
assertMatch(/^\d+$/, state.lastLogTick);
assertEqual(1, compareTicks(state.lastLogTick, tick));
assertTrue(state.totalEvents > events);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test logging enabled
////////////////////////////////////////////////////////////////////////////////
testEnabledLogger : function () {
var state, tick, events;
state = replication.logger.state().state;
assertTrue(state.running);
tick = state.lastLogTick;
assertTrue(typeof tick === 'string');
assertMatch(/^\d+$/, state.lastLogTick);
events = state.totalEvents;
assertTrue(state.totalEvents >= 0);
// do something that will cause logging
var c = db._create(cn);
c.save({ "test" : 1 });
waitForTick(tick);
state = replication.logger.state().state;
assertTrue(state.running);
assertMatch(/^\d+$/, state.lastLogTick);
assertTrue(state.totalEvents >= 1);
assertNotEqual(tick, state.lastLogTick);
assertEqual(1, compareTicks(state.lastLogTick, tick));
assertTrue(state.totalEvents > events);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test first tick
////////////////////////////////////////////////////////////////////////////////
testFirstTick : function () {
var state = replication.logger.state().state;
assertTrue(state.running);
var tick = state.lastLogTick;
assertTrue(typeof tick === 'string');
assertMatch(/^\d+$/, tick);
var firstTick = replication.logger.firstTick();
assertTrue(typeof firstTick === 'string');
assertMatch(/^\d+$/, firstTick);
assertEqual(-1, compareTicks(firstTick, tick));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test tick ranges
////////////////////////////////////////////////////////////////////////////////
testTickRanges : function () {
var state = replication.logger.state().state;
assertTrue(state.running);
var tick = state.lastLogTick;
assertTrue(typeof tick === 'string');
assertMatch(/^\d+$/, tick);
var ranges = replication.logger.tickRanges();
assertTrue(Array.isArray(ranges));
assertTrue(ranges.length > 0);
for (var i = 0; i < ranges.length; ++i) {
var df = ranges[i];
assertTrue(typeof df === 'object');
assertTrue(df.hasOwnProperty('datafile'));
assertTrue(df.hasOwnProperty('status'));
assertTrue(df.hasOwnProperty('tickMin'));
assertTrue(df.hasOwnProperty('tickMax'));
assertTrue(typeof df.datafile === 'string');
assertTrue(typeof df.status === 'string');
assertTrue(typeof df.tickMin === 'string');
assertMatch(/^\d+$/, df.tickMin);
assertTrue(typeof df.tickMax === 'string');
assertMatch(/^\d+$/, df.tickMax);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateCollection : function () {
var tick = getLastLogTick();
var c = db._create(cn);
var entry = getLogEntries(tick, 2000)[0];
assertEqual(2000, entry.type);
assertEqual(2, entry.data.type);
assertEqual(c._id, entry.cid);
assertEqual(c._id, entry.data.cid);
assertFalse(entry.data.deleted);
assertEqual(cn, entry.data.name);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerDropCollection : function () {
var c = db._create(cn);
var tick = getLastLogTick();
db._drop(cn);
var entry = getLogEntries(tick, 2001)[0];
assertEqual(2001, entry.type);
assertEqual(c._id, entry.cid);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerRenameCollection : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.rename(cn2);
var entry = getLogEntries(tick, 2002)[0];
assertEqual(2002, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(cn2, entry.data.name);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerPropertiesCollection : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.properties({ waitForSync: true, journalSize: 2097152 });
var entry = getLogEntries(tick, 2003)[0];
assertEqual(2003, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(c._id, entry.data.cid);
assertEqual(cn, entry.data.name);
assertEqual(2, entry.data.type);
assertEqual(false, entry.data.deleted);
if (db._engine().name === "mmfiles") {
assertEqual(2097152, entry.data.journalSize);
assertEqual(true, entry.data.waitForSync);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerIncludedSystemCollection1 : function () {
var c = db._collection("_graphs");
var tick = getLastLogTick();
var doc = c.save({ "test": 1 });
var entry = getLogEntries(tick, 2300)[0];
assertEqual(2300, entry.type);
assertEqual(c._id, entry.cid);
tick = getLastLogTick();
c.remove(doc._key);
entry = getLogEntries(tick, 2302)[0];
assertEqual(2302, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(doc._key, entry.data._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerIncludedSystemCollection2 : function () {
var c = db._collection("_users");
var tick = getLastLogTick();
var doc = c.save({ "test": 1 });
var entry = getLogEntries(tick, 2300)[0];
assertEqual(2300, entry.type);
assertEqual(c._id, entry.cid);
tick = getLastLogTick();
c.remove(doc._key);
entry = getLogEntries(tick, 2302)[0];
assertEqual(2302, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(doc._key, entry.data._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerSystemCollection : function () {
db._drop("_unittests", true);
var tick = getLastLogTick();
var c = db._create("_unittests", { isSystem : true });
try {
var entry = getLogEntries(tick, 2000)[0];
assertEqual(2000, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(c.name(), entry.data.name);
tick = getLastLogTick();
c.properties({ waitForSync : true });
entry = getLogEntries(tick, 2003)[0];
assertEqual(2003, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(true, entry.data.waitForSync);
tick = getLastLogTick();
} finally {
db._drop("_unittests", true);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTruncateCollection1 : function () {
var c = db._create(cn);
c.save({ "test": 1, "_key": "abc" });
var tick = getLastLogTick();
c.truncate({ compact: false });
var entry = getLogEntries(tick, 2302);
assertEqual(1, entry.length);
assertNotEqual("0", entry[0].tid);
assertEqual(c._id, entry[0].cid);
assertEqual("abc", entry[0].data._key);
c.save({ "test": 1, "_key": "abc" });
tick = getLastLogTick();
c.truncate({ compact: false });
entry = getLogEntries(tick, 2302);
assertNotEqual("0", entry[0].tid);
assertEqual(c._id, entry[0].cid);
assertEqual("abc", entry[0].data._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTruncateCollection2 : function () {
var i;
var c = db._create(cn);
for (i = 0; i < 100; ++i) {
c.save({ "test": 1, "_key": "test" + i });
}
var tick = getLastLogTick();
c.truncate({ compact: false });
getLastLogTick();
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2302 ]);
assertEqual(102, entry.length);
// trx start
assertEqual(2200, entry[0].type);
assertNotEqual("", entry[0].tid);
var tid = entry[0].tid;
// remove
var keys = { };
for (i = 0; i < 100; ++i) {
assertEqual(2302, entry[i + 1].type);
assertEqual(tid, entry[i + 1].tid);
assertEqual(c._id, entry[i + 1].cid);
keys[entry[i + 1].data._key] = true;
}
assertEqual(100, Object.keys(keys).length);
// commit
assertEqual(2201, entry[101].type);
assertEqual(tid, entry[101].tid);
},
testLoggerTruncateCollectionRocksDB : function () {
if (db._engine().name !== 'rocksdb') {
return;
}
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 32769; ++i) {
docs.push({ "_key": "test" + i ,value: i });
if (docs.length === 5000) {
c.insert(docs);
docs = [];
}
}
c.insert(docs);
let tick = getLastLogTick();
c.truncate({ compact: false });
getLastLogTick();
let entry = getLogEntries(tick);
assertEqual(1, entry.length);
// truncate marker
assertEqual(2004, entry[0].type);
},
testLoggerTruncateCollectionAndThenSomeRocksDB : function () {
if (db._engine().name !== 'rocksdb') {
return;
}
let c = db._create(cn);
let docs = [];
for (let i = 0; i < 32769; ++i) {
docs.push({ "_key": "test" + i ,value: i });
if (docs.length === 5000) {
c.insert(docs);
docs = [];
}
}
c.insert(docs);
let tick = getLastLogTick();
c.truncate({ compact: false });
c.insert({ _key: "aha" });
getLastLogTick();
let entry = getLogEntries(tick);
assertEqual(2, entry.length);
// truncate marker
assertEqual(2004, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual("aha", entry[1].data._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexHash1 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureUniqueConstraint("a", "b");
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("hash", entry.data.type);
assertEqual(true, entry.data.unique);
assertEqual(false, entry.data.sparse);
assertEqual([ "a", "b" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexHash2 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureHashIndex("a");
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("hash", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual(false, entry.data.sparse);
assertEqual([ "a" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexSparseHash1 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureUniqueConstraint("a", "b", { sparse: true });
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("hash", entry.data.type);
assertEqual(true, entry.data.unique);
assertEqual(true, entry.data.sparse);
assertEqual([ "a", "b" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexSparseHash2 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureHashIndex("a", { sparse: true });
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("hash", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual(true, entry.data.sparse);
assertEqual([ "a" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexSkiplist1 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureSkiplist("a", "b", "c");
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("skiplist", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual(false, entry.data.sparse);
assertEqual([ "a", "b", "c" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexSkiplist2 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureUniqueSkiplist("a");
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("skiplist", entry.data.type);
assertEqual(true, entry.data.unique);
assertEqual(false, entry.data.sparse);
assertEqual([ "a" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexSparseSkiplist1 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureSkiplist("a", "b", "c", { sparse: true });
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("skiplist", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual(true, entry.data.sparse);
assertEqual([ "a", "b", "c" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexSparseSkiplist2 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureUniqueSkiplist("a", { sparse: true });
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("skiplist", entry.data.type);
assertEqual(true, entry.data.unique);
assertEqual(true, entry.data.sparse);
assertEqual([ "a" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexFulltext1 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureFulltextIndex("a", 5);
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("fulltext", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual(5, entry.data.minLength);
assertEqual([ "a" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexGeo1 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureGeoIndex("a", "b");
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("geo", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual([ "a", "b" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexGeo2 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureGeoIndex("a", true);
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("geo", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual([ "a" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexGeo3 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureGeoConstraint("a", "b", true);
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("geo", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual(true, entry.data.sparse);
assertEqual([ "a", "b" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexGeo4 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureGeoConstraint("a", "b", false);
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("geo", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual(true, entry.data.sparse);
assertEqual([ "a", "b" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerCreateIndexGeo5 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.ensureGeoConstraint("a", true);
var idx = c.getIndexes()[1];
var entry = getLogEntries(tick, 2100)[0];
assertTrue(2100, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
assertEqual("geo", entry.data.type);
assertEqual(false, entry.data.unique);
assertEqual(true, entry.data.sparse);
assertEqual([ "a" ], entry.data.fields);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerDropIndex : function () {
var c = db._create(cn);
c.ensureUniqueConstraint("a", "b");
var tick = getLastLogTick();
// use index at #1 (#0 is primary index)
var idx = c.getIndexes()[1];
c.dropIndex(idx);
var entry = getLogEntries(tick, 2101)[0];
assertTrue(2101, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(idx.id.replace(/^.*\//, ''), entry.data.id);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerSaveDocument : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.save({ "test": 1, "_key": "abc" });
var rev = c.document("abc")._rev;
var entry = getLogEntries(tick, 2300)[0];
assertEqual(2300, entry.type);
assertEqual(c._id, entry.cid);
assertEqual("abc", entry.data._key);
assertEqual(rev, entry.data._rev);
assertEqual(1, entry.data.test);
tick = getLastLogTick();
c.save({ "test": 2, "foo" : "bar", "_key": "12345" });
rev = c.document("12345")._rev;
entry = getLogEntries(tick, 2300)[0];
assertEqual(2300, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(c.name(), entry.cname);
assertEqual("12345", entry.data._key);
assertEqual(rev, entry.data._rev);
assertEqual(2, entry.data.test);
assertEqual("bar", entry.data.foo);
try {
c.save({ "test": 1, "_key": "12345" });
fail();
}
catch (err) {
}
entry = getLogEntries(tick, 2300);
assertEqual(1, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerSaveDocuments : function () {
var c = db._create(cn);
var tick = getLastLogTick();
for (var i = 0; i < 100; ++i) {
c.save({ "test": 1, "_key": "test" + i });
}
var entry = getLogEntries(tick, 2300);
assertEqual(100, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerDeleteDocument : function () {
var c = db._create(cn);
c.save({ "test": 1, "_key": "abc" });
c.save({ "test": 1, "_key": "12345" });
var tick = getLastLogTick();
c.remove("abc");
var entry = getLogEntries(tick, 2302)[0];
assertEqual(2302, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(c.name(), entry.cname);
assertEqual("abc", entry.data._key);
tick = getLastLogTick();
c.remove("12345");
entry = getLogEntries(tick, 2302)[0];
assertEqual(2302, entry.type);
assertEqual(c._id, entry.cid);
assertEqual("12345", entry.data._key);
tick = getLastLogTick();
try {
c.remove("12345");
fail();
}
catch (err) {
}
entry = getLogEntries(tick, 2302);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerUpdateDocument : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.save({ "test": 2, "_key": "abc" });
c.save({ "test": 1, "_key": "12345" });
c.update("abc", { "test" : 2 });
var entry = getLogEntries(tick, 2300);
assertEqual(2300, entry[0].type);
assertEqual(c._id, entry[0].cid);
assertEqual(c.name(), entry[0].cname);
assertEqual("abc", entry[0].data._key);
assertEqual(2, entry[0].data.test);
assertEqual(2300, entry[1].type);
assertEqual(c._id, entry[1].cid);
assertEqual(c.name(), entry[1].cname);
assertEqual("12345", entry[1].data._key);
assertEqual(1, entry[1].data.test);
tick = getLastLogTick();
c.update("abc", { "test" : 3 });
entry = getLogEntries(tick, 2300)[0];
assertEqual(2300, entry.type);
assertEqual(c._id, entry.cid);
assertEqual(c.name(), entry.cname);
assertEqual("abc", entry.data._key);
assertEqual(3, entry.data.test);
tick = getLastLogTick();
c.update("abc", { "test" : 3 });
c.update("12345", { "test" : 2 });
c.update("abc", { "test" : 4 });
entry = getLogEntries(tick, 2300);
assertEqual(3, entry.length);
tick = getLastLogTick();
try {
c.update("thefoxx", { });
fail();
}
catch (err) {
}
entry = getLogEntries(tick, 2300);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerReplaceDocument : function () {
var c = db._create(cn);
var tick = getLastLogTick();
c.save({ "test": 2, "_key": "abc" });
c.save({ "test": 1, "_key": "12345" });
c.replace("abc", { "test" : 2 });
var entry = getLogEntries(tick, 2300);
assertEqual(2300, entry[0].type);
assertEqual(c._id, entry[0].cid);
assertEqual(c.name(), entry[0].cname);
assertEqual("abc", entry[0].data._key);
assertEqual(2, entry[0].data.test);
assertEqual(2300, entry[1].type);
assertEqual(c._id, entry[1].cid);
assertEqual(c.name(), entry[1].cname);
assertEqual("12345", entry[1].data._key);
assertEqual(1, entry[1].data.test);
tick = getLastLogTick();
c.replace("abc", { "test" : 3 });
c.replace("abc", { "test" : 3 });
c.replace("12345", { "test" : 2 });
c.replace("abc", { "test" : 4 });
entry = getLogEntries(tick, 2300);
assertEqual(4, entry.length);
tick = getLastLogTick();
try {
c.replace("thefoxx", { });
fail();
}
catch (err) {
}
entry = getLogEntries(tick, 2300);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerSaveEdge : function () {
var c = db._create(cn);
var e = db._createEdgeCollection(cn2);
var tick = getLastLogTick();
e.save(cn + "/test1", cn + "/test2", { "test": 1, "_key": "abc" });
var entry = getLogEntries(tick, 2300)[0];
assertEqual(2300, entry.type);
assertEqual(e._id, entry.cid);
assertEqual(e.name(), entry.cname);
assertEqual("abc", entry.data._key);
assertEqual(c.name() + "/test1", entry.data._from);
assertEqual(c.name() + "/test2", entry.data._to);
assertEqual(1, entry.data.test);
tick = getLastLogTick();
e.save(cn + "/test3", cn + "/test4", { "test": [ 99, false ], "_key": "12345" });
entry = getLogEntries(tick, 2300)[0];
assertEqual(2300, entry.type);
assertEqual(e._id, entry.cid);
assertEqual(e.name(), entry.cname);
assertEqual("12345", entry.data._key);
assertEqual(c.name() + "/test3", entry.data._from);
assertEqual(c.name() + "/test4", entry.data._to);
assertEqual([ 99, false ], entry.data.test);
tick = getLastLogTick();
try {
e.save();
fail();
}
catch (err) {
}
entry = getLogEntries(tick, 2300);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerDeleteEdge : function () {
db._create(cn);
var e = db._createEdgeCollection(cn2);
e.save(cn + "/test1", cn + "/test2", { "test": 1, "_key": "abc" });
e.save(cn + "/test3", cn + "/test4", { "test": 1, "_key": "12345" });
var tick = getLastLogTick();
e.remove("abc");
var entry = getLogEntries(tick, 2302)[0];
assertEqual(2302, entry.type);
assertEqual(e._id, entry.cid);
assertEqual(e.name(), entry.cname);
assertEqual("abc", entry.data._key);
e.remove("12345");
tick = getLastLogTick();
try {
e.remove("12345");
fail();
}
catch (err) {
}
entry = getLogEntries(tick, 2302);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerUpdateEdge : function () {
var c = db._create(cn);
var e = db._createEdgeCollection(cn2);
var tick = getLastLogTick();
e.save(cn + "/test1", cn + "/test2", { "test": 2, "_key": "abc" });
e.save(cn + "/test3", cn + "/test4", { "test": 1, "_key": "12345" });
e.update("abc", { "test" : 2 });
var entry = getLogEntries(tick, 2300);
assertEqual(2300, entry[0].type);
assertEqual(e._id, entry[0].cid);
assertEqual(e.name(), entry[0].cname);
assertEqual("abc", entry[0].data._key);
assertEqual(2, entry[0].data.test);
assertEqual(c.name() + "/test1", entry[0].data._from);
assertEqual(c.name() + "/test2", entry[0].data._to);
assertEqual(2300, entry[1].type);
assertEqual(e._id, entry[1].cid);
assertEqual(e.name(), entry[1].cname);
assertEqual("12345", entry[1].data._key);
assertEqual(1, entry[1].data.test);
assertEqual(c.name() + "/test3", entry[1].data._from);
assertEqual(c.name() + "/test4", entry[1].data._to);
tick = getLastLogTick();
e.update("abc", { "test" : 3 });
e.update("12345", { "test" : 2 });
e.update("abc", { "test" : 4 });
entry = getLogEntries(tick, 2300);
assertEqual(3, entry.length);
tick = getLastLogTick();
try {
e.update("thefoxx", { });
fail();
}
catch (err) {
}
entry = getLogEntries(tick, 2300);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerReplaceEdge : function () {
var c = db._create(cn);
var e = db._createEdgeCollection(cn2);
var tick = getLastLogTick();
e.save(cn + "/test1", cn + "/test2", { "test": 2, "_key": "abc" });
e.save(cn + "/test3", cn + "/test4", { "test": 1, "_key": "12345" });
e.replace("abc", { _from: c.name() + "/test1", _to: c.name() + "/test2", "test" : 2 });
var entry = getLogEntries(tick, 2300);
assertEqual(2300, entry[0].type);
assertEqual(e._id, entry[0].cid);
assertEqual(e.name(), entry[0].cname);
assertEqual("abc", entry[0].data._key);
assertEqual(2, entry[0].data.test);
assertEqual(c.name() + "/test1", entry[0].data._from);
assertEqual(c.name() + "/test2", entry[0].data._to);
assertEqual(2300, entry[1].type);
assertEqual(e._id, entry[1].cid);
assertEqual(e.name(), entry[1].cname);
assertEqual("12345", entry[1].data._key);
assertEqual(1, entry[1].data.test);
assertEqual(c.name() + "/test3", entry[1].data._from);
assertEqual(c.name() + "/test4", entry[1].data._to);
tick = getLastLogTick();
e.replace("abc", { _from: cn + "/test1", _to: cn + "/test2", "test" : 3 });
e.replace("abc", { _from: cn + "/test1", _to: cn + "/test2", "test" : 3 });
e.replace("12345", { _from: cn + "/test3", _to: cn + "/test4", "test" : 2 });
e.replace("abc", { _from: cn + "/test1", _to: cn + "/test2", "test" : 4 });
entry = getLogEntries(tick, 2300);
assertEqual(4, entry.length);
tick = getLastLogTick();
try {
e.replace("thefoxx", { });
fail();
}
catch (err) {
}
entry = getLogEntries(tick, 2300);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionEmpty : function () {
db._create(cn);
var tick = getLastLogTick();
var actual = db._executeTransaction({
collections: {
},
action: function () {
return true;
}
});
assertTrue(actual);
var entry = getLogEntries(tick, 2200);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionRead1 : function () {
var c = db._create(cn);
c.save({ "test" : 1 });
var tick = getLastLogTick();
var actual = db._executeTransaction({
collections: {
read: cn
},
action: function () {
return true;
}
});
assertTrue(actual);
var entry = getLogEntries(tick, 2200);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionRead2 : function () {
var c = db._create(cn);
c.save({ "test" : 1, "_key": "abc" });
var tick = getLastLogTick();
var actual = db._executeTransaction({
collections: {
read: cn
},
action: function (params) {
var c = require("internal").db._collection(params.cn);
c.document("abc");
return true;
},
params: {
cn: cn
}
});
assertTrue(actual);
var entry = getLogEntries(tick, [ 2200, 2201, 2202 ]);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionRead3 : function () {
db._create(cn);
var tick = getLastLogTick();
try {
var actual = db._executeTransaction({
collections: {
read: cn
},
action: function (params) {
var c = require("internal").db._collection(params.cn);
c.save({ "foo" : "bar" });
return true;
},
params: {
cn: cn
}
});
actual = true;
fail();
}
catch (err) {
}
var entry = getLogEntries(tick, [ 2200, 2201, 2202 ]);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionWrite1 : function () {
db._create(cn);
var tick = getLastLogTick();
var actual = db._executeTransaction({
collections: {
write: cn
},
action: function () {
return true;
}
});
assertTrue(actual);
var entry = getLogEntries(tick, [ 2200, 2201, 2202 ]);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionWrite2 : function () {
var c = db._create(cn);
var tick = getLastLogTick();
var actual = db._executeTransaction({
collections: {
write: cn
},
action: function (params) {
var c = require("internal").db._collection(params.cn);
c.save({ "test" : 2, "_key": "abc" });
return true;
},
params: {
cn: cn
}
});
assertTrue(actual);
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300 ]);
assertEqual(3, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2201, entry[2].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(c._id, entry[1].cid);
assertEqual("abc", entry[1].data._key);
assertEqual(c._id, entry[1].cid);
assertEqual(2, entry[1].data.test);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionWrite3 : function () {
if (db._engine().name === "rocksdb") {
return;
}
db._create(cn);
var tick = getLastLogTick();
try {
db._executeTransaction({
collections: {
write: cn
},
action: function (params) {
var c = require("internal").db._collection(params.cn);
c.save({ "test" : 2, "_key": "abc" });
throw "fail";
},
params: {
cn: cn
}
});
fail();
}
catch (err) {
}
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300 ]);
assertEqual(3, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2202, entry[2].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionWrite4 : function () {
db._create(cn);
db._create(cn2);
var tick = getLastLogTick();
try {
db._executeTransaction({
collections: {
write: cn
},
action: function (params) {
var c2 = require("internal").db._collection(params.cn2);
// we're using a wrong collection here
c2.save({ "test" : 2, "_key": "abc" });
},
params: {
cn2: cn2
}
});
fail();
}
catch (err) {
}
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300 ]);
assertEqual(0, entry.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionWrite5 : function () {
db._create(cn);
db._create(cn2);
var tick = getLastLogTick();
db._executeTransaction({
collections: {
write: [ cn, cn2 ]
},
action: function (params) {
var c2 = require("internal").db._collection(params.cn);
c2.save({ "test" : 1, "_key": "12345" });
c2.save({ "test" : 2, "_key": "abc" });
},
params: {
cn: cn
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300 ]);
assertEqual(4, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2300, entry[2].type);
assertEqual(2201, entry[3].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(entry[2].tid, entry[3].tid);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionWrite6 : function () {
var c1 = db._create(cn);
var c2 = db._create(cn2);
var tick = getLastLogTick();
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);
c1.save({ "test" : 1, "_key": "12345" });
c2.save({ "test" : 2, "_key": "abc" });
},
params: {
cn: cn,
cn2: cn2
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300 ]);
assertEqual(4, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2300, entry[2].type);
assertEqual(2201, entry[3].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(entry[2].tid, entry[3].tid);
assertEqual(c1._id, entry[1].cid);
assertEqual(c2._id, entry[2].cid);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionUpdate : function () {
var c1 = db._create(cn);
c1.insert({ _key: "foo", value: 1 });
var tick = getLastLogTick();
db._executeTransaction({
collections: {
write: [ cn ]
},
action: function (params) {
var c1 = require("internal").db._collection(params.cn);
c1.update("foo", { value: 2 });
c1.insert({ _key: "foo2", value: 3 });
},
params: {
cn: cn
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300 ]);
assertEqual(4, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2300, entry[2].type);
assertEqual(2201, entry[3].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(entry[2].tid, entry[3].tid);
assertEqual("UnitTestsReplication", entry[1].cname);
assertEqual("foo", entry[1].data._key);
assertEqual(2, entry[1].data.value);
assertEqual("UnitTestsReplication", entry[2].cname);
assertEqual("foo2", entry[2].data._key);
assertEqual(3, entry[2].data.value);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionReplace : function () {
var c1 = db._create(cn);
c1.insert({ _key: "foo", value: 1 });
var tick = getLastLogTick();
db._executeTransaction({
collections: {
write: [ cn ]
},
action: function (params) {
var c1 = require("internal").db._collection(params.cn);
c1.replace("foo", { value2: 2 });
c1.insert({ _key: "foo2", value2: 3 });
},
params: {
cn: cn
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300 ]);
assertEqual(4, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2300, entry[2].type);
assertEqual(2201, entry[3].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(entry[2].tid, entry[3].tid);
assertEqual("UnitTestsReplication", entry[1].cname);
assertEqual("foo", entry[1].data._key);
assertEqual(2, entry[1].data.value2);
assertFalse(entry[1].data.hasOwnProperty("value"));
assertEqual("UnitTestsReplication", entry[2].cname);
assertEqual("foo2", entry[2].data._key);
assertEqual(3, entry[2].data.value2);
assertFalse(entry[2].data.hasOwnProperty("value"));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionRemove : function () {
var c1 = db._create(cn);
c1.insert({ _key: "foo", value: 1 });
var tick = getLastLogTick();
db._executeTransaction({
collections: {
write: [ cn ]
},
action: function (params) {
var c1 = require("internal").db._collection(params.cn);
c1.replace("foo", { value2: 2 });
c1.remove("foo");
},
params: {
cn: cn
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300, 2302 ]);
assertEqual(4, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2302, entry[2].type);
assertEqual(2201, entry[3].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(entry[2].tid, entry[3].tid);
assertEqual("UnitTestsReplication", entry[1].cname);
assertEqual("foo", entry[1].data._key);
assertEqual(2, entry[1].data.value2);
assertFalse(entry[1].data.hasOwnProperty("value"));
assertEqual("UnitTestsReplication", entry[2].cname);
assertEqual("foo", entry[2].data._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionMultiRemove : function () {
var c1 = db._create(cn), i;
for (i = 0; i < 100; ++i) {
c1.insert({ _key: "test" + i, value: i });
}
var tick = getLastLogTick();
db._executeTransaction({
collections: {
write: [ cn ]
},
action: function (params) {
var c1 = require("internal").db._collection(params.cn);
for (var i = 0; i < 100; ++i) {
c1.remove("test" + i);
}
},
params: {
cn: cn
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300, 2302 ]);
assertEqual(102, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2201, entry[101].type);
for (i = 1; i < 101; ++i) {
assertEqual(2302, entry[i].type);
assertEqual(entry[0].tid, entry[i].tid);
assertEqual("UnitTestsReplication", entry[i].cname);
assertEqual("test" + (i - 1), entry[i].data._key);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionMultiCollectionUpdate : function () {
var c1 = db._create(cn);
var c2 = db._create(cn2);
c1.insert({ _key: "foo", value: 1 });
c2.insert({ _key: "bar", value: "A" });
var tick = getLastLogTick();
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);
c1.replace("foo", { value: 2 });
c1.insert({ _key: "foo2", value: 3 });
c2.replace("bar", { value: "B" });
c2.insert({ _key: "bar2", value: "C" });
},
params: {
cn: cn,
cn2: cn2
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300 ]);
assertEqual(6, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2300, entry[2].type);
assertEqual(2300, entry[3].type);
assertEqual(2300, entry[4].type);
assertEqual(2201, entry[5].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(entry[2].tid, entry[3].tid);
assertEqual(entry[3].tid, entry[4].tid);
assertEqual(entry[4].tid, entry[5].tid);
assertEqual("UnitTestsReplication", entry[1].cname);
assertEqual("foo", entry[1].data._key);
assertEqual(2, entry[1].data.value);
assertEqual("UnitTestsReplication", entry[2].cname);
assertEqual("foo2", entry[2].data._key);
assertEqual(3, entry[2].data.value);
assertEqual("UnitTestsReplication2", entry[3].cname);
assertEqual("bar", entry[3].data._key);
assertEqual("B", entry[3].data.value);
assertEqual("UnitTestsReplication2", entry[4].cname);
assertEqual("bar2", entry[4].data._key);
assertEqual("C", entry[4].data.value);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionMultiCollectionRemove : function () {
var c1 = db._create(cn);
var c2 = db._create(cn2);
c1.insert({ _key: "foo", value: 1 });
c2.insert({ _key: "bar", value: "A" });
var tick = getLastLogTick();
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);
c1.replace("foo", { value: 2 });
c1.remove("foo");
c2.replace("bar", { value: "B" });
c2.remove("bar");
},
params: {
cn: cn,
cn2: cn2
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300, 2302 ]);
assertEqual(6, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2302, entry[2].type);
assertEqual(2300, entry[3].type);
assertEqual(2302, entry[4].type);
assertEqual(2201, entry[5].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(entry[2].tid, entry[3].tid);
assertEqual(entry[3].tid, entry[4].tid);
assertEqual(entry[4].tid, entry[5].tid);
assertEqual("UnitTestsReplication", entry[1].cname);
assertEqual("foo", entry[1].data._key);
assertEqual(2, entry[1].data.value);
assertEqual("UnitTestsReplication", entry[2].cname);
assertEqual("foo", entry[2].data._key);
assertEqual("UnitTestsReplication2", entry[3].cname);
assertEqual("bar", entry[3].data._key);
assertEqual("B", entry[3].data.value);
assertEqual("UnitTestsReplication2", entry[4].cname);
assertEqual("bar", entry[4].data._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test actions
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionMultiCollectionReplace : function () {
var c1 = db._create(cn);
var c2 = db._create(cn2);
c1.insert({ _key: "foo", value: 1 });
c2.insert({ _key: "bar", value: "A" });
var tick = getLastLogTick();
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);
c1.update("foo", { value2: 2 });
c1.insert({ _key: "foo2", value2: 3 });
c2.update("bar", { value2: "B" });
c2.insert({ _key: "bar2", value2: "C" });
},
params: {
cn: cn,
cn2: cn2
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300 ]);
assertEqual(6, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2300, entry[2].type);
assertEqual(2300, entry[3].type);
assertEqual(2300, entry[4].type);
assertEqual(2201, entry[5].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(entry[2].tid, entry[3].tid);
assertEqual(entry[3].tid, entry[4].tid);
assertEqual(entry[4].tid, entry[5].tid);
assertEqual("UnitTestsReplication", entry[1].cname);
assertEqual("foo", entry[1].data._key);
assertEqual(1, entry[1].data.value);
assertEqual(2, entry[1].data.value2);
assertEqual("UnitTestsReplication", entry[2].cname);
assertEqual("foo2", entry[2].data._key);
assertEqual(3, entry[2].data.value2);
assertFalse(entry[2].data.hasOwnProperty("value"));
assertEqual("UnitTestsReplication2", entry[3].cname);
assertEqual("bar", entry[3].data._key);
assertEqual("A", entry[3].data.value);
assertEqual("B", entry[3].data.value2);
assertEqual("UnitTestsReplication2", entry[4].cname);
assertEqual("bar2", entry[4].data._key);
assertEqual("C", entry[4].data.value2);
assertFalse(entry[4].data.hasOwnProperty("value"));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test collection exclusion
////////////////////////////////////////////////////////////////////////////////
testLoggerTransactionExcluded : function () {
var c = db._create(cn);
var tick = getLastLogTick();
db._executeTransaction({
collections: {
write: [ cn, "_users" ]
},
action: function (params) {
var c = require("internal").db._collection(params.cn);
var users = require("internal").db._collection("_users");
c.save({ "test" : 2, "_key": "12345" });
users.save({ "_key": "unittests1", "foo": false });
users.remove("unittests1");
},
params: {
cn: cn
}
});
var entry = getLogEntries(tick, [ 2200, 2201, 2202, 2300, 2302 ]);
assertEqual(5, entry.length);
assertEqual(2200, entry[0].type);
assertEqual(2300, entry[1].type);
assertEqual(2300, entry[2].type);
assertEqual(2302, entry[3].type);
assertEqual(2201, entry[4].type);
assertEqual(entry[0].tid, entry[1].tid);
assertEqual(entry[1].tid, entry[2].tid);
assertEqual(c._id, entry[1].cid);
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function ReplicationApplierSuite () {
'use strict';
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
replication.applier.stop();
replication.applier.forget();
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
replication.applier.stop();
},
////////////////////////////////////////////////////////////////////////////////
/// @brief start applier w/o configuration
////////////////////////////////////////////////////////////////////////////////
testStartApplierNoConfig : function () {
var state = replication.applier.state();
assertFalse(state.state.running);
try {
// start
replication.applier.start();
fail();
}
catch (err) {
assertEqual(errors.ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief start applier with configuration
////////////////////////////////////////////////////////////////////////////////
testStartApplierInvalidEndpoint1 : function () {
var state = replication.applier.state();
assertFalse(state.state.running);
// configure && start
replication.applier.properties({
endpoint: "tcp://127.0.0.1:0", // should not exist
connectTimeout: 2,
maxConnectRetries: 0,
connectionRetryWaitTime: 1
});
replication.applier.start();
state = replication.applier.state();
assertEqual(errors.ERROR_NO_ERROR.code, state.state.lastError.errorNum);
assertTrue(state.state.running);
var i = 0, max = 30;
while (i++ < max) {
internal.wait(1);
state = replication.applier.state();
if (state.state.running) {
continue;
}
assertFalse(state.state.running);
assertTrue(state.state.totalFailedConnects > 0);
assertTrue(state.state.progress.failedConnects > 0);
assertTrue(errors.ERROR_REPLICATION_NO_RESPONSE.code, state.state.lastError.errorNum);
break;
}
if (i >= max) {
fail();
}
// call start again
replication.applier.start();
state = replication.applier.state();
assertTrue(state.state.running);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief start applier with configuration
////////////////////////////////////////////////////////////////////////////////
testStartApplierInvalidEndpoint2 : function () {
var state = replication.applier.state();
assertFalse(state.state.running);
// configure && start
replication.applier.properties({
endpoint: "tcp://127.0.0.1:0", // should not exist
connectTimeout: 2,
maxConnectRetries: 0,
connectionRetryWaitTime: 1
});
replication.applier.start();
state = replication.applier.state();
assertTrue(state.state.running);
var i = 0, max = 30;
while (i++ < max) {
internal.wait(1);
state = replication.applier.state();
if (state.state.running) {
continue;
}
assertFalse(state.state.running);
assertTrue(state.state.totalFailedConnects > 0);
assertTrue(state.state.progress.failedConnects > 0);
assertTrue(state.state.lastError.errorNum === errors.ERROR_REPLICATION_INVALID_RESPONSE.code ||
state.state.lastError.errorNum === errors.ERROR_REPLICATION_MASTER_ERROR.code ||
state.state.lastError.errorNum === errors.ERROR_REPLICATION_NO_RESPONSE.code);
break;
}
if (i >= max) {
fail();
}
// call start again
replication.applier.start();
state = replication.applier.state();
assertTrue(state.state.running);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief stop applier
////////////////////////////////////////////////////////////////////////////////
testStopApplier : function () {
var state = replication.applier.state();
assertFalse(state.state.running);
// configure && start
replication.applier.properties({
endpoint: "tcp://9.9.9.9:9999", // should not exist
connectTimeout: 2,
maxConnectRetries: 0,
connectionRetryWaitTime: 1
});
replication.applier.start();
state = replication.applier.state();
assertEqual(errors.ERROR_NO_ERROR.code, state.state.lastError.errorNum);
assertTrue(state.state.running);
// stop
replication.applier.stop();
state = replication.applier.state();
assertFalse(state.state.running);
// stop again
replication.applier.stop();
state = replication.applier.state();
assertFalse(state.state.running);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief properties
////////////////////////////////////////////////////////////////////////////////
testApplierProperties : function () {
var properties = replication.applier.properties();
assertEqual(600, properties.requestTimeout);
assertEqual(10, properties.connectTimeout);
assertEqual(100, properties.maxConnectRetries);
assertEqual(0, properties.chunkSize);
assertFalse(properties.autoStart);
assertTrue(properties.adaptivePolling);
assertUndefined(properties.endpoint);
assertTrue(properties.includeSystem);
assertEqual("", properties.restrictType);
assertEqual([ ], properties.restrictCollections);
assertEqual(15, properties.connectionRetryWaitTime);
assertEqual(1, properties.idleMinWaitTime);
assertEqual(2.5, properties.idleMaxWaitTime);
assertFalse(properties.autoResync);
assertEqual(2, properties.autoResyncRetries);
try {
replication.applier.properties({ });
fail();
}
catch (err) {
assertEqual(errors.ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION.code, err.errorNum);
}
replication.applier.properties({
endpoint: "tcp://9.9.9.9:9999"
});
properties = replication.applier.properties();
assertEqual(properties.endpoint, "tcp://9.9.9.9:9999");
assertEqual(600, properties.requestTimeout);
assertEqual(10, properties.connectTimeout);
assertEqual(100, properties.maxConnectRetries);
assertEqual(0, properties.chunkSize);
assertFalse(properties.autoStart);
assertTrue(properties.adaptivePolling);
assertEqual(15, properties.connectionRetryWaitTime);
assertEqual(1, properties.idleMinWaitTime);
assertEqual(2.5, properties.idleMaxWaitTime);
assertFalse(properties.autoResync);
assertEqual(2, properties.autoResyncRetries);
replication.applier.properties({
endpoint: "tcp://9.9.9.9:9998",
autoStart: true,
adaptivePolling: false,
requestTimeout: 5,
connectTimeout: 9,
maxConnectRetries: 4,
chunkSize: 65536,
includeSystem: false,
restrictType: "include",
restrictCollections: [ "_users" ],
connectionRetryWaitTime: 60.2,
idleMinWaitTime: 0.1,
idleMaxWaitTime: 42.44,
autoResync: true,
autoResyncRetries: 13
});
properties = replication.applier.properties();
assertEqual(properties.endpoint, "tcp://9.9.9.9:9998");
assertEqual(5, properties.requestTimeout);
assertEqual(9, properties.connectTimeout);
assertEqual(4, properties.maxConnectRetries);
assertEqual(65536, properties.chunkSize);
assertTrue(properties.autoStart);
assertFalse(properties.adaptivePolling);
assertFalse(properties.includeSystem);
assertEqual("include", properties.restrictType);
assertEqual([ "_users" ], properties.restrictCollections);
assertEqual(60.2, properties.connectionRetryWaitTime);
assertEqual(0.1, properties.idleMinWaitTime);
assertEqual(42.44, properties.idleMaxWaitTime);
assertTrue(properties.autoResync);
assertEqual(13, properties.autoResyncRetries);
replication.applier.properties({
endpoint: "tcp://9.9.9.9:9998",
autoStart: false,
maxConnectRetries: 10,
chunkSize: 128 * 1024,
includeSystem: true,
restrictType: "exclude",
restrictCollections: [ "foo", "bar", "baz" ],
idleMinWaitTime: 7,
autoResync: false,
autoResyncRetries: 22
});
properties = replication.applier.properties();
assertEqual(properties.endpoint, "tcp://9.9.9.9:9998");
assertEqual(5, properties.requestTimeout);
assertEqual(9, properties.connectTimeout);
assertEqual(10, properties.maxConnectRetries);
assertEqual(128 * 1024, properties.chunkSize);
assertFalse(properties.autoStart);
assertFalse(properties.adaptivePolling);
assertTrue(properties.includeSystem);
assertEqual("exclude", properties.restrictType);
assertEqual([ "bar", "baz", "foo" ], properties.restrictCollections.sort());
assertEqual(60.2, properties.connectionRetryWaitTime);
assertEqual(7, properties.idleMinWaitTime);
assertEqual(42.44, properties.idleMaxWaitTime);
assertFalse(properties.autoResync);
assertEqual(22, properties.autoResyncRetries);
replication.applier.properties({
restrictType: "",
restrictCollections: [ ],
idleMaxWaitTime: 33,
autoResyncRetries: 0
});
properties = replication.applier.properties();
assertEqual("", properties.restrictType);
assertEqual([ ], properties.restrictCollections);
assertEqual(60.2, properties.connectionRetryWaitTime);
assertEqual(7, properties.idleMinWaitTime);
assertEqual(33, properties.idleMaxWaitTime);
assertEqual(0, properties.autoResyncRetries);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief start property change while running
////////////////////////////////////////////////////////////////////////////////
testApplierPropertiesChange : function () {
replication.applier.properties({
endpoint: "tcp://9.9.9.9:9999",
connectTimeout: 2,
maxConnectRetries: 0,
connectionRetryWaitTime: 1
});
replication.applier.start();
var state = replication.applier.state();
assertTrue(state.state.running);
try {
replication.applier.properties({ endpoint: "tcp://9.9.9.9:9998" });
fail();
}
catch (err) {
assertEqual(errors.ERROR_REPLICATION_RUNNING.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief applier state
////////////////////////////////////////////////////////////////////////////////
testStateApplier : function () {
var state = replication.applier.state();
assertFalse(state.state.running);
assertMatch(/^\d+-\d+-\d+T\d+:\d+:\d+Z$/, state.state.time);
assertEqual(state.server.version, db._version());
assertNotEqual("", state.server.serverId);
assertMatch(/^\d+$/, state.server.serverId);
assertUndefined(state.endpoint);
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function ReplicationSyncSuite () {
'use strict';
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
replication.applier.stop();
replication.applier.forget();
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
},
////////////////////////////////////////////////////////////////////////////////
/// @brief server id
////////////////////////////////////////////////////////////////////////////////
testServerId : function () {
var result = replication.serverId();
assertTrue(typeof result === 'string');
assertMatch(/^\d+$/, result);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief no endpoint
////////////////////////////////////////////////////////////////////////////////
testSyncNoEndpoint : function () {
try {
replication.sync();
fail();
}
catch (err) {
assertEqual(errors.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief invalid endpoint
////////////////////////////////////////////////////////////////////////////////
testSyncNoEndpoint2 : function () {
try {
replication.sync({
endpoint: "tcp://9.9.9.9:9999",
connectTimeout: 2,
maxConnectRetries: 0,
connectionRetryWaitTime: 1,
verbose: true
});
fail();
}
catch (err) {
assertEqual(errors.ERROR_REPLICATION_NO_RESPONSE.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief invalid response
////////////////////////////////////////////////////////////////////////////////
testSyncInvalidResponse : function () {
try {
replication.sync({
endpoint: "tcp://www.arangodb.com:80",
connectTimeout: 2,
maxConnectRetries: 0,
connectionRetryWaitTime: 1
});
fail();
}
catch (err) {
assertTrue(err.errorNum === errors.ERROR_REPLICATION_INVALID_RESPONSE.code ||
err.errorNum === errors.ERROR_REPLICATION_MASTER_ERROR.code ||
err.errorNum === errors.ERROR_REPLICATION_NO_RESPONSE.code);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief invalid restrictType
////////////////////////////////////////////////////////////////////////////////
testSyncRestrict1 : function () {
try {
replication.sync({
endpoint: "tcp://9.9.9.9:9999",
restrictType: "foo"
});
fail();
}
catch (err) {
assertEqual(errors.ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief invalid restrictCollections
////////////////////////////////////////////////////////////////////////////////
testSyncRestrict2 : function () {
try {
replication.sync({
endpoint: "tcp://9.9.9.9:9999",
restrictType: "exclude"
});
fail();
}
catch (err) {
assertEqual(errors.ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief invalid restrictCollections
////////////////////////////////////////////////////////////////////////////////
testSyncRestrict3 : function () {
try {
replication.sync({
endpoint: "tcp://9.9.9.9:9999",
restrictType: "include"
});
fail();
}
catch (err) {
assertEqual(errors.ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief invalid restrictCollections
////////////////////////////////////////////////////////////////////////////////
testSyncRestrict4 : function () {
try {
replication.sync({
endpoint: "tcp://9.9.9.9:9999",
restrictCollections: [ "foo" ]
});
fail();
}
catch (err) {
assertEqual(errors.ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief invalid restrictCollections
////////////////////////////////////////////////////////////////////////////////
testSyncRestrict5 : function () {
try {
replication.sync({
endpoint: "tcp://9.9.9.9:9999",
restrictType: "include",
restrictCollections: "foo"
});
fail();
}
catch (err) {
assertEqual(errors.ERROR_REPLICATION_INVALID_APPLIER_CONFIGURATION.code, err.errorNum);
}
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suites
////////////////////////////////////////////////////////////////////////////////
jsunity.run(ReplicationLoggerSuite);
jsunity.run(ReplicationApplierSuite);
jsunity.run(ReplicationSyncSuite);
return jsunity.done();