From 161ce9607d27f2731d145a5fb42e9675ef5a61e5 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 27 Jun 2019 21:13:03 +0200 Subject: [PATCH] added test for object creation (#9355) --- arangod/StorageEngine/PhysicalCollection.cpp | 12 +- arangod/StorageEngine/PhysicalCollection.h | 10 +- tests/CMakeLists.txt | 1 + .../StorageEngine/PhysicalCollectionTest.cpp | 176 ++++++++++++++++++ 4 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 tests/StorageEngine/PhysicalCollectionTest.cpp diff --git a/arangod/StorageEngine/PhysicalCollection.cpp b/arangod/StorageEngine/PhysicalCollection.cpp index 5585061d41..ebb5129740 100644 --- a/arangod/StorageEngine/PhysicalCollection.cpp +++ b/arangod/StorageEngine/PhysicalCollection.cpp @@ -175,7 +175,7 @@ TRI_voc_rid_t PhysicalCollection::newRevisionId() const { /// @brief merge two objects for update, oldValue must have correctly set /// _key and _id attributes Result PhysicalCollection::mergeObjectsForUpdate( - transaction::Methods* trx, VPackSlice const& oldValue, + transaction::Methods*, VPackSlice const& oldValue, VPackSlice const& newValue, bool isEdgeCollection, bool mergeObjects, bool keepNull, VPackBuilder& b, bool isRestore, TRI_voc_rid_t& revisionId) const { b.openObject(); @@ -325,7 +325,7 @@ Result PhysicalCollection::mergeObjectsForUpdate( } /// @brief new object for insert, computes the hash of the key -Result PhysicalCollection::newObjectForInsert(transaction::Methods* trx, +Result PhysicalCollection::newObjectForInsert(transaction::Methods*, VPackSlice const& value, bool isEdgeCollection, VPackBuilder& builder, bool isRestore, TRI_voc_rid_t& revisionId) const { @@ -348,6 +348,8 @@ Result PhysicalCollection::newObjectForInsert(transaction::Methods* trx, } else if (!s.isString()) { return Result(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD); } else { + TRI_ASSERT(s.isString()); + VPackValueLength l; char const* p = s.getStringUnchecked(l); @@ -426,7 +428,7 @@ Result PhysicalCollection::newObjectForInsert(transaction::Methods* trx, } /// @brief new object for remove, must have _key set -void PhysicalCollection::newObjectForRemove(transaction::Methods* trx, +void PhysicalCollection::newObjectForRemove(transaction::Methods*, VPackSlice const& oldValue, VPackBuilder& builder, bool isRestore, TRI_voc_rid_t& revisionId) const { @@ -449,7 +451,7 @@ void PhysicalCollection::newObjectForRemove(transaction::Methods* trx, /// @brief new object for replace, oldValue must have _key and _id correctly /// set -Result PhysicalCollection::newObjectForReplace(transaction::Methods* trx, +Result PhysicalCollection::newObjectForReplace(transaction::Methods*, VPackSlice const& oldValue, VPackSlice const& newValue, bool isEdgeCollection, VPackBuilder& builder, bool isRestore, @@ -515,7 +517,7 @@ Result PhysicalCollection::newObjectForReplace(transaction::Methods* trx, } /// @brief checks the revision of a document -int PhysicalCollection::checkRevision(transaction::Methods* trx, TRI_voc_rid_t expected, +int PhysicalCollection::checkRevision(transaction::Methods*, TRI_voc_rid_t expected, TRI_voc_rid_t found) const { if (expected != 0 && found != expected) { return TRI_ERROR_ARANGO_CONFLICT; diff --git a/arangod/StorageEngine/PhysicalCollection.h b/arangod/StorageEngine/PhysicalCollection.h index bb0cb2ebb6..8f5365912a 100644 --- a/arangod/StorageEngine/PhysicalCollection.h +++ b/arangod/StorageEngine/PhysicalCollection.h @@ -197,6 +197,11 @@ class PhysicalCollection { ManagedDocumentResult& previous, OperationOptions& options, bool lock, KeyLockInfo* keyLockInfo, std::function const& cbDuringLock) = 0; + + /// @brief new object for insert, value must have _key set correctly. + Result newObjectForInsert(transaction::Methods* trx, velocypack::Slice const& value, + bool isEdgeCollection, velocypack::Builder& builder, + bool isRestore, TRI_voc_rid_t& revisionId) const; protected: PhysicalCollection(LogicalCollection& collection, arangodb::velocypack::Slice const& info); @@ -210,11 +215,6 @@ class PhysicalCollection { bool isValidEdgeAttribute(velocypack::Slice const& slice) const; - /// @brief new object for insert, value must have _key set correctly. - Result newObjectForInsert(transaction::Methods* trx, velocypack::Slice const& value, - bool isEdgeCollection, velocypack::Builder& builder, - bool isRestore, TRI_voc_rid_t& revisionId) const; - /// @brief new object for remove, must have _key set void newObjectForRemove(transaction::Methods* trx, velocypack::Slice const& oldValue, velocypack::Builder& builder, bool isRestore, diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 91d11ac02e..ceba2f54df 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -178,6 +178,7 @@ set(ARANGODB_TESTS_SOURCES RocksDBEngine/IndexEstimatorTest.cpp Sharding/ShardDistributionReporterTest.cpp SimpleHttpClient/CommunicatorTest.cpp + StorageEngine/PhysicalCollectionTest.cpp Transaction/Context-test.cpp Transaction/Manager-test.cpp Transaction/RestTransactionHandler-test.cpp diff --git a/tests/StorageEngine/PhysicalCollectionTest.cpp b/tests/StorageEngine/PhysicalCollectionTest.cpp new file mode 100644 index 0000000000..0cc8eaeabc --- /dev/null +++ b/tests/StorageEngine/PhysicalCollectionTest.cpp @@ -0,0 +1,176 @@ +//////////////////////////////////////////////////////////////////////////////// +/// DISCLAIMER +/// +/// Copyright 2018 ArangoDB 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 ArangoDB GmbH, Cologne, Germany +/// +/// @author Jan Steemann +//////////////////////////////////////////////////////////////////////////////// + +#include "gtest/gtest.h" + +#include "../IResearch/RestHandlerMock.h" +#include "../Mocks/StorageEngineMock.h" +#include "Aql/QueryRegistry.h" +#include "Basics/Result.h" +#if USE_ENTERPRISE +#include "Enterprise/Ldap/LdapFeature.h" +#endif +#include "GeneralServer/AuthenticationFeature.h" +#include "RestServer/DatabaseFeature.h" +#include "RestServer/QueryRegistryFeature.h" +#include "StorageEngine/EngineSelectorFeature.h" + +#include +#include +#include + +using namespace arangodb; + +// ----------------------------------------------------------------------------- +// --SECTION-- setup / tear-down +// ----------------------------------------------------------------------------- + +class PhysicalCollectionTest : public ::testing::Test { + protected: + StorageEngineMock engine; + arangodb::application_features::ApplicationServer server; + std::vector features; + + PhysicalCollectionTest() : engine(server), server(nullptr, nullptr) { + arangodb::EngineSelectorFeature::ENGINE = &engine; + + // setup required application features + features.emplace_back(new arangodb::AuthenticationFeature(server)); // required for VocbaseContext + features.emplace_back(new arangodb::DatabaseFeature(server)); + features.emplace_back(new arangodb::QueryRegistryFeature(server)); // required for TRI_vocbase_t + +#if USE_ENTERPRISE + features.emplace_back(new arangodb::LdapFeature(server)); +#endif + + for (auto& f : features) { + arangodb::application_features::ApplicationServer::server->addFeature(f); + } + + for (auto& f : features) { + f->prepare(); + } + } + + ~PhysicalCollectionTest() { + arangodb::application_features::ApplicationServer::server = nullptr; + arangodb::EngineSelectorFeature::ENGINE = nullptr; + + for (auto& f : features) { + f->unprepare(); + } + } +}; + +// ----------------------------------------------------------------------------- +// --SECTION-- test suite +// ----------------------------------------------------------------------------- + +TEST_F(PhysicalCollectionTest, test_new_object_for_insert) { + TRI_vocbase_t vocbase(TRI_vocbase_type_e::TRI_VOCBASE_TYPE_NORMAL, 1, "testVocbase"); + + auto json = arangodb::velocypack::Parser::fromJson("{ \"name\": \"test\" }"); + auto collection = vocbase.createCollection(json->slice()); + + auto physical = engine.createPhysicalCollection(*collection, json->slice()); + + auto doc = arangodb::velocypack::Parser::fromJson("{ \"doc1\":\"test1\", \"doc100\":\"test2\", \"doc2\":\"test3\", \"z\":1, \"b\":2, \"a\":3, \"Z\":1, \"B\":2, \"A\": 3, \"_foo\":1, \"_bar\":2, \"_zoo\":3 }"); + + TRI_voc_rid_t revisionId = 0; + arangodb::velocypack::Builder builder; + Result res = physical->newObjectForInsert(nullptr, doc->slice(), false, builder, false, revisionId); + EXPECT_TRUE(res.ok()); + EXPECT_TRUE(revisionId > 0); + + auto slice = builder.slice(); + + EXPECT_TRUE(slice.hasKey("_key")); + EXPECT_TRUE(slice.get("_key").isString()); + EXPECT_TRUE(slice.hasKey("_id")); + EXPECT_TRUE(slice.get("_id").isCustom()); + EXPECT_TRUE(slice.hasKey("_rev")); + EXPECT_TRUE(slice.get("_rev").isString()); + + EXPECT_TRUE(slice.get("doc1").isString()); + EXPECT_EQ("test1", slice.get("doc1").copyString()); + EXPECT_TRUE(slice.get("doc100").isString()); + EXPECT_EQ("test2", slice.get("doc100").copyString()); + EXPECT_TRUE(slice.get("doc2").isString()); + EXPECT_EQ("test3", slice.get("doc2").copyString()); + + EXPECT_TRUE(slice.hasKey("z")); + EXPECT_TRUE(slice.get("z").isNumber()); + EXPECT_EQ(1, slice.get("z").getNumber()); + EXPECT_TRUE(slice.hasKey("b")); + EXPECT_TRUE(slice.get("b").isNumber()); + EXPECT_EQ(2, slice.get("b").getNumber()); + EXPECT_TRUE(slice.hasKey("a")); + EXPECT_TRUE(slice.get("a").isNumber()); + EXPECT_EQ(3, slice.get("a").getNumber()); + + EXPECT_TRUE(slice.hasKey("Z")); + EXPECT_TRUE(slice.get("Z").isNumber()); + EXPECT_EQ(1, slice.get("Z").getNumber()); + EXPECT_TRUE(slice.hasKey("B")); + EXPECT_TRUE(slice.get("B").isNumber()); + EXPECT_EQ(2, slice.get("B").getNumber()); + EXPECT_TRUE(slice.hasKey("A")); + EXPECT_TRUE(slice.get("A").isNumber()); + EXPECT_EQ(3, slice.get("A").getNumber()); + + EXPECT_TRUE(slice.hasKey("_foo")); + EXPECT_TRUE(slice.get("_foo").isNumber()); + EXPECT_EQ(1, slice.get("_foo").getNumber()); + EXPECT_TRUE(slice.hasKey("_bar")); + EXPECT_TRUE(slice.get("_bar").isNumber()); + EXPECT_EQ(2, slice.get("_bar").getNumber()); + EXPECT_TRUE(slice.hasKey("_zoo")); + EXPECT_TRUE(slice.get("_zoo").isNumber()); + EXPECT_EQ(3, slice.get("_zoo").getNumber()); + + EXPECT_TRUE(slice.isObject()); + EXPECT_TRUE(slice.head() == 0xbU); + + // iterate over the data in the order that is stored in the builder + { + velocypack::ObjectIterator it(slice, true); + std::vector expected{ "_key", "_id", "_rev", "doc1", "doc100", "doc2", "z", "b", "a", "Z", "B", "A", "_foo", "_bar", "_zoo" }; + + for (auto const& key : expected) { + EXPECT_TRUE(it.valid()); + EXPECT_EQ(key, it.key().copyString()); + it.next(); + } + } + + // iterate over the data in the order that is stored in the index table + { + velocypack::ObjectIterator it(slice, false); + std::vector expected{ "A", "B", "Z", "_bar", "_foo", "_id", "_key", "_rev", "_zoo", "a", "b", "doc1", "doc100", "doc2", "z" }; + + for (auto const& key : expected) { + EXPECT_TRUE(it.valid()); + EXPECT_EQ(key, it.key().copyString()); + it.next(); + } + } + }