memgraph/tests/unit/storage_v3_vertex_accessors.cpp
2022-11-15 19:29:56 +01:00

214 lines
9.0 KiB
C++

// Copyright 2022 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 <limits>
#include <optional>
#include <variant>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "common/types.hpp"
#include "storage/v3/delta.hpp"
#include "storage/v3/id_types.hpp"
#include "storage/v3/property_value.hpp"
#include "storage/v3/result.hpp"
#include "storage/v3/schema_validator.hpp"
#include "storage/v3/shard.hpp"
#include "storage/v3/vertex_accessor.hpp"
#include "storage_v3_test_utils.hpp"
using testing::UnorderedElementsAre;
namespace memgraph::storage::v3::tests {
class StorageV3Accessor : public ::testing::Test {
protected:
void SetUp() override { storage.StoreMapping({{1, "label"}, {2, "property"}}); }
static VertexAccessor CreateVertexAndValidate(Shard::Accessor &acc, const std::vector<LabelId> &labels,
const PropertyValue &primary_key) {
auto vtx = acc.CreateVertexAndValidate(labels, {primary_key}, {});
EXPECT_TRUE(vtx.HasValue());
return *vtx;
}
LabelId NameToLabelId(std::string_view label_name) { return storage.NameToLabel(label_name); }
PropertyId NameToPropertyId(std::string_view property_name) { return storage.NameToProperty(property_name); }
coordinator::Hlc GetNextHlc() {
++last_hlc.logical_id;
last_hlc.coordinator_wall_clock += std::chrono::seconds(10);
return last_hlc;
}
const std::vector<PropertyValue> min_pk{PropertyValue{0}};
const LabelId primary_label{LabelId::FromUint(1)};
const PropertyId primary_property{PropertyId::FromUint(2)};
std::vector<storage::v3::SchemaProperty> schema_property_vector = {
storage::v3::SchemaProperty{primary_property, common::SchemaType::INT}};
Shard storage{primary_label, min_pk, std::nullopt /*max_primary_key*/, schema_property_vector};
coordinator::Hlc last_hlc{0, io::Time{}};
};
TEST_F(StorageV3Accessor, TestPrimaryLabel) {
{
auto acc = storage.Access(GetNextHlc());
const auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{0});
ASSERT_TRUE(vertex.PrimaryLabel(View::NEW).HasValue());
const auto vertex_primary_label = vertex.PrimaryLabel(View::NEW).GetValue();
ASSERT_FALSE(vertex.PrimaryLabel(View::OLD).HasValue());
EXPECT_EQ(vertex_primary_label, primary_label);
}
{
auto acc = storage.Access(GetNextHlc());
const auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{1});
ASSERT_TRUE(vertex.PrimaryLabel(View::OLD).HasError());
const auto error_primary_label = vertex.PrimaryLabel(View::OLD).GetError();
ASSERT_FALSE(vertex.PrimaryLabel(View::NEW).HasError());
EXPECT_EQ(error_primary_label, SHARD_ERROR(ErrorCode::NONEXISTENT_OBJECT));
}
{
auto acc = storage.Access(GetNextHlc());
CreateVertexAndValidate(acc, {}, PropertyValue{2});
acc.Commit(GetNextHlc());
}
{
auto acc = storage.Access(GetNextHlc());
const auto vertex = acc.FindVertex({PropertyValue{2}}, View::OLD);
ASSERT_TRUE(vertex.has_value());
ASSERT_TRUE(acc.FindVertex({PropertyValue{2}}, View::NEW).has_value());
ASSERT_TRUE(vertex->PrimaryLabel(View::NEW).HasValue());
ASSERT_TRUE(vertex->PrimaryLabel(View::OLD).HasValue());
const auto vertex_primary_label = vertex->PrimaryLabel(View::NEW).GetValue();
EXPECT_EQ(vertex_primary_label, primary_label);
}
}
TEST_F(StorageV3Accessor, TestAddLabels) {
storage.StoreMapping({{1, "label"}, {2, "property"}, {3, "label1"}, {4, "label2"}, {5, "label3"}});
{
auto acc = storage.Access(GetNextHlc());
const auto label1 = NameToLabelId("label1");
const auto label2 = NameToLabelId("label2");
const auto label3 = NameToLabelId("label3");
const auto vertex = CreateVertexAndValidate(acc, {label1, label2, label3}, PropertyValue{0});
ASSERT_TRUE(vertex.Labels(View::NEW).HasValue());
ASSERT_FALSE(vertex.Labels(View::OLD).HasValue());
EXPECT_THAT(vertex.Labels(View::NEW).GetValue(), UnorderedElementsAre(label1, label2, label3));
}
{
auto acc = storage.Access(GetNextHlc());
const auto label1 = NameToLabelId("label1");
const auto label2 = NameToLabelId("label2");
const auto label3 = NameToLabelId("label3");
auto vertex = CreateVertexAndValidate(acc, {label1}, PropertyValue{1});
ASSERT_TRUE(vertex.Labels(View::NEW).HasValue());
ASSERT_FALSE(vertex.Labels(View::OLD).HasValue());
EXPECT_THAT(vertex.Labels(View::NEW).GetValue(), UnorderedElementsAre(label1));
EXPECT_TRUE(vertex.AddLabelAndValidate(label2).HasValue());
EXPECT_TRUE(vertex.AddLabelAndValidate(label3).HasValue());
ASSERT_TRUE(vertex.Labels(View::NEW).HasValue());
ASSERT_FALSE(vertex.Labels(View::OLD).HasValue());
EXPECT_THAT(vertex.Labels(View::NEW).GetValue(), UnorderedElementsAre(label1, label2, label3));
}
{
auto acc = storage.Access(GetNextHlc());
const auto label1 = NameToLabelId("label");
auto vertex = acc.CreateVertexAndValidate({label1}, {PropertyValue{2}}, {});
ASSERT_TRUE(vertex.HasError());
EXPECT_EQ(vertex.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY));
}
{
auto acc = storage.Access(GetNextHlc());
const auto label1 = NameToLabelId("label");
auto vertex = acc.CreateVertexAndValidate({}, {PropertyValue{3}}, {});
ASSERT_TRUE(vertex.HasValue());
const auto schema_violation = vertex->AddLabelAndValidate(label1);
ASSERT_TRUE(schema_violation.HasError());
EXPECT_EQ(schema_violation.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL));
}
}
TEST_F(StorageV3Accessor, TestRemoveLabels) {
storage.StoreMapping({{1, "label"}, {2, "property"}, {3, "label1"}, {4, "label2"}, {5, "label3"}});
{
auto acc = storage.Access(GetNextHlc());
const auto label1 = NameToLabelId("label1");
const auto label2 = NameToLabelId("label2");
const auto label3 = NameToLabelId("label3");
auto vertex = CreateVertexAndValidate(acc, {label1, label2, label3}, PropertyValue{0});
ASSERT_TRUE(vertex.Labels(View::NEW).HasValue());
EXPECT_THAT(vertex.Labels(View::NEW).GetValue(), UnorderedElementsAre(label1, label2, label3));
const auto res1 = vertex.RemoveLabelAndValidate(label2);
ASSERT_TRUE(res1.HasValue());
EXPECT_TRUE(res1.GetValue());
EXPECT_THAT(vertex.Labels(View::NEW).GetValue(), UnorderedElementsAre(label1, label3));
const auto res2 = vertex.RemoveLabelAndValidate(label1);
ASSERT_TRUE(res2.HasValue());
EXPECT_TRUE(res2.GetValue());
EXPECT_THAT(vertex.Labels(View::NEW).GetValue(), UnorderedElementsAre(label3));
const auto res3 = vertex.RemoveLabelAndValidate(label3);
ASSERT_TRUE(res3.HasValue());
ASSERT_TRUE(res3.HasValue());
EXPECT_TRUE(res3.GetValue());
EXPECT_TRUE(vertex.Labels(View::NEW).GetValue().empty());
}
{
auto acc = storage.Access(GetNextHlc());
const auto label1 = NameToLabelId("label1");
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{1});
ASSERT_TRUE(vertex.Labels(View::NEW).HasValue());
EXPECT_TRUE(vertex.Labels(View::NEW).GetValue().empty());
const auto res1 = vertex.RemoveLabelAndValidate(label1);
ASSERT_TRUE(res1.HasValue());
EXPECT_FALSE(res1.GetValue());
}
{
auto acc = storage.Access(GetNextHlc());
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{2});
const auto res1 = vertex.RemoveLabelAndValidate(primary_label);
ASSERT_TRUE(res1.HasError());
EXPECT_EQ(res1.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL));
}
}
TEST_F(StorageV3Accessor, TestSetKeysAndProperties) {
storage.StoreMapping({{1, "label"}, {2, "property"}, {3, "prop1"}});
storage.StoreMapping({{1, "label"}, {2, "property"}, {3, "prop1"}});
{
auto acc = storage.Access(GetNextHlc());
const PropertyId prop1{NameToPropertyId("prop1")};
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{0});
const auto res = vertex.SetPropertyAndValidate(prop1, PropertyValue(1));
ASSERT_TRUE(res.HasValue());
}
{
auto acc = storage.Access(GetNextHlc());
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{1});
const auto res = vertex.SetPropertyAndValidate(primary_property, PropertyValue(1));
ASSERT_TRUE(res.HasError());
EXPECT_EQ(res.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY));
}
{
auto acc = storage.Access(GetNextHlc());
auto vertex = CreateVertexAndValidate(acc, {}, PropertyValue{2});
const auto res = vertex.SetPropertyAndValidate(primary_property, PropertyValue());
ASSERT_TRUE(res.HasError());
EXPECT_EQ(res.GetError(), SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY));
}
}
} // namespace memgraph::storage::v3::tests