1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "components/policy/core/common/schema_registry.h" 6 7 #include "components/policy/core/common/policy_namespace.h" 8 #include "components/policy/core/common/schema.h" 9 #include "testing/gmock/include/gmock/gmock.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 using ::testing::Mock; 13 using ::testing::_; 14 15 namespace policy { 16 17 namespace { 18 19 const char kTestSchema[] = 20 "{" 21 " \"type\": \"object\"," 22 " \"properties\": {" 23 " \"string\": { \"type\": \"string\" }," 24 " \"integer\": { \"type\": \"integer\" }," 25 " \"boolean\": { \"type\": \"boolean\" }," 26 " \"null\": { \"type\": \"null\" }," 27 " \"double\": { \"type\": \"number\" }," 28 " \"list\": {" 29 " \"type\": \"array\"," 30 " \"items\": { \"type\": \"string\" }" 31 " }," 32 " \"object\": {" 33 " \"type\": \"object\"," 34 " \"properties\": {" 35 " \"a\": { \"type\": \"string\" }," 36 " \"b\": { \"type\": \"integer\" }" 37 " }" 38 " }" 39 " }" 40 "}"; 41 42 class MockSchemaRegistryObserver : public SchemaRegistry::Observer { 43 public: 44 MockSchemaRegistryObserver() {} 45 virtual ~MockSchemaRegistryObserver() {} 46 47 MOCK_METHOD1(OnSchemaRegistryUpdated, void(bool)); 48 MOCK_METHOD0(OnSchemaRegistryReady, void()); 49 }; 50 51 } // namespace 52 53 TEST(SchemaRegistryTest, Notifications) { 54 std::string error; 55 Schema schema = Schema::Parse(kTestSchema, &error); 56 ASSERT_TRUE(schema.valid()) << error; 57 58 MockSchemaRegistryObserver observer; 59 SchemaRegistry registry; 60 EXPECT_FALSE(registry.HasObservers()); 61 registry.AddObserver(&observer); 62 EXPECT_TRUE(registry.HasObservers()); 63 64 ASSERT_TRUE(registry.schema_map()); 65 EXPECT_FALSE(registry.schema_map()->GetSchema( 66 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"))); 67 68 EXPECT_CALL(observer, OnSchemaRegistryUpdated(true)); 69 registry.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"), 70 schema); 71 Mock::VerifyAndClearExpectations(&observer); 72 73 // Re-register also triggers notifications, because the Schema might have 74 // changed. 75 EXPECT_CALL(observer, OnSchemaRegistryUpdated(true)); 76 registry.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"), 77 schema); 78 Mock::VerifyAndClearExpectations(&observer); 79 80 EXPECT_TRUE(registry.schema_map()->GetSchema( 81 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"))); 82 83 EXPECT_CALL(observer, OnSchemaRegistryUpdated(false)); 84 registry.UnregisterComponent( 85 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc")); 86 Mock::VerifyAndClearExpectations(&observer); 87 88 EXPECT_FALSE(registry.schema_map()->GetSchema( 89 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"))); 90 91 // Registering multiple components at once issues only one notification. 92 ComponentMap components; 93 components["abc"] = schema; 94 components["def"] = schema; 95 components["xyz"] = schema; 96 EXPECT_CALL(observer, OnSchemaRegistryUpdated(true)); 97 registry.RegisterComponents(POLICY_DOMAIN_EXTENSIONS, components); 98 Mock::VerifyAndClearExpectations(&observer); 99 100 registry.RemoveObserver(&observer); 101 EXPECT_FALSE(registry.HasObservers()); 102 } 103 104 TEST(SchemaRegistryTest, IsReady) { 105 SchemaRegistry registry; 106 MockSchemaRegistryObserver observer; 107 registry.AddObserver(&observer); 108 109 EXPECT_FALSE(registry.IsReady()); 110 #if defined(ENABLE_EXTENSIONS) 111 EXPECT_CALL(observer, OnSchemaRegistryReady()).Times(0); 112 registry.SetReady(POLICY_DOMAIN_EXTENSIONS); 113 Mock::VerifyAndClearExpectations(&observer); 114 EXPECT_FALSE(registry.IsReady()); 115 #endif 116 EXPECT_CALL(observer, OnSchemaRegistryReady()); 117 registry.SetReady(POLICY_DOMAIN_CHROME); 118 Mock::VerifyAndClearExpectations(&observer); 119 EXPECT_TRUE(registry.IsReady()); 120 EXPECT_CALL(observer, OnSchemaRegistryReady()).Times(0); 121 registry.SetReady(POLICY_DOMAIN_CHROME); 122 Mock::VerifyAndClearExpectations(&observer); 123 EXPECT_TRUE(registry.IsReady()); 124 125 CombinedSchemaRegistry combined; 126 EXPECT_TRUE(combined.IsReady()); 127 128 registry.RemoveObserver(&observer); 129 } 130 131 TEST(SchemaRegistryTest, Combined) { 132 std::string error; 133 Schema schema = Schema::Parse(kTestSchema, &error); 134 ASSERT_TRUE(schema.valid()) << error; 135 136 MockSchemaRegistryObserver observer; 137 SchemaRegistry registry1; 138 SchemaRegistry registry2; 139 CombinedSchemaRegistry combined; 140 combined.AddObserver(&observer); 141 142 EXPECT_CALL(observer, OnSchemaRegistryUpdated(_)).Times(0); 143 registry1.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"), 144 schema); 145 Mock::VerifyAndClearExpectations(&observer); 146 147 // Starting to track a registry issues notifications when it comes with new 148 // schemas. 149 EXPECT_CALL(observer, OnSchemaRegistryUpdated(true)); 150 combined.Track(®istry1); 151 Mock::VerifyAndClearExpectations(&observer); 152 153 // Adding a new empty registry does not trigger notifications. 154 EXPECT_CALL(observer, OnSchemaRegistryUpdated(_)).Times(0); 155 combined.Track(®istry2); 156 Mock::VerifyAndClearExpectations(&observer); 157 158 // Adding the same component to the combined registry itself triggers 159 // notifications. 160 EXPECT_CALL(observer, OnSchemaRegistryUpdated(true)); 161 combined.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"), 162 schema); 163 Mock::VerifyAndClearExpectations(&observer); 164 165 // Adding components to the sub-registries triggers notifications. 166 EXPECT_CALL(observer, OnSchemaRegistryUpdated(true)); 167 registry2.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def"), 168 schema); 169 Mock::VerifyAndClearExpectations(&observer); 170 171 // If the same component is published in 2 sub-registries then the combined 172 // registry publishes one of them. 173 EXPECT_CALL(observer, OnSchemaRegistryUpdated(true)); 174 registry1.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def"), 175 schema); 176 Mock::VerifyAndClearExpectations(&observer); 177 178 ASSERT_EQ(1u, combined.schema_map()->GetDomains().size()); 179 ASSERT_TRUE(combined.schema_map()->GetComponents(POLICY_DOMAIN_EXTENSIONS)); 180 ASSERT_EQ( 181 2u, 182 combined.schema_map()->GetComponents(POLICY_DOMAIN_EXTENSIONS)->size()); 183 EXPECT_TRUE(combined.schema_map()->GetSchema( 184 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"))); 185 EXPECT_TRUE(combined.schema_map()->GetSchema( 186 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def"))); 187 EXPECT_FALSE(combined.schema_map()->GetSchema( 188 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "xyz"))); 189 190 EXPECT_CALL(observer, OnSchemaRegistryUpdated(false)); 191 registry1.UnregisterComponent( 192 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc")); 193 Mock::VerifyAndClearExpectations(&observer); 194 // Still registered at the combined registry. 195 EXPECT_TRUE(combined.schema_map()->GetSchema( 196 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"))); 197 198 EXPECT_CALL(observer, OnSchemaRegistryUpdated(false)); 199 combined.UnregisterComponent( 200 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc")); 201 Mock::VerifyAndClearExpectations(&observer); 202 // Now it's gone. 203 EXPECT_FALSE(combined.schema_map()->GetSchema( 204 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "abc"))); 205 206 EXPECT_CALL(observer, OnSchemaRegistryUpdated(false)); 207 registry1.UnregisterComponent( 208 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def")); 209 Mock::VerifyAndClearExpectations(&observer); 210 // Still registered at registry2. 211 EXPECT_TRUE(combined.schema_map()->GetSchema( 212 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def"))); 213 214 EXPECT_CALL(observer, OnSchemaRegistryUpdated(false)); 215 registry2.UnregisterComponent( 216 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def")); 217 Mock::VerifyAndClearExpectations(&observer); 218 // Now it's gone. 219 EXPECT_FALSE(combined.schema_map()->GetSchema( 220 PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "def"))); 221 222 EXPECT_CALL(observer, OnSchemaRegistryUpdated(true)).Times(2); 223 registry1.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_CHROME, ""), 224 schema); 225 registry2.RegisterComponent(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, "hij"), 226 schema); 227 Mock::VerifyAndClearExpectations(&observer); 228 229 // Untracking |registry1| doesn't trigger an update nofitication, because it 230 // doesn't contain any components. 231 EXPECT_CALL(observer, OnSchemaRegistryUpdated(_)).Times(0); 232 combined.Untrack(®istry1); 233 Mock::VerifyAndClearExpectations(&observer); 234 235 EXPECT_CALL(observer, OnSchemaRegistryUpdated(false)); 236 combined.Untrack(®istry2); 237 Mock::VerifyAndClearExpectations(&observer); 238 239 combined.RemoveObserver(&observer); 240 } 241 242 } // namespace policy 243