blob: 410a681ddae2a0a2eaf9a6f4c6a69ba4b6225a4d [file] [log] [blame]
// Copyright (C) 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "icing/schema/schema-store.h"
#include <memory>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "icing/absl_ports/str_cat.h"
#include "icing/file/filesystem.h"
#include "icing/portable/equals-proto.h"
#include "icing/proto/document.pb.h"
#include "icing/proto/schema.pb.h"
#include "icing/schema/schema-util.h"
#include "icing/schema/section-manager.h"
#include "icing/schema/section.h"
#include "icing/store/document-filter-data.h"
#include "icing/testing/common-matchers.h"
#include "icing/testing/tmp-directory.h"
namespace icing {
namespace lib {
namespace {
using ::icing::lib::portable_equals_proto::EqualsProto;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Not;
using ::testing::Pointee;
class SchemaStoreTest : public ::testing::Test {
protected:
SchemaStoreTest() : test_dir_(GetTestTempDir() + "/icing") {
filesystem_.CreateDirectoryRecursively(test_dir_.c_str());
auto type = schema_.add_types();
type->set_schema_type("email");
// Add an indexed property so we generate section metadata on it
auto property = type->add_properties();
property->set_property_name("subject");
property->set_data_type(PropertyConfigProto::DataType::STRING);
property->set_cardinality(PropertyConfigProto::Cardinality::OPTIONAL);
property->mutable_indexing_config()->set_term_match_type(
TermMatchType::EXACT_ONLY);
property->mutable_indexing_config()->set_tokenizer_type(
IndexingConfig::TokenizerType::PLAIN);
}
void TearDown() override {
filesystem_.DeleteDirectoryRecursively(test_dir_.c_str());
}
const Filesystem filesystem_;
const std::string test_dir_;
SchemaProto schema_;
};
TEST_F(SchemaStoreTest, CorruptSchemaError) {
{
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema_));
}
// "Corrupt" the ground truth schema by adding new data to it. This will mess
// up the checksum of the schema store
SchemaProto corrupt_schema;
auto type = corrupt_schema.add_types();
type->set_schema_type("corrupted");
const std::string schema_file = absl_ports::StrCat(test_dir_, "/schema.pb");
const std::string serialized_schema = corrupt_schema.SerializeAsString();
filesystem_.Write(schema_file.c_str(), serialized_schema.data(),
serialized_schema.size());
// If ground truth was corrupted, we won't know what to do
EXPECT_THAT(SchemaStore::Create(&filesystem_, test_dir_),
StatusIs(libtextclassifier3::StatusCode::INTERNAL));
}
TEST_F(SchemaStoreTest, RecoverCorruptDerivedFileOk) {
{
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema_));
EXPECT_THAT(schema_store->GetSchemaTypeId("email"), IsOkAndHolds(0));
}
// "Corrupt" the derived SchemaTypeIds by deleting the entire directory. This
// will mess up the initialization of schema store, causing everything to be
// regenerated from ground truth
const std::string schema_type_mapper_dir =
absl_ports::StrCat(test_dir_, "/schema_type_mapper");
filesystem_.DeleteDirectoryRecursively(schema_type_mapper_dir.c_str());
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Everything looks fine, ground truth and derived data
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema_));
EXPECT_THAT(schema_store->GetSchemaTypeId("email"), IsOkAndHolds(0));
}
TEST_F(SchemaStoreTest, RecoverBadChecksumOk) {
{
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema_));
EXPECT_THAT(schema_store->GetSchemaTypeId("email"), IsOkAndHolds(0));
}
// Change the SchemaStore's header combined checksum so that it won't match
// the recalculated checksum on initialization. This will force a regeneration
// of derived files from ground truth.
const std::string header_file =
absl_ports::StrCat(test_dir_, "/schema_store_header");
SchemaStore::Header header;
header.magic = SchemaStore::Header::kMagic;
header.checksum = 10; // Arbitrary garbage checksum
filesystem_.DeleteFile(header_file.c_str());
filesystem_.Write(header_file.c_str(), &header, sizeof(header));
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Everything looks fine, ground truth and derived data
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema_));
EXPECT_THAT(schema_store->GetSchemaTypeId("email"), IsOkAndHolds(0));
}
TEST_F(SchemaStoreTest, CreateNoPreviousSchemaOk) {
EXPECT_THAT(SchemaStore::Create(&filesystem_, test_dir_), IsOk());
}
TEST_F(SchemaStoreTest, CreateWithPreviousSchemaOk) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
schema_store.reset();
EXPECT_THAT(SchemaStore::Create(&filesystem_, test_dir_), IsOk());
}
TEST_F(SchemaStoreTest, MultipleCreateOk) {
DocumentProto document;
document.set_schema("email");
auto properties = document.add_properties();
properties->set_name("subject");
properties->add_string_values("subject_content");
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
// Verify that our in-memory structures are ok
EXPECT_THAT(schema_store->GetSchemaTypeConfig("email"),
IsOkAndHolds(Pointee(EqualsProto(schema_.types(0)))));
ICING_ASSERT_OK_AND_ASSIGN(std::vector<Section> sections,
schema_store->ExtractSections(document));
EXPECT_THAT(sections[0].content, ElementsAre("subject_content"));
// Verify that our persisted data is ok
EXPECT_THAT(schema_store->GetSchemaTypeId("email"), IsOkAndHolds(0));
schema_store.reset();
ICING_ASSERT_OK_AND_ASSIGN(schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Verify that our in-memory structures are ok
EXPECT_THAT(schema_store->GetSchemaTypeConfig("email"),
IsOkAndHolds(Pointee(EqualsProto(schema_.types(0)))));
ICING_ASSERT_OK_AND_ASSIGN(sections, schema_store->ExtractSections(document));
EXPECT_THAT(sections[0].content, ElementsAre("subject_content"));
// Verify that our persisted data is ok
EXPECT_THAT(schema_store->GetSchemaTypeId("email"), IsOkAndHolds(0));
}
TEST_F(SchemaStoreTest, SetNewSchemaOk) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema_));
}
TEST_F(SchemaStoreTest, SetSameSchemaOk) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema_));
// And one more for fun
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(actual_schema, schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema_));
}
TEST_F(SchemaStoreTest, SetIncompatibleSchemaOk) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema_));
// Make the schema incompatible by removing a type.
schema_.clear_types();
// Set the incompatible schema
result.success = false;
result.schema_types_deleted_by_name.emplace("email");
result.schema_types_deleted_by_id.emplace(0);
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
}
TEST_F(SchemaStoreTest, SetSchemaWithAddedTypeOk) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaProto schema;
auto type = schema.add_types();
type->set_schema_type("email");
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
// Add a type, shouldn't affect the index or cached SchemaTypeIds
type = schema.add_types();
type->set_schema_type("new_type");
// Set the compatible schema
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(actual_schema, schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
}
TEST_F(SchemaStoreTest, SetSchemaWithDeletedTypeOk) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaProto schema;
auto type = schema.add_types();
type->set_schema_type("email");
type = schema.add_types();
type->set_schema_type("message");
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
ICING_ASSERT_OK_AND_ASSIGN(SchemaTypeId old_email_schema_type_id,
schema_store->GetSchemaTypeId("email"));
ICING_ASSERT_OK_AND_ASSIGN(SchemaTypeId old_message_schema_type_id,
schema_store->GetSchemaTypeId("message"));
// Remove "email" type, this also changes previous SchemaTypeIds
schema.Clear();
type = schema.add_types();
type->set_schema_type("message");
SchemaStore::SetSchemaResult incompatible_result;
incompatible_result.success = false;
incompatible_result.old_schema_type_ids_changed.emplace(
old_message_schema_type_id);
incompatible_result.schema_types_deleted_by_name.emplace("email");
incompatible_result.schema_types_deleted_by_id.emplace(
old_email_schema_type_id);
// Can't set the incompatible schema
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(incompatible_result)));
SchemaStore::SetSchemaResult force_result;
force_result.success = true;
force_result.old_schema_type_ids_changed.emplace(old_message_schema_type_id);
force_result.schema_types_deleted_by_name.emplace("email");
force_result.schema_types_deleted_by_id.emplace(old_email_schema_type_id);
// Force set the incompatible schema
EXPECT_THAT(schema_store->SetSchema(
schema, /*ignore_errors_and_delete_documents=*/true),
IsOkAndHolds(EqualsSetSchemaResult(force_result)));
ICING_ASSERT_OK_AND_ASSIGN(actual_schema, schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
}
TEST_F(SchemaStoreTest, SetSchemaWithReorderedTypesOk) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaProto schema;
auto type = schema.add_types();
type->set_schema_type("email");
type = schema.add_types();
type->set_schema_type("message");
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
// Reorder the types
schema.clear_types();
type = schema.add_types();
type->set_schema_type("message");
type = schema.add_types();
type->set_schema_type("email");
// Since we assign SchemaTypeIds based on order in the SchemaProto, this will
// cause SchemaTypeIds to change
result.old_schema_type_ids_changed.emplace(0); // Old SchemaTypeId of "email"
result.old_schema_type_ids_changed.emplace(
1); // Old SchemaTypeId of "message"
// Set the compatible schema
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(actual_schema, schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
}
TEST_F(SchemaStoreTest, SetSchemaThatRequiresReindexingOk) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaProto schema;
auto type = schema.add_types();
type->set_schema_type("email");
// Add an unindexed property
auto property = type->add_properties();
property->set_property_name("subject");
property->set_data_type(PropertyConfigProto::DataType::STRING);
property->set_cardinality(PropertyConfigProto::Cardinality::OPTIONAL);
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
// Make a previously unindexed property indexed
property = schema.mutable_types(0)->mutable_properties(0);
property->mutable_indexing_config()->set_term_match_type(
TermMatchType::EXACT_ONLY);
property->mutable_indexing_config()->set_tokenizer_type(
IndexingConfig::TokenizerType::PLAIN);
// With a new indexed property, we'll need to reindex
result.index_incompatible = true;
// Set the compatible schema
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(actual_schema, schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
}
TEST_F(SchemaStoreTest, SetSchemaWithIncompatibleTypesOk) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaProto schema;
auto type = schema.add_types();
type->set_schema_type("email");
// Add a STRING property
auto property = type->add_properties();
property->set_property_name("subject");
property->set_data_type(PropertyConfigProto::DataType::STRING);
property->set_cardinality(PropertyConfigProto::Cardinality::OPTIONAL);
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(result)));
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
ICING_ASSERT_OK_AND_ASSIGN(SchemaTypeId old_email_schema_type_id,
schema_store->GetSchemaTypeId("email"));
// Make a previously STRING property into DOUBLE
property = schema.mutable_types(0)->mutable_properties(0);
property->set_data_type(PropertyConfigProto::DataType::DOUBLE);
SchemaStore::SetSchemaResult incompatible_result;
incompatible_result.success = false;
incompatible_result.schema_types_incompatible_by_name.emplace("email");
incompatible_result.schema_types_incompatible_by_id.emplace(
old_email_schema_type_id);
// Can't set the incompatible schema
EXPECT_THAT(schema_store->SetSchema(schema),
IsOkAndHolds(EqualsSetSchemaResult(incompatible_result)));
SchemaStore::SetSchemaResult force_result;
force_result.success = true;
force_result.schema_types_incompatible_by_name.emplace("email");
force_result.schema_types_incompatible_by_id.emplace(
old_email_schema_type_id);
// Force set the incompatible schema
EXPECT_THAT(schema_store->SetSchema(
schema, /*ignore_errors_and_delete_documents=*/true),
IsOkAndHolds(EqualsSetSchemaResult(force_result)));
ICING_ASSERT_OK_AND_ASSIGN(actual_schema, schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
}
TEST_F(SchemaStoreTest, GetSchemaTypeId) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
schema_.clear_types();
// Add a few schema types
const std::string first_type = "first";
auto type = schema_.add_types();
type->set_schema_type(first_type);
const std::string second_type = "second";
type = schema_.add_types();
type->set_schema_type(second_type);
// Set it for the first time
SchemaStore::SetSchemaResult result;
result.success = true;
EXPECT_THAT(schema_store->SetSchema(schema_),
IsOkAndHolds(EqualsSetSchemaResult(result)));
EXPECT_THAT(schema_store->GetSchemaTypeId(first_type), IsOkAndHolds(0));
EXPECT_THAT(schema_store->GetSchemaTypeId(second_type), IsOkAndHolds(1));
}
TEST_F(SchemaStoreTest, ComputeChecksumDefaultOnEmptySchemaStore) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
Crc32 default_checksum;
EXPECT_THAT(schema_store->ComputeChecksum(), IsOkAndHolds(default_checksum));
}
TEST_F(SchemaStoreTest, ComputeChecksumSameBetweenCalls) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaProto foo_schema;
auto type_config = foo_schema.add_types();
type_config->set_schema_type("foo");
ICING_EXPECT_OK(schema_store->SetSchema(foo_schema));
ICING_ASSERT_OK_AND_ASSIGN(Crc32 checksum, schema_store->ComputeChecksum());
// Calling it again doesn't change the checksum
EXPECT_THAT(schema_store->ComputeChecksum(), IsOkAndHolds(checksum));
}
TEST_F(SchemaStoreTest, ComputeChecksumSameAcrossInstances) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaProto foo_schema;
auto type_config = foo_schema.add_types();
type_config->set_schema_type("foo");
ICING_EXPECT_OK(schema_store->SetSchema(foo_schema));
ICING_ASSERT_OK_AND_ASSIGN(Crc32 checksum, schema_store->ComputeChecksum());
// Destroy the previous instance and recreate SchemaStore
schema_store.reset();
ICING_ASSERT_OK_AND_ASSIGN(schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
EXPECT_THAT(schema_store->ComputeChecksum(), IsOkAndHolds(checksum));
}
TEST_F(SchemaStoreTest, ComputeChecksumChangesOnModification) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaProto foo_schema;
auto type_config = foo_schema.add_types();
type_config->set_schema_type("foo");
ICING_EXPECT_OK(schema_store->SetSchema(foo_schema));
ICING_ASSERT_OK_AND_ASSIGN(Crc32 checksum, schema_store->ComputeChecksum());
// Modifying the SchemaStore changes the checksum
SchemaProto foo_bar_schema;
type_config = foo_bar_schema.add_types();
type_config->set_schema_type("foo");
type_config = foo_bar_schema.add_types();
type_config->set_schema_type("bar");
ICING_EXPECT_OK(schema_store->SetSchema(foo_bar_schema));
EXPECT_THAT(schema_store->ComputeChecksum(), IsOkAndHolds(Not(Eq(checksum))));
}
TEST_F(SchemaStoreTest, PersistToDiskFineForEmptySchemaStore) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
// Persisting is fine and shouldn't affect anything
ICING_EXPECT_OK(schema_store->PersistToDisk());
}
TEST_F(SchemaStoreTest, PersistToDiskPreservesAcrossInstances) {
ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<SchemaStore> schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
SchemaProto schema;
auto type_config = schema.add_types();
type_config->set_schema_type("foo");
ICING_EXPECT_OK(schema_store->SetSchema(schema));
// Persisting shouldn't change anything
ICING_EXPECT_OK(schema_store->PersistToDisk());
ICING_ASSERT_OK_AND_ASSIGN(const SchemaProto* actual_schema,
schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
// Modify the schema so that something different is persisted next time
type_config = schema.add_types();
type_config->set_schema_type("bar");
ICING_EXPECT_OK(schema_store->SetSchema(schema));
// Should also persist on destruction
schema_store.reset();
// And we get the same schema back on reinitialization
ICING_ASSERT_OK_AND_ASSIGN(schema_store,
SchemaStore::Create(&filesystem_, test_dir_));
ICING_ASSERT_OK_AND_ASSIGN(actual_schema, schema_store->GetSchema());
EXPECT_THAT(*actual_schema, EqualsProto(schema));
}
} // namespace
} // namespace lib
} // namespace icing