// Copyright 2024 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source // License, and you may not use this file except in compliance with the Business Source License. // // As of the Change Date specified in that file, in accordance with // the Business Source License, use of this software will be governed // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. #include #include #include #include #include "disk_test_utils.hpp" #include "storage/v2/disk/storage.hpp" #include "storage/v2/inmemory/storage.hpp" #include "storage/v2/property_value.hpp" #include "storage/v2/storage.hpp" #include "storage/v2/vertex_accessor.hpp" #include "storage_test_utils.hpp" using memgraph::replication::ReplicationRole; using testing::Types; using testing::UnorderedElementsAre; template class StorageV2Test : public testing::Test { public: StorageV2Test() { config_ = disk_test_utils::GenerateOnDiskConfig(testSuite); store = std::make_unique(config_); } void TearDown() override { if (std::is_same::value) { disk_test_utils::RemoveRocksDbDirs(testSuite); } store.reset(nullptr); } const std::string testSuite = "storage_v2"; std::unique_ptr store; memgraph::storage::Config config_; }; using StorageTypes = ::testing::Types; TYPED_TEST_CASE(StorageV2Test, StorageTypes); // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, Commit) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(acc->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 1U); ASSERT_FALSE(acc->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); ASSERT_TRUE(acc->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 1U); acc->Abort(); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::NEW); ASSERT_TRUE(vertex); auto res = acc->DeleteVertex(&*vertex); ASSERT_FALSE(res.HasError()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); acc->AdvanceCommand(); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); ASSERT_FALSE(acc->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); ASSERT_FALSE(acc->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, Abort) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(acc->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 1U); acc->Abort(); } { auto acc = this->store->Access(ReplicationRole::MAIN); ASSERT_FALSE(acc->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, AdvanceCommandCommit) { memgraph::storage::Gid gid1 = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); memgraph::storage::Gid gid2 = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex1 = acc->CreateVertex(); gid1 = vertex1.Gid(); ASSERT_FALSE(acc->FindVertex(gid1, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(acc->FindVertex(gid1, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 1U); acc->AdvanceCommand(); auto vertex2 = acc->CreateVertex(); gid2 = vertex2.Gid(); ASSERT_FALSE(acc->FindVertex(gid2, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc->FindVertex(gid2, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 2U); ASSERT_TRUE(acc->FindVertex(gid1, memgraph::storage::View::OLD).has_value()); ASSERT_TRUE(acc->FindVertex(gid1, memgraph::storage::View::NEW).has_value()); ASSERT_FALSE(acc->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); ASSERT_TRUE(acc->FindVertex(gid1, memgraph::storage::View::OLD).has_value()); ASSERT_TRUE(acc->FindVertex(gid1, memgraph::storage::View::NEW).has_value()); ASSERT_TRUE(acc->FindVertex(gid2, memgraph::storage::View::OLD).has_value()); ASSERT_TRUE(acc->FindVertex(gid2, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 2U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 2U); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, AdvanceCommandAbort) { memgraph::storage::Gid gid1 = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); memgraph::storage::Gid gid2 = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex1 = acc->CreateVertex(); gid1 = vertex1.Gid(); ASSERT_FALSE(acc->FindVertex(gid1, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(acc->FindVertex(gid1, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 1U); acc->AdvanceCommand(); auto vertex2 = acc->CreateVertex(); gid2 = vertex2.Gid(); ASSERT_FALSE(acc->FindVertex(gid2, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc->FindVertex(gid2, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 2U); ASSERT_TRUE(acc->FindVertex(gid1, memgraph::storage::View::OLD).has_value()); ASSERT_TRUE(acc->FindVertex(gid1, memgraph::storage::View::NEW).has_value()); acc->Abort(); } { auto acc = this->store->Access(ReplicationRole::MAIN); ASSERT_FALSE(acc->FindVertex(gid1, memgraph::storage::View::OLD).has_value()); ASSERT_FALSE(acc->FindVertex(gid1, memgraph::storage::View::NEW).has_value()); ASSERT_FALSE(acc->FindVertex(gid2, memgraph::storage::View::OLD).has_value()); ASSERT_FALSE(acc->FindVertex(gid2, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, SnapshotIsolation) { auto acc1 = this->store->Access(ReplicationRole::MAIN); auto acc2 = this->store->Access(ReplicationRole::MAIN); auto vertex = acc1->CreateVertex(); auto gid = vertex.Gid(); ASSERT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 1U); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::NEW), 0U); ASSERT_FALSE(acc1->Commit().HasError()); ASSERT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::NEW), 0U); acc2->Abort(); auto acc3 = this->store->Access(ReplicationRole::MAIN); ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::NEW), 1U); acc3->Abort(); } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, AccessorMove) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(acc->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 1U); auto moved(std::move(acc)); ASSERT_FALSE(moved->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*moved, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(moved->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*moved, memgraph::storage::View::NEW), 1U); ASSERT_FALSE(moved->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); ASSERT_TRUE(acc->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 1U); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexDeleteCommit) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); auto acc1 = this->store->Access(ReplicationRole::MAIN); // read transaction auto acc2 = this->store->Access(ReplicationRole::MAIN); // write transaction // Create the vertex in transaction 2 { auto vertex = acc2->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::NEW), 1U); ASSERT_FALSE(acc2->Commit().HasError()); } auto acc3 = this->store->Access(ReplicationRole::MAIN); // read transaction auto acc4 = this->store->Access(ReplicationRole::MAIN); // write transaction // Check whether the vertex exists in transaction 1 ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 0U); // Check whether the vertex exists in transaction 3 ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::NEW), 1U); // Delete the vertex in transaction 4 { auto vertex = acc4->FindVertex(gid, memgraph::storage::View::NEW); ASSERT_TRUE(vertex); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::NEW), 1U); auto res = acc4->DeleteVertex(&*vertex); ASSERT_TRUE(res.HasValue()); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::NEW), 0U); acc4->AdvanceCommand(); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::NEW), 0U); ASSERT_FALSE(acc4->Commit().HasError()); } auto acc5 = this->store->Access(ReplicationRole::MAIN); // read transaction // Check whether the vertex exists in transaction 1 ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 0U); // Check whether the vertex exists in transaction 3 ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::NEW), 1U); // Check whether the vertex exists in transaction 5 ASSERT_FALSE(acc5->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc5, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc5->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc5, memgraph::storage::View::NEW), 0U); } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexDeleteAbort) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); auto acc1 = this->store->Access(ReplicationRole::MAIN); // read transaction auto acc2 = this->store->Access(ReplicationRole::MAIN); // write transaction // Create the vertex in transaction 2 { auto vertex = acc2->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::NEW), 1U); ASSERT_FALSE(acc2->Commit().HasError()); } auto acc3 = this->store->Access(ReplicationRole::MAIN); // read transaction auto acc4 = this->store->Access(ReplicationRole::MAIN); // write transaction (aborted) // Check whether the vertex exists in transaction 1 ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 0U); // Check whether the vertex exists in transaction 3 ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::NEW), 1U); // Delete the vertex in transaction 4, but abort the transaction { auto vertex = acc4->FindVertex(gid, memgraph::storage::View::NEW); ASSERT_TRUE(vertex); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::NEW), 1U); auto res = acc4->DeleteVertex(&*vertex); ASSERT_TRUE(res.HasValue()); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::NEW), 0U); acc4->AdvanceCommand(); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc4, memgraph::storage::View::NEW), 0U); acc4->Abort(); } auto acc5 = this->store->Access(ReplicationRole::MAIN); // read transaction auto acc6 = this->store->Access(ReplicationRole::MAIN); // write transaction // Check whether the vertex exists in transaction 1 ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 0U); // Check whether the vertex exists in transaction 3 ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::NEW), 1U); // Check whether the vertex exists in transaction 5 ASSERT_TRUE(acc5->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc5, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc5->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc5, memgraph::storage::View::NEW), 1U); // Delete the vertex in transaction 6 { auto vertex = acc6->FindVertex(gid, memgraph::storage::View::NEW); ASSERT_TRUE(vertex); EXPECT_EQ(CountVertices(*acc6, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc6, memgraph::storage::View::NEW), 1U); auto res = acc6->DeleteVertex(&*vertex); ASSERT_TRUE(res.HasValue()); EXPECT_EQ(CountVertices(*acc6, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc6, memgraph::storage::View::NEW), 0U); acc6->AdvanceCommand(); EXPECT_EQ(CountVertices(*acc6, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc6, memgraph::storage::View::NEW), 0U); ASSERT_FALSE(acc6->Commit().HasError()); } auto acc7 = this->store->Access(ReplicationRole::MAIN); // read transaction // Check whether the vertex exists in transaction 1 ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 0U); // Check whether the vertex exists in transaction 3 ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc3, memgraph::storage::View::NEW), 1U); // Check whether the vertex exists in transaction 5 ASSERT_TRUE(acc5->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc5, memgraph::storage::View::OLD), 1U); ASSERT_TRUE(acc5->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc5, memgraph::storage::View::NEW), 1U); // Check whether the vertex exists in transaction 7 ASSERT_FALSE(acc7->FindVertex(gid, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc7, memgraph::storage::View::OLD), 0U); ASSERT_FALSE(acc7->FindVertex(gid, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc7, memgraph::storage::View::NEW), 0U); // Commit all accessors ASSERT_FALSE(acc1->Commit().HasError()); ASSERT_FALSE(acc3->Commit().HasError()); ASSERT_FALSE(acc5->Commit().HasError()); ASSERT_FALSE(acc7->Commit().HasError()); } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexDeleteSerializationError) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); // Create vertex { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->Commit().HasError()); } auto acc1 = this->store->Access(ReplicationRole::MAIN); auto acc2 = this->store->Access(ReplicationRole::MAIN); // Delete vertex in accessor 1 { auto vertex = acc1->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 1U); { auto res = acc1->DeleteVertex(&*vertex); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 0U); } { auto res = acc1->DeleteVertex(&*vertex); ASSERT_TRUE(res.HasValue()); ASSERT_FALSE(res.GetValue()); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 0U); } acc1->AdvanceCommand(); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc1, memgraph::storage::View::NEW), 0U); } // Delete vertex in accessor 2 { auto vertex = acc2->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::NEW), 1U); auto res = acc2->DeleteVertex(&*vertex); if (std::is_same::value) { // Serialization error for disk will be on commit ASSERT_TRUE(res.HasError()); ASSERT_EQ(res.GetError(), memgraph::storage::Error::SERIALIZATION_ERROR); } EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::OLD), 1U); if (std::is_same::value) { // Beucase of pessimistic Serialization error happened on DeleteVertex() function EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::NEW), 1U); } else { EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::NEW), 0U); } acc2->AdvanceCommand(); if (std::is_same::value) { EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::OLD), 1U); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::NEW), 1U); } else { EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc2, memgraph::storage::View::NEW), 0U); } } // Finalize both accessors ASSERT_FALSE(acc1->Commit().HasError()); if (std::is_same::value) { acc2->Abort(); } else { auto res = acc2->Commit(); ASSERT_TRUE(res.HasError()); ASSERT_EQ(std::get(res.GetError()), memgraph::storage::SerializationError()); } // Check whether the vertex exists { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_FALSE(vertex); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); ASSERT_FALSE(acc->Commit().HasError()); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexDeleteSpecialCases) { memgraph::storage::Gid gid1 = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); memgraph::storage::Gid gid2 = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); // Create vertex and delete it in the same transaction, but abort the // transaction { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid1 = vertex.Gid(); ASSERT_FALSE(acc->FindVertex(gid1, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(acc->FindVertex(gid1, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 1U); auto res = acc->DeleteVertex(&vertex); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); acc->AdvanceCommand(); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); acc->Abort(); } // Create vertex and delete it in the same transaction { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid2 = vertex.Gid(); ASSERT_FALSE(acc->FindVertex(gid2, memgraph::storage::View::OLD).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); ASSERT_TRUE(acc->FindVertex(gid2, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 1U); auto res = acc->DeleteVertex(&vertex); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); acc->AdvanceCommand(); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); ASSERT_FALSE(acc->Commit().HasError()); } // Check whether the vertices exist { auto acc = this->store->Access(ReplicationRole::MAIN); ASSERT_FALSE(acc->FindVertex(gid1, memgraph::storage::View::OLD).has_value()); ASSERT_FALSE(acc->FindVertex(gid1, memgraph::storage::View::NEW).has_value()); ASSERT_FALSE(acc->FindVertex(gid2, memgraph::storage::View::OLD).has_value()); ASSERT_FALSE(acc->FindVertex(gid2, memgraph::storage::View::NEW).has_value()); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::OLD), 0U); EXPECT_EQ(CountVertices(*acc, memgraph::storage::View::NEW), 0U); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexDeleteLabel) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); // Create the vertex { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->FindVertex(gid, memgraph::storage::View::OLD).has_value()); ASSERT_TRUE(acc->FindVertex(gid, memgraph::storage::View::NEW).has_value()); ASSERT_FALSE(acc->Commit().HasError()); } // Add label, delete the vertex and check the label API (same command) { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::NEW); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); // Check whether label 5 exists ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); // Add label 5 ASSERT_TRUE(vertex->AddLabel(label).GetValue()); // Check whether label 5 exists ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } // Delete the vertex ASSERT_TRUE(acc->DeleteVertex(&*vertex).GetValue()); // Check whether label 5 exists ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_EQ(vertex->HasLabel(label, memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); // Try to add the label { auto ret = vertex->AddLabel(label); ASSERT_TRUE(ret.HasError()); ASSERT_EQ(ret.GetError(), memgraph::storage::Error::DELETED_OBJECT); } // Try to remove the label { auto ret = vertex->RemoveLabel(label); ASSERT_TRUE(ret.HasError()); ASSERT_EQ(ret.GetError(), memgraph::storage::Error::DELETED_OBJECT); } acc->Abort(); } // Add label, delete the vertex and check the label API (different command) { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::NEW); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); // Check whether label 5 exists ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); // Add label 5 ASSERT_TRUE(vertex->AddLabel(label).GetValue()); // Check whether label 5 exists ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } // Advance command acc->AdvanceCommand(); // Check whether label 5 exists ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } // Delete the vertex ASSERT_TRUE(acc->DeleteVertex(&*vertex).GetValue()); // Check whether label 5 exists ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_EQ(vertex->HasLabel(label, memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); { auto labels = vertex->Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); // Advance command acc->AdvanceCommand(); // Check whether label 5 exists ASSERT_EQ(vertex->HasLabel(label, memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::DELETED_OBJECT); ASSERT_EQ(vertex->HasLabel(label, memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::DELETED_OBJECT); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); // Try to add the label { auto ret = vertex->AddLabel(label); ASSERT_TRUE(ret.HasError()); ASSERT_EQ(ret.GetError(), memgraph::storage::Error::DELETED_OBJECT); } // Try to remove the label { auto ret = vertex->RemoveLabel(label); ASSERT_TRUE(ret.HasError()); ASSERT_EQ(ret.GetError(), memgraph::storage::Error::DELETED_OBJECT); } acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexDeleteProperty) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); // Create the vertex { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->FindVertex(gid, memgraph::storage::View::OLD).has_value()); ASSERT_TRUE(acc->FindVertex(gid, memgraph::storage::View::NEW).has_value()); ASSERT_FALSE(acc->Commit().HasError()); } // Set property, delete the vertex and check the property API (same command) { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::NEW); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); // Check whether property 5 exists ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); // Set property 5 to "nandare" ASSERT_TRUE(vertex->SetProperty(property, memgraph::storage::PropertyValue("nandare"))->IsNull()); // Check whether property 5 exists ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } // Delete the vertex ASSERT_TRUE(acc->DeleteVertex(&*vertex).GetValue()); // Check whether label 5 exists ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); // Try to set the property { auto ret = vertex->SetProperty(property, memgraph::storage::PropertyValue("haihai")); ASSERT_TRUE(ret.HasError()); ASSERT_EQ(ret.GetError(), memgraph::storage::Error::DELETED_OBJECT); } acc->Abort(); } // Set property, delete the vertex and check the property API (different // command) { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::NEW); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); // Check whether property 5 exists ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); // Set property 5 to "nandare" ASSERT_TRUE(vertex->SetProperty(property, memgraph::storage::PropertyValue("nandare"))->IsNull()); // Check whether property 5 exists ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } // Advance command acc->AdvanceCommand(); // Check whether property 5 exists ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } // Delete the vertex ASSERT_TRUE(acc->DeleteVertex(&*vertex).GetValue()); // Check whether property 5 exists ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); // Advance command acc->AdvanceCommand(); // Check whether property 5 exists ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::DELETED_OBJECT); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::DELETED_OBJECT); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW).GetError(), memgraph::storage::Error::DELETED_OBJECT); // Try to set the property { auto ret = vertex->SetProperty(property, memgraph::storage::PropertyValue("haihai")); ASSERT_TRUE(ret.HasError()); ASSERT_EQ(ret.GetError(), memgraph::storage::Error::DELETED_OBJECT); } acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexLabelCommit) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); auto label = acc->NameToLabel("label5"); ASSERT_FALSE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex.Labels(memgraph::storage::View::NEW)->size(), 0); { auto res = vertex.AddLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); } ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex.Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } { auto res = vertex.AddLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_FALSE(res.GetValue()); } ASSERT_FALSE(acc->Commit().HasError()); spdlog::debug("Commit done"); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } auto other_label = acc->NameToLabel("other"); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::NEW).GetValue()); acc->Abort(); spdlog::debug("Abort done"); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); { auto res = vertex->RemoveLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); } ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); { auto res = vertex->RemoveLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_FALSE(res.GetValue()); } ASSERT_FALSE(acc->Commit().HasError()); spdlog::debug("Commit done"); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); auto other_label = acc->NameToLabel("other"); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::NEW).GetValue()); acc->Abort(); spdlog::debug("Abort done"); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexLabelAbort) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); // Create the vertex. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->Commit().HasError()); } // Add label 5, but abort the transaction. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); { auto res = vertex->AddLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); } ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } { auto res = vertex->AddLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_FALSE(res.GetValue()); } acc->Abort(); } // Check that label 5 doesn't exist. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); auto other_label = acc->NameToLabel("other"); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::NEW).GetValue()); acc->Abort(); } // Add label 5. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); { auto res = vertex->AddLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); } ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } { auto res = vertex->AddLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_FALSE(res.GetValue()); } ASSERT_FALSE(acc->Commit().HasError()); } // Check that label 5 exists. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } auto other_label = acc->NameToLabel("other"); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::NEW).GetValue()); acc->Abort(); } // Remove label 5, but abort the transaction. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); { auto res = vertex->RemoveLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); } ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); { auto res = vertex->RemoveLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_FALSE(res.GetValue()); } acc->Abort(); } // Check that label 5 exists. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } auto other_label = acc->NameToLabel("other"); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::NEW).GetValue()); acc->Abort(); } // Remove label 5. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); { auto res = vertex->RemoveLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); } ASSERT_TRUE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); { auto res = vertex->RemoveLabel(label); ASSERT_TRUE(res.HasValue()); ASSERT_FALSE(res.GetValue()); } ASSERT_FALSE(acc->Commit().HasError()); } // Check that label 5 doesn't exist. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label = acc->NameToLabel("label5"); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); auto other_label = acc->NameToLabel("other"); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(other_label, memgraph::storage::View::NEW).GetValue()); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexLabelSerializationError) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->Commit().HasError()); } auto acc1 = this->store->Access(ReplicationRole::MAIN); auto acc2 = this->store->Access(ReplicationRole::MAIN); // Add label 1 in accessor 1. { auto vertex = acc1->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label1 = acc1->NameToLabel("label1"); auto label2 = acc1->NameToLabel("label2"); ASSERT_FALSE(vertex->HasLabel(label1, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label1, memgraph::storage::View::NEW).GetValue()); ASSERT_FALSE(vertex->HasLabel(label2, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label2, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); { auto res = vertex->AddLabel(label1); ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); } ASSERT_FALSE(vertex->HasLabel(label1, memgraph::storage::View::OLD).GetValue()); ASSERT_TRUE(vertex->HasLabel(label1, memgraph::storage::View::NEW).GetValue()); ASSERT_FALSE(vertex->HasLabel(label2, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label2, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label1); } { auto res = vertex->AddLabel(label1); ASSERT_TRUE(res.HasValue()); ASSERT_FALSE(res.GetValue()); } } // Add label 2 in accessor 2. { auto vertex = acc2->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label1 = acc2->NameToLabel("label1"); auto label2 = acc2->NameToLabel("label2"); ASSERT_FALSE(vertex->HasLabel(label1, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label1, memgraph::storage::View::NEW).GetValue()); ASSERT_FALSE(vertex->HasLabel(label2, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label2, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex->Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Labels(memgraph::storage::View::NEW)->size(), 0); { auto res = vertex->AddLabel(label2); if (std::is_same::value) { // InMemoryStorage works with pessimistic transactions. ASSERT_TRUE(res.HasError()); ASSERT_EQ(res.GetError(), memgraph::storage::Error::SERIALIZATION_ERROR); } else { // Disk storage works with optimistic transactions. ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res.GetValue()); } } } // Finalize both accessors. ASSERT_FALSE(acc1->Commit().HasError()); if (std::is_same::value) { acc2->Abort(); } else { // Disk storage works with optimistic transactions. So on write conflict, transaction fails on commit. auto res = acc2->Commit(); ASSERT_TRUE(res.HasError()); ASSERT_EQ(std::get(res.GetError()), memgraph::storage::SerializationError()); } // Check which labels exist. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto label1 = acc->NameToLabel("label1"); auto label2 = acc->NameToLabel("label2"); ASSERT_TRUE(vertex->HasLabel(label1, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex->HasLabel(label2, memgraph::storage::View::OLD).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label1); } ASSERT_TRUE(vertex->HasLabel(label1, memgraph::storage::View::NEW).GetValue()); ASSERT_FALSE(vertex->HasLabel(label2, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex->Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label1); } acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexPropertyCommit) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); auto property = acc->NameToProperty("property5"); ASSERT_TRUE(vertex.GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 0); { auto old_value = vertex.SetProperty(property, memgraph::storage::PropertyValue("temporary")); ASSERT_TRUE(old_value.HasValue()); ASSERT_TRUE(old_value->IsNull()); } ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "temporary"); { auto properties = vertex.Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "temporary"); } { auto old_value = vertex.SetProperty(property, memgraph::storage::PropertyValue("nandare")); ASSERT_TRUE(old_value.HasValue()); ASSERT_FALSE(old_value->IsNull()); } ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex.Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_FALSE(acc->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } auto other_property = acc->NameToProperty("other"); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::NEW)->IsNull()); acc->Abort(); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); { auto old_value = vertex->SetProperty(property, memgraph::storage::PropertyValue()); ASSERT_TRUE(old_value.HasValue()); ASSERT_FALSE(old_value->IsNull()); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); { auto old_value = vertex->SetProperty(property, memgraph::storage::PropertyValue()); ASSERT_TRUE(old_value.HasValue()); ASSERT_TRUE(old_value->IsNull()); } ASSERT_FALSE(acc->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); auto other_property = acc->NameToProperty("other"); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::NEW)->IsNull()); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexPropertyAbort) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); // Create the vertex. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->Commit().HasError()); } // Set property 5 to "nandare", but abort the transaction. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); { auto old_value = vertex->SetProperty(property, memgraph::storage::PropertyValue("temporary")); ASSERT_TRUE(old_value.HasValue()); ASSERT_TRUE(old_value->IsNull()); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "temporary"); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "temporary"); } { auto old_value = vertex->SetProperty(property, memgraph::storage::PropertyValue("nandare")); ASSERT_TRUE(old_value.HasValue()); ASSERT_FALSE(old_value->IsNull()); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } acc->Abort(); } // Check that property 5 is null. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); auto other_property = acc->NameToProperty("other"); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::NEW)->IsNull()); acc->Abort(); } // Set property 5 to "nandare". { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); { auto old_value = vertex->SetProperty(property, memgraph::storage::PropertyValue("temporary")); ASSERT_TRUE(old_value.HasValue()); ASSERT_TRUE(old_value->IsNull()); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "temporary"); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "temporary"); } { auto old_value = vertex->SetProperty(property, memgraph::storage::PropertyValue("nandare")); ASSERT_TRUE(old_value.HasValue()); ASSERT_FALSE(old_value->IsNull()); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_FALSE(acc->Commit().HasError()); } // Check that property 5 is "nandare". { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } auto other_property = acc->NameToProperty("other"); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::NEW)->IsNull()); acc->Abort(); } // Set property 5 to null, but abort the transaction. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } { auto old_value = vertex->SetProperty(property, memgraph::storage::PropertyValue()); ASSERT_TRUE(old_value.HasValue()); ASSERT_FALSE(old_value->IsNull()); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); acc->Abort(); } // Check that property 5 is "nandare". { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } auto other_property = acc->NameToProperty("other"); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::NEW)->IsNull()); acc->Abort(); } // Set property 5 to null. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } { auto old_value = vertex->SetProperty(property, memgraph::storage::PropertyValue()); ASSERT_TRUE(old_value.HasValue()); ASSERT_FALSE(old_value->IsNull()); } ASSERT_EQ(vertex->GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); ASSERT_FALSE(acc->Commit().HasError()); } // Check that property 5 is null. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property = acc->NameToProperty("property5"); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); auto other_property = acc->NameToProperty("other"); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(other_property, memgraph::storage::View::NEW)->IsNull()); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexPropertySerializationError) { memgraph::storage::Gid gid = memgraph::storage::Gid::FromUint(std::numeric_limits::max()); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(acc->Commit().HasError()); } auto acc1 = this->store->Access(ReplicationRole::MAIN); auto acc2 = this->store->Access(ReplicationRole::MAIN); // Set property 1 to 123 in accessor 1. { auto vertex = acc1->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property1 = acc1->NameToProperty("property1"); auto property2 = acc1->NameToProperty("property2"); ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::NEW)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); { auto old_value = vertex->SetProperty(property1, memgraph::storage::PropertyValue(123)); ASSERT_TRUE(old_value.HasValue()); ASSERT_TRUE(old_value->IsNull()); } ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::OLD)->IsNull()); ASSERT_EQ(vertex->GetProperty(property1, memgraph::storage::View::NEW)->ValueInt(), 123); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property1].ValueInt(), 123); } } // Set property 2 to "nandare" in accessor 2. { auto vertex = acc2->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property1 = acc2->NameToProperty("property1"); auto property2 = acc2->NameToProperty("property2"); ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::NEW)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW)->size(), 0); { auto res = vertex->SetProperty(property2, memgraph::storage::PropertyValue("nandare")); if (std::is_same::value) { // InMemoryStorage works with pessimistic transactions. ASSERT_TRUE(res.HasError()); ASSERT_EQ(res.GetError(), memgraph::storage::Error::SERIALIZATION_ERROR); } else { // Disk storage works with optimistic transactions. ASSERT_TRUE(res.HasValue()); ASSERT_TRUE(res->IsNull()); } } } // Finalize both accessors. ASSERT_FALSE(acc1->Commit().HasError()); if (std::is_same::value) { acc2->Abort(); } else { // Disk storage works with optimistic transactions. So on write conflict, transaction fails on commit. auto res = acc2->Commit(); ASSERT_TRUE(res.HasError()); ASSERT_EQ(std::get(res.GetError()), memgraph::storage::SerializationError()); } // Check which properties exist. { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto property1 = acc->NameToProperty("property1"); auto property2 = acc->NameToProperty("property2"); ASSERT_EQ(vertex->GetProperty(property1, memgraph::storage::View::OLD)->ValueInt(), 123); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::OLD)->IsNull()); { auto properties = vertex->Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property1].ValueInt(), 123); } ASSERT_EQ(vertex->GetProperty(property1, memgraph::storage::View::NEW)->ValueInt(), 123); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::NEW)->IsNull()); { auto properties = vertex->Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property1].ValueInt(), 123); } acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, VertexLabelPropertyMixed) { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); auto label = acc->NameToLabel("label5"); auto property = acc->NameToProperty("property5"); // Check whether label 5 and property 5 exist ASSERT_FALSE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex.Labels(memgraph::storage::View::NEW)->size(), 0); ASSERT_TRUE(vertex.GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 0); // Add label 5 ASSERT_TRUE(vertex.AddLabel(label).GetValue()); // Check whether label 5 and property 5 exist ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex.Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_TRUE(vertex.GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 0); // Advance command acc->AdvanceCommand(); // Check whether label 5 and property 5 exist ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex.Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } { auto labels = vertex.Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_TRUE(vertex.GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_TRUE(vertex.GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex.Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 0); // Set property 5 to "nandare" ASSERT_TRUE(vertex.SetProperty(property, memgraph::storage::PropertyValue("nandare"))->IsNull()); // Check whether label 5 and property 5 exist ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex.Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } { auto labels = vertex.Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_TRUE(vertex.GetProperty(property, memgraph::storage::View::OLD)->IsNull()); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); ASSERT_EQ(vertex.Properties(memgraph::storage::View::OLD)->size(), 0); { auto properties = vertex.Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } // Advance command acc->AdvanceCommand(); // Check whether label 5 and property 5 exist ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex.Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } { auto labels = vertex.Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "nandare"); { auto properties = vertex.Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } { auto properties = vertex.Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } // Set property 5 to "haihai" ASSERT_FALSE(vertex.SetProperty(property, memgraph::storage::PropertyValue("haihai"))->IsNull()); // Check whether label 5 and property 5 exist ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex.Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } { auto labels = vertex.Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "nandare"); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "haihai"); { auto properties = vertex.Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "nandare"); } { auto properties = vertex.Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "haihai"); } // Advance command acc->AdvanceCommand(); // Check whether label 5 and property 5 exist ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex.Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } { auto labels = vertex.Labels(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "haihai"); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "haihai"); { auto properties = vertex.Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "haihai"); } { auto properties = vertex.Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "haihai"); } // Remove label 5 ASSERT_TRUE(vertex.RemoveLabel(label).GetValue()); // Check whether label 5 and property 5 exist ASSERT_TRUE(vertex.HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); { auto labels = vertex.Labels(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(labels.size(), 1); ASSERT_EQ(labels[0], label); } ASSERT_EQ(vertex.Labels(memgraph::storage::View::NEW)->size(), 0); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "haihai"); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "haihai"); { auto properties = vertex.Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "haihai"); } { auto properties = vertex.Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "haihai"); } // Advance command acc->AdvanceCommand(); // Check whether label 5 and property 5 exist ASSERT_FALSE(vertex.HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex.Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex.Labels(memgraph::storage::View::NEW)->size(), 0); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "haihai"); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::NEW)->ValueString(), "haihai"); { auto properties = vertex.Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "haihai"); } { auto properties = vertex.Properties(memgraph::storage::View::NEW).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "haihai"); } // Set property 5 to null ASSERT_FALSE(vertex.SetProperty(property, memgraph::storage::PropertyValue())->IsNull()); // Check whether label 5 and property 5 exist ASSERT_FALSE(vertex.HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex.Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex.Labels(memgraph::storage::View::NEW)->size(), 0); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::OLD)->ValueString(), "haihai"); ASSERT_TRUE(vertex.GetProperty(property, memgraph::storage::View::NEW)->IsNull()); { auto properties = vertex.Properties(memgraph::storage::View::OLD).GetValue(); ASSERT_EQ(properties.size(), 1); ASSERT_EQ(properties[property].ValueString(), "haihai"); } ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 0); // Advance command acc->AdvanceCommand(); // Check whether label 5 and property 5 exist ASSERT_FALSE(vertex.HasLabel(label, memgraph::storage::View::OLD).GetValue()); ASSERT_FALSE(vertex.HasLabel(label, memgraph::storage::View::NEW).GetValue()); ASSERT_EQ(vertex.Labels(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex.Labels(memgraph::storage::View::NEW)->size(), 0); ASSERT_TRUE(vertex.GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_TRUE(vertex.GetProperty(property, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex.Properties(memgraph::storage::View::OLD)->size(), 0); ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 0); ASSERT_FALSE(acc->Commit().HasError()); } TYPED_TEST(StorageV2Test, VertexPropertyClear) { memgraph::storage::Gid gid; auto property1 = this->store->NameToProperty("property1"); auto property2 = this->store->NameToProperty("property2"); { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); auto old_value = vertex.SetProperty(property1, memgraph::storage::PropertyValue("value")); ASSERT_TRUE(old_value.HasValue()); ASSERT_TRUE(old_value->IsNull()); ASSERT_FALSE(acc->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); ASSERT_EQ(vertex->GetProperty(property1, memgraph::storage::View::OLD)->ValueString(), "value"); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::OLD)->IsNull()); ASSERT_THAT(vertex->Properties(memgraph::storage::View::OLD).GetValue(), UnorderedElementsAre(std::pair(property1, memgraph::storage::PropertyValue("value")))); { auto old_values = vertex->ClearProperties(); ASSERT_TRUE(old_values.HasValue()); ASSERT_FALSE(old_values->empty()); } ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::NEW)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW).GetValue().size(), 0); { auto old_values = vertex->ClearProperties(); ASSERT_TRUE(old_values.HasValue()); ASSERT_TRUE(old_values->empty()); } ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::NEW)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW).GetValue().size(), 0); acc->Abort(); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto old_value = vertex->SetProperty(property2, memgraph::storage::PropertyValue(42)); ASSERT_TRUE(old_value.HasValue()); ASSERT_TRUE(old_value->IsNull()); ASSERT_FALSE(acc->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); ASSERT_EQ(vertex->GetProperty(property1, memgraph::storage::View::OLD)->ValueString(), "value"); ASSERT_EQ(vertex->GetProperty(property2, memgraph::storage::View::OLD)->ValueInt(), 42); ASSERT_THAT(vertex->Properties(memgraph::storage::View::OLD).GetValue(), UnorderedElementsAre(std::pair(property1, memgraph::storage::PropertyValue("value")), std::pair(property2, memgraph::storage::PropertyValue(42)))); { auto old_values = vertex->ClearProperties(); ASSERT_TRUE(old_values.HasValue()); ASSERT_FALSE(old_values->empty()); } ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::NEW)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW).GetValue().size(), 0); { auto old_values = vertex->ClearProperties(); ASSERT_TRUE(old_values.HasValue()); ASSERT_TRUE(old_values->empty()); } ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::NEW)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW).GetValue().size(), 0); ASSERT_FALSE(acc->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); ASSERT_TRUE(vertex->GetProperty(property1, memgraph::storage::View::NEW)->IsNull()); ASSERT_TRUE(vertex->GetProperty(property2, memgraph::storage::View::NEW)->IsNull()); ASSERT_EQ(vertex->Properties(memgraph::storage::View::NEW).GetValue().size(), 0); acc->Abort(); } } TYPED_TEST(StorageV2Test, VertexNonexistentLabelPropertyEdgeAPI) { auto label = this->store->NameToLabel("label"); auto property = this->store->NameToProperty("property"); auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); // Check state before (OLD view). ASSERT_EQ(vertex.Labels(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.HasLabel(label, memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.Properties(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.InEdges(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.OutEdges(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.InDegree(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.OutDegree(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); // Check state before (NEW view). ASSERT_EQ(vertex.Labels(memgraph::storage::View::NEW)->size(), 0); ASSERT_EQ(*vertex.HasLabel(label, memgraph::storage::View::NEW), false); ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 0); ASSERT_EQ(*vertex.GetProperty(property, memgraph::storage::View::NEW), memgraph::storage::PropertyValue()); ASSERT_EQ(vertex.InEdges(memgraph::storage::View::NEW)->edges.size(), 0); ASSERT_EQ(vertex.OutEdges(memgraph::storage::View::NEW)->edges.size(), 0); ASSERT_EQ(*vertex.InDegree(memgraph::storage::View::NEW), 0); ASSERT_EQ(*vertex.OutDegree(memgraph::storage::View::NEW), 0); // Modify vertex. ASSERT_TRUE(vertex.AddLabel(label).HasValue()); ASSERT_TRUE(vertex.SetProperty(property, memgraph::storage::PropertyValue("value")).HasValue()); ASSERT_TRUE(acc->CreateEdge(&vertex, &vertex, acc->NameToEdgeType("edge")).HasValue()); // Check state after (OLD view). ASSERT_EQ(vertex.Labels(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.HasLabel(label, memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.Properties(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.GetProperty(property, memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.InEdges(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.OutEdges(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.InDegree(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); ASSERT_EQ(vertex.OutDegree(memgraph::storage::View::OLD).GetError(), memgraph::storage::Error::NONEXISTENT_OBJECT); // Check state after (NEW view). ASSERT_EQ(vertex.Labels(memgraph::storage::View::NEW)->size(), 1); ASSERT_EQ(*vertex.HasLabel(label, memgraph::storage::View::NEW), true); ASSERT_EQ(vertex.Properties(memgraph::storage::View::NEW)->size(), 1); ASSERT_EQ(*vertex.GetProperty(property, memgraph::storage::View::NEW), memgraph::storage::PropertyValue("value")); ASSERT_EQ(vertex.InEdges(memgraph::storage::View::NEW)->edges.size(), 1); ASSERT_EQ(vertex.OutEdges(memgraph::storage::View::NEW)->edges.size(), 1); ASSERT_EQ(*vertex.InDegree(memgraph::storage::View::NEW), 1); ASSERT_EQ(*vertex.OutDegree(memgraph::storage::View::NEW), 1); ASSERT_FALSE(acc->Commit().HasError()); } TYPED_TEST(StorageV2Test, VertexVisibilitySingleTransaction) { auto acc1 = this->store->Access(ReplicationRole::MAIN); auto acc2 = this->store->Access(ReplicationRole::MAIN); auto vertex = acc1->CreateVertex(); auto gid = vertex.Gid(); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); ASSERT_TRUE(vertex.AddLabel(acc1->NameToLabel("label")).HasValue()); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); ASSERT_TRUE(vertex.SetProperty(acc1->NameToProperty("meaning"), memgraph::storage::PropertyValue(42)).HasValue()); auto acc3 = this->store->Access(ReplicationRole::MAIN); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); ASSERT_TRUE(acc1->DeleteVertex(&vertex).HasValue()); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc1->AdvanceCommand(); acc3->AdvanceCommand(); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc1->Abort(); acc2->Abort(); acc3->Abort(); } TYPED_TEST(StorageV2Test, VertexVisibilityMultipleTransactions) { memgraph::storage::Gid gid; { auto acc1 = this->store->Access(ReplicationRole::MAIN); auto acc2 = this->store->Access(ReplicationRole::MAIN); auto vertex = acc1->CreateVertex(); gid = vertex.Gid(); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); acc2->AdvanceCommand(); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); acc1->AdvanceCommand(); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); ASSERT_FALSE(acc1->Commit().HasError()); ASSERT_FALSE(acc2->Commit().HasError()); } { auto acc1 = this->store->Access(ReplicationRole::MAIN); auto acc2 = this->store->Access(ReplicationRole::MAIN); auto vertex = acc1->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); ASSERT_TRUE(vertex->AddLabel(acc1->NameToLabel("label")).HasValue()); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); acc1->AdvanceCommand(); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); acc2->AdvanceCommand(); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); ASSERT_TRUE(vertex->SetProperty(acc1->NameToProperty("meaning"), memgraph::storage::PropertyValue(42)).HasValue()); auto acc3 = this->store->Access(ReplicationRole::MAIN); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc1->AdvanceCommand(); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc2->AdvanceCommand(); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc3->AdvanceCommand(); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); ASSERT_FALSE(acc1->Commit().HasError()); ASSERT_FALSE(acc2->Commit().HasError()); ASSERT_FALSE(acc3->Commit().HasError()); } { auto acc1 = this->store->Access(ReplicationRole::MAIN); auto acc2 = this->store->Access(ReplicationRole::MAIN); auto vertex = acc1->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); ASSERT_TRUE(acc1->DeleteVertex(&*vertex).HasValue()); auto acc3 = this->store->Access(ReplicationRole::MAIN); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc2->AdvanceCommand(); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc1->AdvanceCommand(); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc3->AdvanceCommand(); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc1->Abort(); acc2->Abort(); acc3->Abort(); } { auto acc = this->store->Access(ReplicationRole::MAIN); EXPECT_TRUE(acc->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc->FindVertex(gid, memgraph::storage::View::NEW)); acc->AdvanceCommand(); EXPECT_TRUE(acc->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc->FindVertex(gid, memgraph::storage::View::NEW)); acc->Abort(); } { auto acc1 = this->store->Access(ReplicationRole::MAIN); auto acc2 = this->store->Access(ReplicationRole::MAIN); auto vertex = acc1->FindVertex(gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); ASSERT_TRUE(acc1->DeleteVertex(&*vertex).HasValue()); auto acc3 = this->store->Access(ReplicationRole::MAIN); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc2->AdvanceCommand(); EXPECT_TRUE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc1->AdvanceCommand(); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); acc3->AdvanceCommand(); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc1->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc2->FindVertex(gid, memgraph::storage::View::NEW)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_TRUE(acc3->FindVertex(gid, memgraph::storage::View::NEW)); ASSERT_FALSE(acc1->Commit().HasError()); ASSERT_FALSE(acc2->Commit().HasError()); ASSERT_FALSE(acc3->Commit().HasError()); } { auto acc = this->store->Access(ReplicationRole::MAIN); EXPECT_FALSE(acc->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc->FindVertex(gid, memgraph::storage::View::NEW)); acc->AdvanceCommand(); EXPECT_FALSE(acc->FindVertex(gid, memgraph::storage::View::OLD)); EXPECT_FALSE(acc->FindVertex(gid, memgraph::storage::View::NEW)); acc->Abort(); } } // NOLINTNEXTLINE(hicpp-special-member-functions) TYPED_TEST(StorageV2Test, DeletedVertexAccessor) { const auto property = this->store->NameToProperty("property"); const memgraph::storage::PropertyValue property_value{"property_value"}; std::optional gid; // Create the vertex { auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); gid = vertex.Gid(); ASSERT_FALSE(vertex.SetProperty(property, property_value).HasError()); ASSERT_FALSE(acc->Commit().HasError()); } auto acc = this->store->Access(ReplicationRole::MAIN); auto vertex = acc->FindVertex(*gid, memgraph::storage::View::OLD); ASSERT_TRUE(vertex); auto maybe_deleted_vertex = acc->DeleteVertex(&*vertex); ASSERT_FALSE(maybe_deleted_vertex.HasError()); auto deleted_vertex = maybe_deleted_vertex.GetValue(); ASSERT_TRUE(deleted_vertex); // you cannot modify deleted vertex ASSERT_TRUE(deleted_vertex->ClearProperties().HasError()); // you can call read only methods const auto maybe_property = deleted_vertex->GetProperty(property, memgraph::storage::View::OLD); ASSERT_FALSE(maybe_property.HasError()); ASSERT_EQ(property_value, *maybe_property); ASSERT_FALSE(acc->Commit().HasError()); { // you can call read only methods and get valid results even after the // transaction which deleted the vertex committed, but only if the transaction // accessor is still alive const auto maybe_property = deleted_vertex->GetProperty(property, memgraph::storage::View::OLD); ASSERT_FALSE(maybe_property.HasError()); ASSERT_EQ(property_value, *maybe_property); } }