diff --git a/arangod/Cache/Cache.cpp b/arangod/Cache/Cache.cpp index efcb6d65ae..989f0f90f5 100644 --- a/arangod/Cache/Cache.cpp +++ b/arangod/Cache/Cache.cpp @@ -163,6 +163,15 @@ bool Cache::isResizing() { return resizing; } +bool Cache::isShutdown() { + bool shutdown = false; + _state.lock(); + shutdown = !isOperational(); + _state.unlock(); + + return shutdown; +} + void Cache::destroy(std::shared_ptr cache) { if (cache.get() != nullptr) { cache->shutdown(); diff --git a/arangod/Cache/Cache.h b/arangod/Cache/Cache.h index ff67e2c300..3275368e18 100644 --- a/arangod/Cache/Cache.h +++ b/arangod/Cache/Cache.h @@ -112,6 +112,11 @@ class Cache : public std::enable_shared_from_this { ////////////////////////////////////////////////////////////////////////////// bool isResizing(); + ////////////////////////////////////////////////////////////////////////////// + /// @brief Check whether the cache has begin the process of shutting down. + ////////////////////////////////////////////////////////////////////////////// + bool isShutdown(); + protected: static constexpr int64_t triesFast = 50; static constexpr int64_t triesSlow = 10000; diff --git a/arangod/Cache/TransactionalCache.cpp b/arangod/Cache/TransactionalCache.cpp index 1cd0123d8c..545b66aa8c 100644 --- a/arangod/Cache/TransactionalCache.cpp +++ b/arangod/Cache/TransactionalCache.cpp @@ -32,6 +32,7 @@ #include "Cache/State.h" #include "Cache/Table.h" #include "Cache/TransactionalBucket.h" +#include "Logger/Logger.h" #include #include diff --git a/arangod/RocksDBEngine/RocksDBIndex.cpp b/arangod/RocksDBEngine/RocksDBIndex.cpp index 8d0a29d266..1892062d7a 100644 --- a/arangod/RocksDBEngine/RocksDBIndex.cpp +++ b/arangod/RocksDBEngine/RocksDBIndex.cpp @@ -73,6 +73,14 @@ void RocksDBIndex::createCache() { } } +void RocksDBIndex::disableCache() { + TRI_ASSERT(_cacheManager != nullptr); + TRI_ASSERT(_useCache); + TRI_ASSERT(_cache.get() != nullptr); + _useCache = false; + _cacheManager->destroyCache(_cache); + _cache.reset(); +} int RocksDBIndex::drop() { // Try to drop the cache as well. if (_useCache && _cache != nullptr) { diff --git a/arangod/RocksDBEngine/RocksDBIndex.h b/arangod/RocksDBEngine/RocksDBIndex.h index c6be0cdf4d..99a896d961 100644 --- a/arangod/RocksDBEngine/RocksDBIndex.h +++ b/arangod/RocksDBEngine/RocksDBIndex.h @@ -48,7 +48,6 @@ class RocksDBIndex : public Index { arangodb::velocypack::Slice const&); public: - ~RocksDBIndex(); uint64_t objectId() const { return _objectId; } @@ -56,7 +55,7 @@ class RocksDBIndex : public Index { bool isPersistent() const override final { return true; } int drop() override; - + int unload() override { // nothing to do here yet // TODO: free the cache the index uses @@ -64,13 +63,14 @@ class RocksDBIndex : public Index { } /// @brief provides a size hint for the index - int sizeHint(transaction::Methods* /*trx*/, size_t /*size*/) override final{ + int sizeHint(transaction::Methods* /*trx*/, size_t /*size*/) override final { // nothing to do here return TRI_ERROR_NO_ERROR; } protected: void createCache(); + void disableCache(); protected: uint64_t _objectId; diff --git a/arangod/RocksDBEngine/RocksDBPrimaryIndex.cpp b/arangod/RocksDBEngine/RocksDBPrimaryIndex.cpp index ff5df2c3da..fabcb6c037 100644 --- a/arangod/RocksDBEngine/RocksDBPrimaryIndex.cpp +++ b/arangod/RocksDBEngine/RocksDBPrimaryIndex.cpp @@ -178,26 +178,42 @@ bool RocksDBAllIndexIterator::outOfRange() const { uint64_t RocksDBAnyIndexIterator::OFFSET = 0; -RocksDBAnyIndexIterator::RocksDBAnyIndexIterator(LogicalCollection* collection, transaction::Methods* trx, - ManagedDocumentResult* mmdr, RocksDBPrimaryIndex const* index) -: IndexIterator(collection, trx, mmdr, index), -_cmp(index->_cmp), -_bounds(RocksDBKeyBounds::PrimaryIndex(index->objectId())) { +uint64_t RocksDBAnyIndexIterator::newOffset(LogicalCollection* collection, + transaction::Methods* trx) { + auto count = collection->numberDocuments(trx); + /*auto adjustment = RandomGenerator::interval(count); + OFFSET = (OFFSET + adjustment) % count; + return OFFSET;*/ + if (count == 0) { + return 0; + } + + return RandomGenerator::interval(count); +} + +RocksDBAnyIndexIterator::RocksDBAnyIndexIterator( + LogicalCollection* collection, transaction::Methods* trx, + ManagedDocumentResult* mmdr, RocksDBPrimaryIndex const* index) + : IndexIterator(collection, trx, mmdr, index), + _cmp(index->_cmp), + _bounds(RocksDBKeyBounds::PrimaryIndex(index->objectId())) { // aquire rocksdb transaction RocksDBTransactionState* state = rocksutils::toRocksTransactionState(trx); rocksdb::Transaction* rtrx = state->rocksTransaction(); auto options = state->readOptions(); - + _iterator.reset(rtrx->GetIterator(options)); _iterator->Seek(_bounds.start()); - + // not thread safe by design - uint64_t off = OFFSET++; - while (_iterator->Valid() && --off > 0) { - _iterator->Next(); + uint64_t off = newOffset(collection, trx); + if (off > 0) { + while (_iterator->Valid() && --off > 0) { + _iterator->Next(); + } } if (!_iterator->Valid()) { - OFFSET = 0; + // OFFSET = 0; _iterator->Seek(_bounds.start()); } } @@ -209,24 +225,22 @@ bool RocksDBAnyIndexIterator::next(TokenCallback const& cb, size_t limit) { TRI_ASSERT(limit > 0); // Someone called with limit == 0. Api broken return false; } - + while (limit > 0) { RocksDBToken token(RocksDBValue::revisionId(_iterator->value())); cb(token); - + --limit; _iterator->Next(); if (!_iterator->Valid() || outOfRange()) { return false; } } - + return true; } -void RocksDBAnyIndexIterator::reset() { - _iterator->Seek(_bounds.start()); -} +void RocksDBAnyIndexIterator::reset() { _iterator->Seek(_bounds.start()); } bool RocksDBAnyIndexIterator::outOfRange() const { return _cmp->Compare(_iterator->key(), _bounds.end()) > 0; @@ -350,9 +364,18 @@ int RocksDBPrimaryIndex::insert(transaction::Methods* trx, if (_useCache) { // blacklist from cache bool blacklisted = false; + uint64_t attempts = 0; while (!blacklisted) { blacklisted = _cache->blacklist( key.string().data(), static_cast(key.string().size())); + attempts++; + if (attempts > 10) { + if (_cache->isShutdown()) { + disableCache(); + break; + } + attempts = 0; + } } } @@ -376,9 +399,18 @@ int RocksDBPrimaryIndex::remove(transaction::Methods* trx, if (_useCache) { // blacklist from cache bool blacklisted = false; + uint64_t attempts = 0; while (!blacklisted) { blacklisted = _cache->blacklist( key.string().data(), static_cast(key.string().size())); + attempts++; + if (attempts > 10) { + if (_cache->isShutdown()) { + disableCache(); + break; + } + attempts = 0; + } } } @@ -468,15 +500,16 @@ IndexIterator* RocksDBPrimaryIndex::allIterator(transaction::Methods* trx, /// @brief request an iterator over all elements in the index in /// a sequential order. -IndexIterator* RocksDBPrimaryIndex::anyIterator(transaction::Methods* trx, - ManagedDocumentResult* mmdr) const { +IndexIterator* RocksDBPrimaryIndex::anyIterator( + transaction::Methods* trx, ManagedDocumentResult* mmdr) const { return new RocksDBAnyIndexIterator(_collection, trx, mmdr, this); } -void RocksDBPrimaryIndex::invokeOnAllElements(transaction::Methods* trx, - std::function callback) { +void RocksDBPrimaryIndex::invokeOnAllElements( + transaction::Methods* trx, + std::function callback) { ManagedDocumentResult mmdr; - std::unique_ptr cursor (allIterator(trx, &mmdr, false)); + std::unique_ptr cursor(allIterator(trx, &mmdr, false)); bool cnt = true; auto cb = [&](DocumentIdentifierToken token) { if (cnt) { @@ -484,11 +517,9 @@ void RocksDBPrimaryIndex::invokeOnAllElements(transaction::Methods* trx, } }; while (cursor->next(cb, 1000) && cnt) { - } } - /// @brief create the iterator, for a single attribute, IN operator IndexIterator* RocksDBPrimaryIndex::createInIterator( transaction::Methods* trx, ManagedDocumentResult* mmdr, diff --git a/arangod/RocksDBEngine/RocksDBPrimaryIndex.h b/arangod/RocksDBEngine/RocksDBPrimaryIndex.h index 4bb6a3ea49..c2e47083f9 100644 --- a/arangod/RocksDBEngine/RocksDBPrimaryIndex.h +++ b/arangod/RocksDBEngine/RocksDBPrimaryIndex.h @@ -27,6 +27,7 @@ #include "Basics/Common.h" #include "Indexes/Index.h" #include "Indexes/IndexIterator.h" +#include "Random/RandomGenerator.h" #include "RocksDBEngine/RocksDBIndex.h" #include "RocksDBEngine/RocksDBKeyBounds.h" #include "RocksDBEngine/RocksDBToken.h" @@ -95,23 +96,25 @@ class RocksDBAllIndexIterator final : public IndexIterator { }; class RocksDBAnyIndexIterator final : public IndexIterator { - public: - RocksDBAnyIndexIterator(LogicalCollection* collection, - transaction::Methods* trx, - ManagedDocumentResult* mmdr, - RocksDBPrimaryIndex const* index); - - ~RocksDBAnyIndexIterator() {} - - char const* typeName() const override { return "any-index-iterator"; } - - bool next(TokenCallback const& cb, size_t limit) override; - - void reset() override; - -private: + public: + RocksDBAnyIndexIterator(LogicalCollection* collection, + transaction::Methods* trx, + ManagedDocumentResult* mmdr, + RocksDBPrimaryIndex const* index); + + ~RocksDBAnyIndexIterator() {} + + char const* typeName() const override { return "any-index-iterator"; } + + bool next(TokenCallback const& cb, size_t limit) override; + + void reset() override; + + private: bool outOfRange() const; - + static uint64_t newOffset(LogicalCollection* collection, + transaction::Methods* trx); + RocksDBComparator const* _cmp; std::unique_ptr _iterator; RocksDBKeyBounds _bounds; @@ -189,10 +192,11 @@ class RocksDBPrimaryIndex final : public RocksDBIndex { IndexIterator* anyIterator(transaction::Methods* trx, ManagedDocumentResult* mmdr) const; - - void invokeOnAllElements(transaction::Methods* trx, - std::function callback); - + + void invokeOnAllElements( + transaction::Methods* trx, + std::function callback); + private: /// @brief create the iterator, for a single attribute, IN operator IndexIterator* createInIterator(transaction::Methods*, ManagedDocumentResult*, diff --git a/js/common/tests/shell/shell-figures-noncluster.js b/js/common/tests/shell/shell-figures-mmfiles-noncluster.js similarity index 100% rename from js/common/tests/shell/shell-figures-noncluster.js rename to js/common/tests/shell/shell-figures-mmfiles-noncluster.js diff --git a/js/server/tests/shell/shell-collection-files-noncluster.js b/js/server/tests/shell/shell-collection-mmfiles-files-noncluster.js similarity index 100% rename from js/server/tests/shell/shell-collection-files-noncluster.js rename to js/server/tests/shell/shell-collection-mmfiles-files-noncluster.js diff --git a/js/server/tests/shell/shell-compaction-noncluster-timecritical.js b/js/server/tests/shell/shell-compaction-mmfiles-noncluster-timecritical.js similarity index 100% rename from js/server/tests/shell/shell-compaction-noncluster-timecritical.js rename to js/server/tests/shell/shell-compaction-mmfiles-noncluster-timecritical.js diff --git a/js/server/tests/shell/shell-compaction-seq-noncluster-timecritical.js b/js/server/tests/shell/shell-compaction-seq-mmfiles-noncluster-timecritical.js similarity index 100% rename from js/server/tests/shell/shell-compaction-seq-noncluster-timecritical.js rename to js/server/tests/shell/shell-compaction-seq-mmfiles-noncluster-timecritical.js diff --git a/js/server/tests/shell/shell-database-noncluster.js b/js/server/tests/shell/shell-database-mmfiles-noncluster.js similarity index 100% rename from js/server/tests/shell/shell-database-noncluster.js rename to js/server/tests/shell/shell-database-mmfiles-noncluster.js diff --git a/js/server/tests/shell/shell-database-rocksdb-noncluster.js b/js/server/tests/shell/shell-database-rocksdb-noncluster.js new file mode 100644 index 0000000000..678ba20c05 --- /dev/null +++ b/js/server/tests/shell/shell-database-rocksdb-noncluster.js @@ -0,0 +1,248 @@ +/*jshint globalstrict:false, strict:false, unused : false */ +/*global fail, assertTrue, assertFalse, assertEqual, assertMatch */ + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test the server-side database interface +/// +/// @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 2012, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +var jsunity = require("jsunity"); +var internal = require("internal"); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test suite: dropping databases while holding references +//////////////////////////////////////////////////////////////////////////////// + +var logLevel; +function DatabaseSuite () { + 'use strict'; + return { + + setUp : function () { + logLevel = require("internal").logLevel(); + internal.db._useDatabase("_system"); + }, + + tearDown : function () { + require("internal").logLevel(logLevel); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test whether the expected keys are present in db._version(true) +//////////////////////////////////////////////////////////////////////////////// + + testVersionDetails : function () { + let result = internal.db._version(true); + + let keys = [ + "architecture", + "asan", + "asm-crc32", + "assertions", + "boost-version", + "build-date", + "compiler", + "cplusplus", + "debug", + "endianness", + "failure-tests", + "full-version-string", + "icu-version", + "jemalloc", + "maintainer-mode", + "openssl-version", + "platform", + "reactor-type", + "rocksdb-version", + "server-version", + "sse42", + "unaligned-access", + "v8-version", + "vpack-version", + "zlib-version" + ]; + + keys.forEach(function(k) { + assertTrue(result.hasOwnProperty(k)); + }); + }, + + testVersionBooleans : function () { + let result = internal.db._version(true); + + let keys = [ + "asan", + "asm-crc32", + "assertions", + "debug", + "failure-tests", + "jemalloc", + "maintainer-mode", + "sse42", + "unaligned-access" + ]; + + keys.forEach(function(k) { + assertTrue(result[k] === "true" || result[k] === "false"); + }); + }, + + testVersionNumbers : function () { + let result = internal.db._version(true); + + let keys = [ + "boost-version", + "icu-version", + "rocksdb-version", + "server-version", + "v8-version", + "vpack-version", + "zlib-version" + ]; + + keys.forEach(function(k) { + assertMatch(/^\d+(\.\d+)*([\.\-][a-z\-]+\d*)?$/, result[k]); + }); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test references helt on dropped database collections +//////////////////////////////////////////////////////////////////////////////// + + testDropDatabaseCollectionReferences : function () { + assertEqual("_system", internal.db._name()); + + try { + internal.db._dropDatabase("UnitTestsDatabase0"); + } + catch (err) { + } + + assertTrue(internal.db._createDatabase("UnitTestsDatabase0")); + + internal.db._useDatabase("UnitTestsDatabase0"); + assertEqual("UnitTestsDatabase0", internal.db._name()); + + // insert 1000 docs and hold a reference on the data + var c = internal.db._create("test"); + for (var i = 0; i < 1000; ++i) { + c.save({ "_key": "test" + i, "value" : i }); + } + assertEqual(1000, c.count()); + + internal.db._useDatabase("_system"); + assertEqual(1000, c.count()); + + // drop the database + internal.db._dropDatabase("UnitTestsDatabase0"); + // should be dropped + internal.db._databases().forEach(function (d) { + if (d === "UnitTestsDatabase0") { + fail(); + } + }); + + // collection should still be there + assertEqual(1000, c.count()); + assertEqual("test", c.name()); + + internal.wait(5); + // still... + assertEqual(1000, c.count()); + + c = null; + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test references helt on documents of dropped databases +//////////////////////////////////////////////////////////////////////////////// + + testDropDatabaseDocumentReferences : function () { + assertEqual("_system", internal.db._name()); + + try { + internal.db._dropDatabase("UnitTestsDatabase0"); + } + catch (err) { + } + + assertTrue(internal.db._createDatabase("UnitTestsDatabase0")); + + internal.db._useDatabase("UnitTestsDatabase0"); + assertEqual("UnitTestsDatabase0", internal.db._name()); + + // insert docs and hold a reference on the data + var c = internal.db._create("test"); + for (var i = 0; i < 10; ++i) { + c.save({ "_key": "test" + i, "value" : i }); + } + + var d0 = c.document("test0"); + var d4 = c.document("test4"); + var d9 = c.document("test9"); + + c = null; + + internal.db._useDatabase("_system"); + + // drop the database + internal.db._dropDatabase("UnitTestsDatabase0"); + // should be dropped + internal.db._databases().forEach(function (d) { + if (d === "UnitTestsDatabase0") { + fail(); + } + }); + + assertEqual(0, d0.value); + assertEqual(4, d4.value); + assertEqual(9, d9.value); + + internal.wait(5); + + assertEqual(0, d0.value); + assertEqual(4, d4.value); + assertEqual(9, d9.value); + + d0 = null; + d4 = null; + + internal.wait(3); + assertEqual(9, d9.value); + + d9 = null; + }, + + }; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief executes the test suite +//////////////////////////////////////////////////////////////////////////////// + +jsunity.run(DatabaseSuite); + +return jsunity.done(); diff --git a/js/server/tests/shell/shell-datafile-timecritical-noncluster.js b/js/server/tests/shell/shell-datafile-mmfiles-timecritical-noncluster.js similarity index 100% rename from js/server/tests/shell/shell-datafile-timecritical-noncluster.js rename to js/server/tests/shell/shell-datafile-mmfiles-timecritical-noncluster.js diff --git a/js/server/tests/shell/shell-shaped-noncluster.js b/js/server/tests/shell/shell-shaped-mmfiles-noncluster.js similarity index 100% rename from js/server/tests/shell/shell-shaped-noncluster.js rename to js/server/tests/shell/shell-shaped-mmfiles-noncluster.js diff --git a/js/server/tests/shell/shell-shaped-rocksdb-noncluster.js b/js/server/tests/shell/shell-shaped-rocksdb-noncluster.js new file mode 100644 index 0000000000..463504041e --- /dev/null +++ b/js/server/tests/shell/shell-shaped-rocksdb-noncluster.js @@ -0,0 +1,1086 @@ +/*jshint globalstrict:false, strict:false */ +/*global fail, assertFalse, assertTrue, assertEqual, assertUndefined */ + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test the shaped json behavior +/// +/// @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 2012, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +var jsunity = require("jsunity"); + +var arangodb = require("@arangodb"); +var db = arangodb.db; +var internal = require("internal"); + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test suite +//////////////////////////////////////////////////////////////////////////////// + +function DocumentShapedJsonSuite () { + 'use strict'; + var cn = "UnitTestsCollectionShaped"; + var c; + + return { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief set up +//////////////////////////////////////////////////////////////////////////////// + + setUp : function () { + db._drop(cn); + c = db._create(cn); + + for (var i = 0; i < 100; ++i) { + c.save({ _key: "test" + i, + value: i, + text: "Test" + i, + values: [ i ], + one: { two: { three: [ 1 ] } } }); + } + + // wait until the documents are actually shaped json + internal.wal.flush(true, true); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tear down +//////////////////////////////////////////////////////////////////////////////// + + tearDown : function () { + db._drop(cn); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief save a Buffer object +//////////////////////////////////////////////////////////////////////////////// + + testBuffer : function () { + var b = new Buffer('abcdefg', 'binary'); + c.save({ _key: "buffer", value: b }); + var doc = c.document("buffer"); + assertTrue(doc.hasOwnProperty("value")); + assertEqual(b.toJSON(), doc.value); + assertEqual([ 97, 98, 99, 100, 101, 102, 103 ], doc.value); + }, + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief save a date object +//////////////////////////////////////////////////////////////////////////////// + + testDate : function () { + var dt = new Date(); + c.save({ _key: "date", value: dt }); + var doc = c.document("date"); + assertTrue(doc.hasOwnProperty("value")); + assertEqual(dt.toJSON(), doc.value); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief save a regexp object +//////////////////////////////////////////////////////////////////////////////// + + testRegexp : function () { + try { + c.save({ _key: "date", regexp : /foobar/ }); + fail(); + } + catch (err) { + assertEqual(internal.errors.ERROR_BAD_PARAMETER.code, err.errorNum); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief save a function object +//////////////////////////////////////////////////////////////////////////////// + + testFunction : function () { + try { + c.save({ _key: "date", func : function () { } }); + fail(); + } + catch (err) { + assertEqual(internal.errors.ERROR_BAD_PARAMETER.code, err.errorNum); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check getting keys +//////////////////////////////////////////////////////////////////////////////// + + testGet : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + assertTrue(doc.hasOwnProperty("one")); + + assertEqual(cn + "/test" + i, doc._id); + assertEqual("test" + i, doc._key); + assertEqual(i, doc.value); + assertEqual("Test" + i, doc.text); + assertEqual([ i ], doc.values); + assertEqual({ two: { three: [ 1 ] } }, doc.one); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check getting keys +//////////////////////////////////////////////////////////////////////////////// + + testGetKeys : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + var keys = Object.keys(doc).sort(); + assertEqual([ "_id", "_key", "_rev", "one", "text", "value", "values" ], keys); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check updating of keys in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testUpdatePseudo : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + assertEqual(cn + "/test" + i, doc._id); + assertEqual("test" + i, doc._key); + assertEqual(i, doc.value); + assertEqual("Test" + i, doc.text); + assertEqual([ i ], doc.values); + + doc._id = "foobarbaz"; + doc._key = "meow"; + doc._rev = null; + + assertEqual("foobarbaz", doc._id); + assertEqual("meow", doc._key); + assertEqual(null, doc._rev); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check updating of keys in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testUpdateShaped1 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + doc.value = "Tester" + i; + doc.text = 42 + i; + doc.values.push(i); + + assertEqual(cn + "/test" + i, doc._id); + assertEqual("test" + i, doc._key); + assertEqual("Tester" + i, doc.value); + assertEqual(42 + i, doc.text); + assertEqual([ i, i ], doc.values); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check updating of keys in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testUpdateShaped2 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + assertEqual(i, doc.value); + + doc.value = 99; + assertEqual(99, doc.value); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check updating of keys in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testUpdateShaped3 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + assertEqual([ i ], doc.values); + + doc.someValue = 1; // need to do this to trigger copying + doc.values.push(42); + assertEqual([ i, 42 ], doc.values); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check updating of keys in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testUpdateShapedNested1 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + assertEqual({ two: { three: [ 1 ] } }, doc.one); + + doc.one = "removing the nested structure"; + assertTrue(doc.hasOwnProperty("one")); + assertEqual("removing the nested structure", doc.one); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check updating of keys in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testUpdateShapedNested2 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + assertEqual({ two: { three: [ 1 ] } }, doc.one); + + doc.someValue = 1; // need to do this to trigger copying + doc.one.two.three = "removing the nested structure"; + assertTrue(doc.hasOwnProperty("one")); + assertTrue(doc.one.hasOwnProperty("two")); + assertTrue(doc.one.two.hasOwnProperty("three")); + assertEqual("removing the nested structure", doc.one.two.three); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check updating of keys in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testUpdateShapedNested3 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + assertEqual({ two: { three: [ 1 ] } }, doc.one); + doc.someValue = 1; // need to do this to trigger copying + + doc.one.two.four = 42; + assertTrue(doc.hasOwnProperty("one")); + assertTrue(doc.one.hasOwnProperty("two")); + assertTrue(doc.one.two.hasOwnProperty("three")); + assertTrue(doc.one.two.hasOwnProperty("four")); + assertEqual([ 1 ], doc.one.two.three); + assertEqual(42, doc.one.two.four); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check adding attributes in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testAddAttributes1 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + doc.thisIsAnAttribute = 99; + + assertTrue(doc.hasOwnProperty("thisIsAnAttribute")); + assertEqual(99, doc.thisIsAnAttribute); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check adding attributes in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testAddAttributes2 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + doc["some attribute set now"] = "aha"; + + assertTrue(doc.hasOwnProperty("some attribute set now")); + assertEqual("aha", doc["some attribute set now"]); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check adding attributes in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testAddAttributesIndexed : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + doc[1] = "aha"; + + assertTrue(doc.hasOwnProperty(1)); + assertTrue(doc.hasOwnProperty("1")); + assertEqual("aha", doc[1]); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check adding attributes in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testAddAttributesNested1 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + doc.someValue = 1; // need to do this to trigger copying + doc.one.test = { foo: "bar" }; + assertTrue(doc.hasOwnProperty("one")); + assertTrue(doc.one.hasOwnProperty("two")); + assertTrue(doc.one.two.hasOwnProperty("three")); + assertTrue(doc.one.hasOwnProperty("test")); + assertEqual({ foo: "bar" }, doc.one.test); + assertEqual({ three: [ 1 ] }, doc.one.two); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check adding attributes in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testAddAttributesNested2 : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + doc.something = { foo: "bar" }; + assertTrue(doc.hasOwnProperty("something")); + assertTrue(doc.something.hasOwnProperty("foo")); + assertEqual("bar", doc.something.foo); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of keys from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionPseudoFirst : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + + // delete pseudo-attributes first + delete doc._key; + assertFalse(doc.hasOwnProperty("_key")); + + delete doc._rev; + assertFalse(doc.hasOwnProperty("_rev")); + + delete doc._id; + assertFalse(doc.hasOwnProperty("_id")); + + delete doc.value; + assertFalse(doc.hasOwnProperty("value")); + + delete doc.text; + assertFalse(doc.hasOwnProperty("text")); + + delete doc.values; + assertFalse(doc.hasOwnProperty("values")); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of special attribute _id +//////////////////////////////////////////////////////////////////////////////// + + testDeletionShapedKeyId : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + + // delete special attribute _id + delete doc._id; + assertFalse(doc.hasOwnProperty("_id")); + assertUndefined(doc._id); + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of special attributes from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionShapedKeyRev : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + + // delete special attribute _key + delete doc._key; + assertFalse(doc.hasOwnProperty("_key")); + assertUndefined(doc._key); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + + // delete special attribute _rev + delete doc._rev; + assertFalse(doc.hasOwnProperty("_rev")); + assertFalse(doc.hasOwnProperty("_key")); + assertUndefined(doc._rev); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of keys from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionShapedFirst : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + + // delete shaped attributes first + delete doc.value; + assertFalse(doc.hasOwnProperty("value")); + assertUndefined(doc.value); + + delete doc.text; + assertFalse(doc.hasOwnProperty("text")); + assertUndefined(doc.text); + + delete doc.values; + assertFalse(doc.hasOwnProperty("values")); + assertUndefined(doc.values); + + delete doc._key; + assertFalse(doc.hasOwnProperty("_key")); + assertUndefined(doc._key); + + delete doc._rev; + assertFalse(doc.hasOwnProperty("_rev")); + assertUndefined(doc._rev); + + delete doc._id; + assertFalse(doc.hasOwnProperty("_id")); + assertUndefined(doc._id); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion after deletion +//////////////////////////////////////////////////////////////////////////////// + + testDeletionDeletion : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("one")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("values")); + + assertEqual([ "_id", "_key", "_rev", "one", "text", "value", "values" ], Object.keys(doc).sort()); + + // delete _key + delete doc._key; + assertEqual([ "_id", "_rev", "one", "text", "value", "values" ], Object.keys(doc).sort()); + + // delete text + delete doc.text; + assertEqual([ "_id", "_rev", "one", "value", "values" ], Object.keys(doc).sort()); + + // delete _id + delete doc._id; + assertEqual([ "_rev", "one", "value", "values" ], Object.keys(doc).sort()); + + // delete value + delete doc.value; + assertEqual([ "_rev", "one", "values" ], Object.keys(doc).sort()); + + // delete _rev + delete doc._rev; + assertEqual([ "one", "values" ], Object.keys(doc).sort()); + + // delete values + delete doc.values; + assertEqual([ "one" ], Object.keys(doc).sort()); + + // delete one + delete doc.one; + assertEqual([ ], Object.keys(doc).sort()); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of keys from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionAfterUpdate : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + + doc._key = "foobar"; + assertEqual("foobar", doc._key); + doc._rev = 12345; + assertEqual(12345, doc._rev); + doc._id = "foo"; + assertEqual("foo", doc._id); + + delete doc._key; + delete doc._rev; + + assertFalse(doc.hasOwnProperty("_rev")); + assertFalse(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_id")); + assertEqual("foo", doc._id); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of keys from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionSomeAttributes : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + + delete doc._key; + delete doc.value; + + assertFalse(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertFalse(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of keys from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionIndexed : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + delete doc._key; + doc[9] = "42!"; + + assertFalse(doc.hasOwnProperty("_key")); + assertEqual("42!", doc[9]); + + delete doc[9]; + assertFalse(doc.hasOwnProperty(9)); + assertFalse(doc.hasOwnProperty("9")); + assertUndefined(doc[9]); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of keys from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionNested : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + delete doc.one.two.three; + + assertTrue(doc.hasOwnProperty("one")); + assertTrue(doc.one.hasOwnProperty("two")); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check access after deletion of documents +//////////////////////////////////////////////////////////////////////////////// + + testAccessAfterDeletion : function () { + var docs = [ ]; + for (var i = 0; i < 100; ++i) { + docs[i] = c.document("test" + i); + } + + c.truncate(); + + internal.wait(5); + + for (i = 0; i < 100; ++i) { + assertEqual(cn + "/test" + i, docs[i]._id); + assertEqual("test" + i, docs[i]._key); + assertEqual("Test" + i, docs[i].text); + assertEqual([ i ], docs[i].values); + assertEqual({ two: { three: [ 1 ] } }, docs[i].one); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check access after dropping collection +//////////////////////////////////////////////////////////////////////////////// + + testAccessAfterDropping : function () { + var docs = [ ]; + for (var i = 0; i < 100; ++i) { + docs[i] = c.document("test" + i); + } + + c.drop(); + + internal.wait(5); + + for (i = 0; i < 100; ++i) { + assertEqual(cn + "/test" + i, docs[i]._id); + assertEqual("test" + i, docs[i]._key); + assertEqual("Test" + i, docs[i].text); + assertEqual([ i ], docs[i].values); + assertEqual({ two: { three: [ 1 ] } }, docs[i].one); + } + } + + }; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test suite +//////////////////////////////////////////////////////////////////////////////// + +function EdgeShapedJsonSuite () { + 'use strict'; + var cn = "UnitTestsCollectionShaped"; + var c; + + return { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief set up +//////////////////////////////////////////////////////////////////////////////// + + setUp : function () { + db._drop(cn); + c = db._createEdgeCollection(cn); + + for (var i = 0; i < 100; ++i) { + c.save(cn + "/from" + i, + cn + "/to" + i, + { _key: "test" + i, + value: i, + text: "Test" + i, + values: [ i ], + one: { two: { three: [ 1 ] } } }); + } + + // wait until the documents are actually shaped json + internal.wal.flush(true, true); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tear down +//////////////////////////////////////////////////////////////////////////////// + + tearDown : function () { + db._drop(cn); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check updating of keys in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testUpdatePseudo : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + assertEqual(cn + "/from" + i, doc._from); + assertEqual(cn + "/to" + i, doc._to); + + doc._from = "foobarbaz"; + doc._to = "meow"; + + assertEqual("foobarbaz", doc._from); + assertEqual("meow", doc._to); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check adding attributes in shaped json +//////////////////////////////////////////////////////////////////////////////// + + testAddAttribute : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + doc["some attribute set now"] = "aha"; + + assertTrue(doc.hasOwnProperty("some attribute set now")); + assertEqual("aha", doc["some attribute set now"]); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of keys from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionPseudoFirst : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("_from")); + assertTrue(doc.hasOwnProperty("_to")); + + // delete pseudo-attributes + delete doc._from; + assertFalse(doc.hasOwnProperty("_from")); + + delete doc._to; + assertFalse(doc.hasOwnProperty("_to")); + + delete doc._key; + assertFalse(doc.hasOwnProperty("_key")); + + delete doc._rev; + assertFalse(doc.hasOwnProperty("_rev")); + + delete doc._id; + assertFalse(doc.hasOwnProperty("_id")); + + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of keys from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionShapedFirst : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_from")); + assertTrue(doc.hasOwnProperty("_to")); + assertTrue(doc.hasOwnProperty("value")); + + // delete shaped attributes first + delete doc.value; + assertFalse(doc.hasOwnProperty("value")); + assertUndefined(doc.value); + + delete doc._from; + assertFalse(doc.hasOwnProperty("_from")); + assertUndefined(doc._from); + + delete doc._to; + assertFalse(doc.hasOwnProperty("_to")); + assertUndefined(doc._to); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of special attributes from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionShapedKeyRev : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_from")); + assertTrue(doc.hasOwnProperty("_to")); + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + + // delete special attribute _key + delete doc._key; + assertFalse(doc.hasOwnProperty("_key")); + assertUndefined(doc._key); + assertTrue(doc.hasOwnProperty("_from")); + assertTrue(doc.hasOwnProperty("_to")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + + // delete special attribute _rev + delete doc._rev; + assertFalse(doc.hasOwnProperty("_rev")); + assertFalse(doc.hasOwnProperty("_key")); + assertUndefined(doc._rev); + assertTrue(doc.hasOwnProperty("_from")); + assertTrue(doc.hasOwnProperty("_to")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("values")); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion of keys from shaped json +//////////////////////////////////////////////////////////////////////////////// + + testDeletionAfterUpdate : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_from")); + assertTrue(doc.hasOwnProperty("_to")); + + doc._from = "foobar"; + assertEqual("foobar", doc._from); + doc._from = 12345; + assertEqual(12345, doc._from); + doc._to = "foo"; + assertEqual("foo", doc._to); + + delete doc._from; + delete doc._to; + + assertFalse(doc.hasOwnProperty("_from")); + assertFalse(doc.hasOwnProperty("_to")); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check deletion after deletion +//////////////////////////////////////////////////////////////////////////////// + + testDeletionDeletion : function () { + for (var i = 0; i < 100; ++i) { + var doc = c.document("test" + i); + + // initial state + assertTrue(doc.hasOwnProperty("_from")); + assertTrue(doc.hasOwnProperty("_to")); + assertTrue(doc.hasOwnProperty("_key")); + assertTrue(doc.hasOwnProperty("_rev")); + assertTrue(doc.hasOwnProperty("_id")); + assertTrue(doc.hasOwnProperty("one")); + assertTrue(doc.hasOwnProperty("text")); + assertTrue(doc.hasOwnProperty("value")); + assertTrue(doc.hasOwnProperty("values")); + + var keys = Object.keys(doc).sort(); + assertEqual([ "_from", "_id", "_key", "_rev", "_to", "one", "text", "value", "values" ], keys); + + // delete _from + delete doc._from; + assertEqual([ "_id", "_key", "_rev", "_to", "one", "text", "value", "values" ], Object.keys(doc).sort()); + + // delete _to + delete doc._to; + assertEqual([ "_id", "_key", "_rev", "one", "text", "value", "values" ], Object.keys(doc).sort()); + + // delete _key + delete doc._key; + assertEqual([ "_id", "_rev", "one", "text", "value", "values" ], Object.keys(doc).sort()); + + // delete text + delete doc.text; + assertEqual([ "_id", "_rev", "one", "value", "values" ], Object.keys(doc).sort()); + + // delete _id + delete doc._id; + assertEqual([ "_rev", "one", "value", "values" ], Object.keys(doc).sort()); + + // delete value + delete doc.value; + assertEqual([ "_rev", "one", "values" ], Object.keys(doc).sort()); + + // delete _rev + delete doc._rev; + assertEqual([ "one", "values" ], Object.keys(doc).sort()); + + // delete values + delete doc.values; + assertEqual([ "one" ], Object.keys(doc).sort()); + + // delete one + delete doc.one; + assertEqual([ ], Object.keys(doc).sort()); + } + } + + }; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test suite +//////////////////////////////////////////////////////////////////////////////// + +function GeoShapedJsonSuite () { + 'use strict'; + var cn = "UnitTestsCollectionShaped"; + var c; + + return { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief set up +//////////////////////////////////////////////////////////////////////////////// + + setUp : function () { + db._drop(cn); + c = db._create(cn); + c.ensureGeoIndex("lat", "lon"); + + for (var i = -3; i < 3; ++i) { + for (var j = -3; j < 3; ++j) { + c.save({ distance: 0, lat: 40 + 0.01 * i, lon: 40 + 0.01 * j, something: "test" }); + } + } + + + // wait until the documents are actually shaped json + internal.wal.flush(true, true); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tear down +//////////////////////////////////////////////////////////////////////////////// + + tearDown : function () { + db._drop(cn); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief call within function with "distance" attribute +//////////////////////////////////////////////////////////////////////////////// + + testDistance : function () { + var result = db._query( + "FOR u IN WITHIN(" + cn + ", 40.0, 40.0, 5000000, 'distance') " + + "SORT u.distance "+ + "RETURN { lat: u.lat, lon: u.lon, distance: u.distance }" + ).toArray(); + + // skip first result (which has a distance of 0) + for (var i = 1; i < result.length; ++i) { + var doc = result[i]; + + assertTrue(doc.hasOwnProperty("lat")); + assertTrue(doc.hasOwnProperty("lon")); + assertTrue(doc.hasOwnProperty("distance")); + assertTrue(doc.distance > 0); + } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief call near function with "distance" attribute +//////////////////////////////////////////////////////////////////////////////// + + testNear : function () { + var result = db._query( + "FOR u IN NEAR(" + cn + ", 40.0, 40.0, 5, 'something') SORT u.something " + + "RETURN { lat: u.lat, lon: u.lon, distance: u.something }") + .toArray(); + + // skip first result (which has a distance of 0) + for (var i = 1; i < result.length; ++i) { + var doc = result[i]; + + assertTrue(doc.hasOwnProperty("lat")); + assertTrue(doc.hasOwnProperty("lon")); + assertTrue(doc.hasOwnProperty("distance")); + assertTrue(doc.distance >= 0); + } + } + + }; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief executes the test suite +//////////////////////////////////////////////////////////////////////////////// + +jsunity.run(DocumentShapedJsonSuite); +jsunity.run(EdgeShapedJsonSuite); +jsunity.run(GeoShapedJsonSuite); + +return jsunity.done(); diff --git a/js/server/tests/shell/shell-wal-noncluster-memoryintense.js b/js/server/tests/shell/shell-wal-mmfiles-noncluster-memoryintense.js similarity index 100% rename from js/server/tests/shell/shell-wal-noncluster-memoryintense.js rename to js/server/tests/shell/shell-wal-mmfiles-noncluster-memoryintense.js