summaryrefslogtreecommitdiffstats
path: root/chromium/components/policy/core/common/schema_registry_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/policy/core/common/schema_registry_unittest.cc')
-rw-r--r--chromium/components/policy/core/common/schema_registry_unittest.cc342
1 files changed, 342 insertions, 0 deletions
diff --git a/chromium/components/policy/core/common/schema_registry_unittest.cc b/chromium/components/policy/core/common/schema_registry_unittest.cc
new file mode 100644
index 00000000000..298b583035d
--- /dev/null
+++ b/chromium/components/policy/core/common/schema_registry_unittest.cc
@@ -0,0 +1,342 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/policy/core/common/schema_registry.h"
+
+#include <memory>
+
+#include "base/test/gtest_util.h"
+#include "components/policy/core/common/policy_namespace.h"
+#include "components/policy/core/common/schema.h"
+#include "extensions/buildflags/buildflags.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Mock;
+using ::testing::_;
+
+namespace policy {
+
+namespace {
+
+const char kTestSchema[] =
+ R"({
+ "type": "object",
+ "properties": {
+ "string": { "type": "string" },
+ "integer": { "type": "integer" },
+ "boolean": { "type": "boolean" },
+ "double": { "type": "number" },
+ "list": {
+ "type": "array",
+ "items": { "type": "string" }
+ },
+ "object": {
+ "type": "object",
+ "properties": {
+ "a": { "type": "string" },
+ "b": { "type": "integer" }
+ }
+ }
+ }
+ })";
+
+class MockSchemaRegistryObserver : public SchemaRegistry::Observer {
+ public:
+ MockSchemaRegistryObserver() {}
+ ~MockSchemaRegistryObserver() override {}
+
+ MOCK_METHOD1(OnSchemaRegistryUpdated, void(bool));
+ MOCK_METHOD0(OnSchemaRegistryReady, void());
+};
+
+bool SchemaMapEquals(const scoped_refptr<SchemaMap>& schema_map1,
+ const scoped_refptr<SchemaMap>& schema_map2) {
+ PolicyNamespaceList added;
+ PolicyNamespaceList removed;
+ schema_map1->GetChanges(schema_map2, &removed, &added);
+ return added.empty() && removed.empty();
+}
+
+} // namespace
+
+TEST(SchemaRegistryTest, Notifications) {
+ std::string error;
+ Schema schema = Schema::Parse(kTestSchema, &error);
+ ASSERT_TRUE(schema.valid()) << error;
+
+ MockSchemaRegistryObserver observer;
+ SchemaRegistry registry;
+ registry.AddObserver(&observer);
+
+ ASSERT_TRUE(registry.schema_map().get());
+ EXPECT_FALSE(registry.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc")));
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(true));
+ registry.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"),
+ schema);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Re-register also triggers notifications, because the Schema might have
+ // changed.
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(true));
+ registry.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"),
+ schema);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_TRUE(registry.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc")));
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(false));
+ registry.UnregisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_FALSE(registry.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc")));
+
+ // Registering multiple components at once issues only one notification.
+ ComponentMap components;
+ components["abc"] = schema;
+ components["def"] = schema;
+ components["xyz"] = schema;
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(true));
+ registry.RegisterComponents(POLICY_DOMAIN_EXTENSIONS, components);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ registry.RemoveObserver(&observer);
+}
+
+TEST(SchemaRegistryTest, IsReady) {
+ SchemaRegistry registry;
+ MockSchemaRegistryObserver observer;
+ registry.AddObserver(&observer);
+
+ EXPECT_FALSE(registry.IsReady());
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ EXPECT_CALL(observer, OnSchemaRegistryReady()).Times(0);
+ registry.SetExtensionsDomainsReady();
+ Mock::VerifyAndClearExpectations(&observer);
+ EXPECT_FALSE(registry.IsReady());
+#endif
+ EXPECT_CALL(observer, OnSchemaRegistryReady());
+ registry.SetDomainReady(POLICY_DOMAIN_CHROME);
+ Mock::VerifyAndClearExpectations(&observer);
+ EXPECT_TRUE(registry.IsReady());
+ EXPECT_CALL(observer, OnSchemaRegistryReady()).Times(0);
+ registry.SetDomainReady(POLICY_DOMAIN_CHROME);
+ Mock::VerifyAndClearExpectations(&observer);
+ EXPECT_TRUE(registry.IsReady());
+
+ CombinedSchemaRegistry combined;
+ EXPECT_TRUE(combined.IsReady());
+
+ registry.RemoveObserver(&observer);
+}
+
+TEST(SchemaRegistryTest, Combined) {
+ std::string error;
+ Schema schema = Schema::Parse(kTestSchema, &error);
+ ASSERT_TRUE(schema.valid()) << error;
+
+ MockSchemaRegistryObserver observer;
+ std::unique_ptr<SchemaRegistry> registry1(new SchemaRegistry);
+ std::unique_ptr<SchemaRegistry> registry2(new SchemaRegistry);
+ CombinedSchemaRegistry combined;
+ combined.AddObserver(&observer);
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(_)).Times(0);
+ registry1->RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"),
+ schema);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Starting to track a registry issues notifications when it comes with new
+ // schemas.
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(true));
+ combined.Track(registry1.get());
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Adding a new empty registry does not trigger notifications.
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(_)).Times(0);
+ combined.Track(registry2.get());
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Adding the same component to the combined registry itself triggers
+ // notifications.
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(true));
+ combined.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"),
+ schema);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Adding components to the sub-registries triggers notifications.
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(true));
+ registry2->RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def"),
+ schema);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // If the same component is published in 2 sub-registries then the combined
+ // registry publishes one of them.
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(true));
+ registry1->RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def"),
+ schema);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ ASSERT_EQ(1u, combined.schema_map()->GetDomains().size());
+ ASSERT_TRUE(combined.schema_map()->GetComponents(POLICY_DOMAIN_EXTENSIONS));
+ ASSERT_EQ(
+ 2u,
+ combined.schema_map()->GetComponents(POLICY_DOMAIN_EXTENSIONS)->size());
+ EXPECT_TRUE(combined.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc")));
+ EXPECT_TRUE(combined.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def")));
+ EXPECT_FALSE(combined.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "xyz")));
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(false));
+ registry1->UnregisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"));
+ Mock::VerifyAndClearExpectations(&observer);
+ // Still registered at the combined registry.
+ EXPECT_TRUE(combined.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc")));
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(false));
+ combined.UnregisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"));
+ Mock::VerifyAndClearExpectations(&observer);
+ // Now it's gone.
+ EXPECT_FALSE(combined.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc")));
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(false));
+ registry1->UnregisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def"));
+ Mock::VerifyAndClearExpectations(&observer);
+ // Still registered at registry2.
+ EXPECT_TRUE(combined.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def")));
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(false));
+ registry2->UnregisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def"));
+ Mock::VerifyAndClearExpectations(&observer);
+ // Now it's gone.
+ EXPECT_FALSE(combined.schema_map()->GetSchema(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def")));
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(true)).Times(2);
+ registry1->RegisterComponent(PolicyNamespace(POLICY_DOMAIN_CHROME, ""),
+ schema);
+ registry2->RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "hij"),
+ schema);
+ Mock::VerifyAndClearExpectations(&observer);
+
+ // Untracking |registry1| doesn't trigger an update notification, because it
+ // doesn't contain any components.
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(_)).Times(0);
+ registry1.reset();
+ Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(false));
+ registry2.reset();
+ Mock::VerifyAndClearExpectations(&observer);
+
+ combined.RemoveObserver(&observer);
+}
+
+TEST(SchemaRegistryTest, ForwardingSchemaRegistry) {
+ std::unique_ptr<SchemaRegistry> registry(new SchemaRegistry);
+ ForwardingSchemaRegistry forwarding(registry.get());
+ MockSchemaRegistryObserver observer;
+ forwarding.AddObserver(&observer);
+
+ EXPECT_FALSE(registry->IsReady());
+ EXPECT_FALSE(forwarding.IsReady());
+ // They always have the same SchemaMap.
+ EXPECT_TRUE(SchemaMapEquals(registry->schema_map(), forwarding.schema_map()));
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(true));
+ registry->RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"),
+ Schema());
+ Mock::VerifyAndClearExpectations(&observer);
+ EXPECT_TRUE(SchemaMapEquals(registry->schema_map(), forwarding.schema_map()));
+
+ EXPECT_CALL(observer, OnSchemaRegistryUpdated(false));
+ registry->UnregisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"));
+ Mock::VerifyAndClearExpectations(&observer);
+ EXPECT_TRUE(SchemaMapEquals(registry->schema_map(), forwarding.schema_map()));
+
+ // No notifications expected for these calls.
+ EXPECT_FALSE(registry->IsReady());
+ EXPECT_FALSE(forwarding.IsReady());
+
+ registry->SetExtensionsDomainsReady();
+ EXPECT_FALSE(registry->IsReady());
+ EXPECT_FALSE(forwarding.IsReady());
+
+ EXPECT_CALL(observer, OnSchemaRegistryReady());
+ registry->SetDomainReady(POLICY_DOMAIN_CHROME);
+ EXPECT_TRUE(registry->IsReady());
+ EXPECT_TRUE(forwarding.IsReady());
+ Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_TRUE(SchemaMapEquals(registry->schema_map(), forwarding.schema_map()));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ forwarding.SetExtensionsDomainsReady();
+ forwarding.SetDomainReady(POLICY_DOMAIN_CHROME);
+ EXPECT_TRUE(forwarding.IsReady());
+
+ // Keep the same SchemaMap when the original registry is gone.
+ // No notifications are expected in this case either.
+ scoped_refptr<SchemaMap> schema_map = registry->schema_map();
+ registry.reset();
+ EXPECT_TRUE(SchemaMapEquals(schema_map, forwarding.schema_map()));
+ Mock::VerifyAndClearExpectations(&observer);
+
+ forwarding.RemoveObserver(&observer);
+}
+
+TEST(SchemaRegistryTest, ForwardingSchemaRegistryReadiness) {
+ std::unique_ptr<SchemaRegistry> registry(new SchemaRegistry);
+
+ ForwardingSchemaRegistry forwarding_1(registry.get());
+ EXPECT_FALSE(registry->IsReady());
+ EXPECT_FALSE(forwarding_1.IsReady());
+
+ // Once the wrapped registry gets ready, the forwarding schema registry
+ // becomes ready too.
+ registry->SetAllDomainsReady();
+ EXPECT_TRUE(registry->IsReady());
+ EXPECT_TRUE(forwarding_1.IsReady());
+
+ // The wrapped registry was ready at the time when the forwarding registry was
+ // constructed, so the forwarding registry is immediately ready too.
+ ForwardingSchemaRegistry forwarding_2(registry.get());
+ EXPECT_TRUE(forwarding_2.IsReady());
+
+ // Destruction of the wrapped registry doesn't change the readiness of the
+ // forwarding registry.
+ registry.reset();
+ EXPECT_TRUE(forwarding_1.IsReady());
+ EXPECT_TRUE(forwarding_2.IsReady());
+}
+
+// Extension policy unregister before register shouldn't cause DCHECK failure.
+// However, Chrome policy should always register first.
+TEST(SchemaRegistryTest, UnregisterBeforeRegister) {
+ SchemaRegistry registry;
+ ASSERT_NO_FATAL_FAILURE(registry.UnregisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "")));
+ ASSERT_NO_FATAL_FAILURE(registry.UnregisterComponent(
+ PolicyNamespace(POLICY_DOMAIN_SIGNIN_EXTENSIONS, "")));
+
+ ASSERT_DCHECK_DEATH(
+ registry.UnregisterComponent(PolicyNamespace(POLICY_DOMAIN_CHROME, "")));
+}
+
+} // namespace policy