// 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 #include #include "disk_test_utils.hpp" #include "query/common.hpp" #include "query/db_accessor.hpp" #include "storage/v2/delta.hpp" #include "storage/v2/disk/storage.hpp" #include "storage/v2/id_types.hpp" #include "storage/v2/isolation_level.hpp" #include "storage/v2/property_store.hpp" #include "storage/v2/property_value.hpp" #include "storage/v2/storage.hpp" #include "storage/v2/vertex_accessor.hpp" #include "storage/v2/view.hpp" #include "utils/rocksdb_serialization.hpp" using memgraph::replication_coordination_glue::ReplicationRole; // NOLINTNEXTLINE(google-build-using-namespace) using namespace memgraph::storage; /* Tests that serialization of vertices and edges to RocksDB works correctly. */ class RocksDBStorageTest : public ::testing::TestWithParam { public: const std::string testSuite = "storage_rocks"; RocksDBStorageTest() { config_ = disk_test_utils::GenerateOnDiskConfig(testSuite); storage = std::make_unique(config_); } void TearDown() override { storage.reset(nullptr); disk_test_utils::RemoveRocksDbDirs(testSuite); } ~RocksDBStorageTest() override = default; protected: std::unique_ptr storage; Config config_; }; TEST_F(RocksDBStorageTest, SerializeVertexGID) { auto acc = storage->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); auto gid = vertex.Gid(); ASSERT_EQ(memgraph::utils::SerializeVertex(*vertex.vertex_), "|" + gid.ToString()); } TEST_F(RocksDBStorageTest, SerializeVertexGIDLabels) { auto acc = storage->Access(ReplicationRole::MAIN); auto vertex = acc->CreateVertex(); auto ser_player_label = acc->NameToLabel("Player"); auto ser_user_label = acc->NameToLabel("User"); ASSERT_FALSE(vertex.AddLabel(ser_player_label).HasError()); ASSERT_FALSE(vertex.AddLabel(ser_user_label).HasError()); auto gid = vertex.Gid(); ASSERT_EQ(memgraph::utils::SerializeVertex(*vertex.vertex_), ser_player_label.ToString() + "," + ser_user_label.ToString() + "|" + gid.ToString()); } TEST_F(RocksDBStorageTest, SerializePropertiesLocalBuffer) { PropertyStore props; auto id = PropertyId::FromInt(0); auto id_value = PropertyValue(1); auto completion_percentage = PropertyId::FromInt(1); auto completion_percentage_value = PropertyValue(14); auto gender = PropertyId::FromInt(2); auto gender_value = PropertyValue("man"); auto age = PropertyId::FromInt(3); auto age_value = PropertyValue(26); ASSERT_TRUE(props.SetProperty(id, id_value)); ASSERT_TRUE(props.SetProperty(age, age_value)); ASSERT_TRUE(props.SetProperty(completion_percentage, completion_percentage_value)); ASSERT_TRUE(props.SetProperty(gender, gender_value)); std::string serialized_props = memgraph::utils::SerializeProperties(props); PropertyStore deserialized_props = PropertyStore::CreateFromBuffer(serialized_props); for (const auto &[prop_id, prop_value] : props.Properties()) { ASSERT_TRUE(deserialized_props.IsPropertyEqual(prop_id, prop_value)); } } TEST_F(RocksDBStorageTest, SerializePropertiesExternalBuffer) { PropertyStore props; auto id = PropertyId::FromInt(0); auto id_value = PropertyValue(1); auto completion_percentage = PropertyId::FromInt(1); auto completion_percentage_value = PropertyValue(14); auto gender = PropertyId::FromInt(2); // Use big value so that memory for properties is allocated on the heap not on the stack auto gender_value = PropertyValue("man167863816386826"); auto age = PropertyId::FromInt(3); auto age_value = PropertyValue(26); ASSERT_TRUE(props.SetProperty(id, id_value)); ASSERT_TRUE(props.SetProperty(age, age_value)); ASSERT_TRUE(props.SetProperty(completion_percentage, completion_percentage_value)); ASSERT_TRUE(props.SetProperty(gender, gender_value)); std::string serialized_props = memgraph::utils::SerializeProperties(props); PropertyStore deserialized_props = PropertyStore::CreateFromBuffer(serialized_props); for (const auto &[prop_id, prop_value] : props.Properties()) { ASSERT_TRUE(deserialized_props.IsPropertyEqual(prop_id, prop_value)); } } TEST(RocksDbSerDeSuite, ExtractVertexGidFromVertexKeyNoLabels) { auto gid = Gid::FromInt(1); Vertex vertex(gid, nullptr); std::string serializedVertex = memgraph::utils::SerializeVertex(vertex); ASSERT_EQ(memgraph::utils::ExtractGidFromKey(serializedVertex), "1"); } TEST(RocksDbSerDeSuite, ExtractVertexGidFromVertexKeyWithOneLabel) { auto gid = Gid::FromInt(1); Vertex vertex(gid, nullptr); vertex.labels.push_back(LabelId::FromInt(2)); std::string serializedVertex = memgraph::utils::SerializeVertex(vertex); ASSERT_EQ(memgraph::utils::ExtractGidFromKey(serializedVertex), "1"); } TEST(RocksDbSerDeSuite, ExtractVertexGidFromVertexKeyWithMultipleLabels) { auto gid = Gid::FromInt(1); Vertex vertex(gid, nullptr); std::vector labels = {2, 3, 4}; for (unsigned label : labels) { vertex.labels.push_back(LabelId::FromInt(label)); } std::string serializedVertex = memgraph::utils::SerializeVertex(vertex); ASSERT_EQ(memgraph::utils::ExtractGidFromKey(serializedVertex), "1"); } TEST(RocksDbSerDeSuite, ExtractLabelsFromMainDiskStorageWhenOnlyOneLabel) { auto gid = Gid::FromInt(1); Vertex vertex(gid, nullptr); std::vector labels = {2}; std::vector expectedLabelsStr = {"2"}; for (unsigned label : labels) { vertex.labels.push_back(LabelId::FromInt(label)); } std::string serializedVertex = memgraph::utils::SerializeVertex(vertex); ASSERT_EQ(memgraph::utils::ExtractLabelsFromMainDiskStorage(serializedVertex), expectedLabelsStr); } TEST(RocksDbSerDeSuite, ExtractLabelsFromMainDiskStorageWhenMultipleLabels) { auto gid = Gid::FromInt(1); Vertex vertex(gid, nullptr); std::vector labels = {2, 3, 4}; std::vector expectedLabelsStr = {"2", "3", "4"}; for (unsigned label : labels) { vertex.labels.push_back(LabelId::FromInt(label)); } std::string serializedVertex = memgraph::utils::SerializeVertex(vertex); ASSERT_EQ(memgraph::utils::ExtractLabelsFromMainDiskStorage(serializedVertex), expectedLabelsStr); } TEST(RocksDbSerDeSuite, ExtractVertexGidFromMainDiskStorageNoLabels) { auto gid = Gid::FromInt(1); Vertex vertex(gid, nullptr); std::string serializedVertex = memgraph::utils::SerializeVertex(vertex); ASSERT_EQ(memgraph::utils::ExtractGidFromMainDiskStorage(serializedVertex), "1"); } TEST(RocksDbSerDeSuite, ExtractVertexGidFromMainDiskStorageWithOneLabel) { auto gid = Gid::FromInt(1); Vertex vertex(gid, nullptr); vertex.labels.push_back(LabelId::FromInt(2)); std::string serializedVertex = memgraph::utils::SerializeVertex(vertex); ASSERT_EQ(memgraph::utils::ExtractGidFromMainDiskStorage(serializedVertex), "1"); } TEST(RocksDbSerDeSuite, ExtractVertexGidFromMainDiskStorageWithMultipleLabels) { auto gid = Gid::FromInt(1); Vertex vertex(gid, nullptr); vertex.labels.push_back(LabelId::FromInt(2)); vertex.labels.push_back(LabelId::FromInt(3)); vertex.labels.push_back(LabelId::FromInt(4)); std::string serializedVertex = memgraph::utils::SerializeVertex(vertex); ASSERT_EQ(memgraph::utils::ExtractGidFromLabelIndexStorage(serializedVertex), "1"); } TEST(RocksDbSerDeSuite, ExtractGidFromLabelIndexStorageKey) { auto gid = Gid::FromInt(1); LabelId label = LabelId::FromInt(2); std::string serializedVertex = memgraph::utils::SerializeVertexAsKeyForLabelIndex(label, gid); ASSERT_EQ(memgraph::utils::ExtractGidFromLabelIndexStorage(serializedVertex), "1"); } TEST(RocksDbSerDeSuite, DeserializePropertiesFromLabelIndexStorage) { std::string expectedGid = "1"; LabelId indexingLabel = LabelId::FromInt(2); std::vector labels = {LabelId::FromInt(3), LabelId::FromInt(4)}; std::map properties = {{PropertyId::FromInt(5), PropertyValue("5")}, {PropertyId::FromInt(6), PropertyValue("6")}}; PropertyStore propertyStore; propertyStore.InitProperties(properties); std::string serializedVertex = memgraph::utils::SerializeVertexAsValueForLabelIndex(indexingLabel, labels, propertyStore); ASSERT_EQ(memgraph::utils::DeserializePropertiesFromLabelIndexStorage(serializedVertex).StringBuffer(), propertyStore.StringBuffer()); } TEST(RocksDbSerDeSuite, DeserializePropertiesFromLabelPropertyIndexStorage) { std::string expectedGid = "1"; LabelId indexingLabel = LabelId::FromInt(2); std::vector labels = {LabelId::FromInt(3), LabelId::FromInt(4)}; std::map properties = {{PropertyId::FromInt(5), PropertyValue("5")}, {PropertyId::FromInt(6), PropertyValue("6")}}; PropertyStore propertyStore; propertyStore.InitProperties(properties); std::string serializedVertex = memgraph::utils::SerializeVertexAsValueForLabelPropertyIndex(indexingLabel, labels, propertyStore); ASSERT_EQ(memgraph::utils::DeserializePropertiesFromLabelPropertyIndexStorage(serializedVertex).StringBuffer(), propertyStore.StringBuffer()); } TEST(RocksDbSerDeSuite, ExtractGidFromLabelPropertyIndexStorageKey) { auto gid = Gid::FromInt(1); LabelId label = LabelId::FromInt(2); PropertyId property = PropertyId::FromInt(3); std::string serializedVertex = memgraph::utils::SerializeVertexAsKeyForLabelPropertyIndex(label, property, gid); ASSERT_EQ(memgraph::utils::ExtractGidFromLabelPropertyIndexStorage(serializedVertex), "1"); } TEST(RocksDbSerDeSuite, ExtractGidFromUniqueConstraintStorageKey) { std::string expectedGid = "1"; LabelId constraintLabel = LabelId::FromInt(2); std::set properties = {PropertyId::FromInt(3), PropertyId::FromInt(4)}; std::string serializedVertex = memgraph::utils::SerializeVertexAsKeyForUniqueConstraint(constraintLabel, properties, expectedGid); ASSERT_EQ(memgraph::utils::ExtractGidFromUniqueConstraintStorage(serializedVertex), expectedGid); } TEST(RocksDbSerDeSuite, DeserializeConstraintLabelFromUniqueConstraintStorage) { std::string expectedGid = "1"; LabelId constraintLabel = LabelId::FromInt(2); std::set properties = {PropertyId::FromInt(3), PropertyId::FromInt(4)}; std::string serializedVertex = memgraph::utils::SerializeVertexAsKeyForUniqueConstraint(constraintLabel, properties, expectedGid); ASSERT_EQ(memgraph::utils::DeserializeConstraintLabelFromUniqueConstraintStorage(serializedVertex), constraintLabel); } TEST(RocksDbSerDeSuite, DeserializePropertiesFromUniqueConstraintStorage) { std::string expectedGid = "1"; LabelId constraintLabel = LabelId::FromInt(2); std::vector labels = {LabelId::FromInt(3), LabelId::FromInt(4)}; std::map properties = {{PropertyId::FromInt(5), PropertyValue("5")}, {PropertyId::FromInt(6), PropertyValue("6")}}; PropertyStore propertyStore; propertyStore.InitProperties(properties); std::string serializedVertex = memgraph::utils::SerializeVertexAsValueForUniqueConstraint(constraintLabel, labels, propertyStore); ASSERT_EQ(memgraph::utils::DeserializePropertiesFromUniqueConstraintStorage(serializedVertex).StringBuffer(), propertyStore.StringBuffer()); }