OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/common/features/base_feature_provider.h" | 5 #include "extensions/common/features/base_feature_provider.h" |
6 | 6 |
7 #include "chrome/common/extensions/features/chrome_channel_feature_filter.h" | 7 #include <set> |
8 #include "chrome/common/extensions/features/feature_channel.h" | 8 #include <string> |
9 #include "extensions/common/features/permission_feature.h" | 9 |
| 10 #include "extensions/common/extension_builder.h" |
| 11 #include "extensions/common/features/feature.h" |
| 12 #include "extensions/common/features/simple_feature.h" |
| 13 #include "extensions/common/manifest.h" |
10 #include "extensions/common/value_builder.h" | 14 #include "extensions/common/value_builder.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
12 | 16 |
13 using chrome::VersionInfo; | |
14 | |
15 namespace extensions { | 17 namespace extensions { |
16 | 18 |
17 namespace { | 19 // Tests that a real manifest feature is available for the correct types of |
18 | 20 // extensions and apps. |
19 template <class FeatureClass> | 21 TEST(BaseFeatureProviderTest, ManifestFeatureTypes) { |
20 SimpleFeature* CreateFeature() { | |
21 SimpleFeature* feature = new FeatureClass(); | |
22 feature->AddFilter( | |
23 scoped_ptr<SimpleFeatureFilter>(new ChromeChannelFeatureFilter(feature))); | |
24 return feature; | |
25 } | |
26 | |
27 } // namespace | |
28 | |
29 TEST(BaseFeatureProviderTest, ManifestFeatures) { | |
30 const FeatureProvider* provider = BaseFeatureProvider::GetByName("manifest"); | 22 const FeatureProvider* provider = BaseFeatureProvider::GetByName("manifest"); |
| 23 // NOTE: This feature cannot have multiple rules, otherwise it is not a |
| 24 // SimpleFeature. |
31 SimpleFeature* feature = | 25 SimpleFeature* feature = |
32 static_cast<SimpleFeature*>(provider->GetFeature("description")); | 26 static_cast<SimpleFeature*>(provider->GetFeature("description")); |
33 ASSERT_TRUE(feature); | 27 ASSERT_TRUE(feature); |
34 EXPECT_EQ(6u, feature->extension_types()->size()); | 28 std::set<Manifest::Type>* extension_types = feature->extension_types(); |
35 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION)); | 29 EXPECT_EQ(6u, extension_types->size()); |
36 EXPECT_EQ(1u, | 30 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_EXTENSION)); |
37 feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); | 31 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); |
38 EXPECT_EQ(1u, | 32 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_PLATFORM_APP)); |
39 feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP)); | 33 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_HOSTED_APP)); |
40 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_HOSTED_APP)); | 34 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_THEME)); |
41 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_THEME)); | 35 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_SHARED_MODULE)); |
42 EXPECT_EQ(1u, | |
43 feature->extension_types()->count(Manifest::TYPE_SHARED_MODULE)); | |
44 | |
45 base::DictionaryValue manifest; | |
46 manifest.SetString("name", "test extension"); | |
47 manifest.SetString("version", "1"); | |
48 manifest.SetString("description", "hello there"); | |
49 | |
50 std::string error; | |
51 scoped_refptr<const Extension> extension(Extension::Create( | |
52 base::FilePath(), Manifest::INTERNAL, manifest, Extension::NO_FLAGS, | |
53 &error)); | |
54 | |
55 ASSERT_TRUE(extension.get()); | |
56 EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToContext( | |
57 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
58 | |
59 feature = | |
60 static_cast<SimpleFeature*>(provider->GetFeature("theme")); | |
61 ASSERT_TRUE(feature); | |
62 EXPECT_EQ(Feature::INVALID_TYPE, feature->IsAvailableToContext( | |
63 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
64 | |
65 feature = | |
66 static_cast<SimpleFeature*>(provider->GetFeature("devtools_page")); | |
67 ASSERT_TRUE(feature); | |
68 EXPECT_EQ(Feature::NOT_PRESENT, feature->IsAvailableToContext( | |
69 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
70 } | 36 } |
71 | 37 |
72 TEST(BaseFeatureProviderTest, PermissionFeatures) { | 38 // Tests that real manifest features have the correct availability for an |
| 39 // extension. |
| 40 TEST(BaseFeatureProviderTest, ManifestFeatureAvailability) { |
| 41 const FeatureProvider* provider = BaseFeatureProvider::GetByName("manifest"); |
| 42 |
| 43 scoped_refptr<const Extension> extension = |
| 44 ExtensionBuilder() |
| 45 .SetManifest(DictionaryBuilder() |
| 46 .Set("name", "test extension") |
| 47 .Set("version", "1") |
| 48 .Set("description", "hello there")) |
| 49 .Build(); |
| 50 ASSERT_TRUE(extension.get()); |
| 51 |
| 52 Feature* feature = provider->GetFeature("description"); |
| 53 EXPECT_EQ(Feature::IS_AVAILABLE, |
| 54 feature->IsAvailableToContext(extension.get(), |
| 55 Feature::UNSPECIFIED_CONTEXT, |
| 56 GURL()).result()); |
| 57 |
| 58 // This is a generic extension, so an app-only feature isn't allowed. |
| 59 feature = provider->GetFeature("app.background"); |
| 60 ASSERT_TRUE(feature); |
| 61 EXPECT_EQ(Feature::INVALID_TYPE, |
| 62 feature->IsAvailableToContext(extension.get(), |
| 63 Feature::UNSPECIFIED_CONTEXT, |
| 64 GURL()).result()); |
| 65 |
| 66 // A feature not listed in the manifest isn't allowed. |
| 67 feature = provider->GetFeature("background"); |
| 68 ASSERT_TRUE(feature); |
| 69 EXPECT_EQ(Feature::NOT_PRESENT, |
| 70 feature->IsAvailableToContext(extension.get(), |
| 71 Feature::UNSPECIFIED_CONTEXT, |
| 72 GURL()).result()); |
| 73 } |
| 74 |
| 75 // Tests that a real permission feature is available for the correct types of |
| 76 // extensions and apps. |
| 77 TEST(BaseFeatureProviderTest, PermissionFeatureTypes) { |
73 const FeatureProvider* provider = | 78 const FeatureProvider* provider = |
74 BaseFeatureProvider::GetByName("permission"); | 79 BaseFeatureProvider::GetByName("permission"); |
| 80 // NOTE: This feature cannot have multiple rules, otherwise it is not a |
| 81 // SimpleFeature. |
75 SimpleFeature* feature = | 82 SimpleFeature* feature = |
76 static_cast<SimpleFeature*>(provider->GetFeature("contextMenus")); | 83 static_cast<SimpleFeature*>(provider->GetFeature("power")); |
77 ASSERT_TRUE(feature); | 84 ASSERT_TRUE(feature); |
78 EXPECT_EQ(3u, feature->extension_types()->size()); | 85 std::set<Manifest::Type>* extension_types = feature->extension_types(); |
79 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION)); | 86 EXPECT_EQ(3u, extension_types->size()); |
80 EXPECT_EQ(1u, | 87 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_EXTENSION)); |
81 feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); | 88 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); |
82 EXPECT_EQ(1u, | 89 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_PLATFORM_APP)); |
83 feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP)); | |
84 | |
85 base::DictionaryValue manifest; | |
86 manifest.SetString("name", "test extension"); | |
87 manifest.SetString("version", "1"); | |
88 base::ListValue* permissions = new base::ListValue(); | |
89 manifest.Set("permissions", permissions); | |
90 permissions->Append(new base::StringValue("contextMenus")); | |
91 | |
92 std::string error; | |
93 scoped_refptr<const Extension> extension(Extension::Create( | |
94 base::FilePath(), Manifest::INTERNAL, manifest, Extension::NO_FLAGS, | |
95 &error)); | |
96 | |
97 ASSERT_TRUE(extension.get()); | |
98 EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToContext( | |
99 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
100 | |
101 feature = | |
102 static_cast<SimpleFeature*>(provider->GetFeature("chromePrivate")); | |
103 ASSERT_TRUE(feature); | |
104 EXPECT_EQ(Feature::NOT_FOUND_IN_WHITELIST, feature->IsAvailableToContext( | |
105 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
106 | |
107 feature = | |
108 static_cast<SimpleFeature*>(provider->GetFeature("clipboardWrite")); | |
109 ASSERT_TRUE(feature); | |
110 EXPECT_EQ(Feature::NOT_PRESENT, feature->IsAvailableToContext( | |
111 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
112 } | 90 } |
113 | 91 |
114 TEST(BaseFeatureProviderTest, Validation) { | 92 // Tests that real permission features have the correct availability for an app. |
115 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); | 93 TEST(BaseFeatureProviderTest, PermissionFeatureAvailability) { |
| 94 const FeatureProvider* provider = |
| 95 BaseFeatureProvider::GetByName("permission"); |
116 | 96 |
117 base::DictionaryValue* feature1 = new base::DictionaryValue(); | 97 scoped_refptr<const Extension> app = |
118 feature1->SetString("channel", "trunk"); | 98 ExtensionBuilder() |
119 value->Set("feature1", feature1); | 99 .SetManifest(DictionaryBuilder() |
| 100 .Set("name", "test app") |
| 101 .Set("version", "1") |
| 102 .Set("app", |
| 103 DictionaryBuilder().Set( |
| 104 "background", |
| 105 DictionaryBuilder().Set( |
| 106 "scripts", |
| 107 ListBuilder().Append("background.js")))) |
| 108 .Set("permissions", ListBuilder().Append("power"))) |
| 109 .Build(); |
| 110 ASSERT_TRUE(app.get()); |
| 111 ASSERT_TRUE(app->is_platform_app()); |
120 | 112 |
121 base::DictionaryValue* feature2 = new base::DictionaryValue(); | 113 // A permission requested in the manifest is available. |
122 feature2->SetString("channel", "trunk"); | 114 Feature* feature = provider->GetFeature("power"); |
123 base::ListValue* extension_types = new base::ListValue(); | 115 EXPECT_EQ( |
124 extension_types->Append(new base::StringValue("extension")); | 116 Feature::IS_AVAILABLE, |
125 feature2->Set("extension_types", extension_types); | 117 feature->IsAvailableToContext( |
126 base::ListValue* contexts = new base::ListValue(); | 118 app.get(), Feature::UNSPECIFIED_CONTEXT, GURL()).result()); |
127 contexts->Append(new base::StringValue("blessed_extension")); | |
128 feature2->Set("contexts", contexts); | |
129 value->Set("feature2", feature2); | |
130 | 119 |
131 scoped_ptr<BaseFeatureProvider> provider( | 120 // A permission only available to whitelisted extensions returns availability |
132 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); | 121 // NOT_FOUND_IN_WHITELIST. |
| 122 feature = provider->GetFeature("bluetoothPrivate"); |
| 123 ASSERT_TRUE(feature); |
| 124 EXPECT_EQ( |
| 125 Feature::NOT_FOUND_IN_WHITELIST, |
| 126 feature->IsAvailableToContext( |
| 127 app.get(), Feature::UNSPECIFIED_CONTEXT, GURL()).result()); |
133 | 128 |
134 // feature1 won't validate because it lacks an extension type. | 129 // A permission that isn't part of the manifest returns NOT_PRESENT. |
135 EXPECT_FALSE(provider->GetFeature("feature1")); | 130 feature = provider->GetFeature("serial"); |
136 | 131 ASSERT_TRUE(feature); |
137 // If we add one, it works. | 132 EXPECT_EQ( |
138 feature1->Set("extension_types", extension_types->DeepCopy()); | 133 Feature::NOT_PRESENT, |
139 provider.reset( | 134 feature->IsAvailableToContext( |
140 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); | 135 app.get(), Feature::UNSPECIFIED_CONTEXT, GURL()).result()); |
141 EXPECT_TRUE(provider->GetFeature("feature1")); | |
142 | |
143 // Remove the channel, and feature1 won't validate. | |
144 feature1->Remove("channel", NULL); | |
145 provider.reset( | |
146 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); | |
147 EXPECT_FALSE(provider->GetFeature("feature1")); | |
148 | |
149 // feature2 won't validate because of the presence of "contexts". | |
150 EXPECT_FALSE(provider->GetFeature("feature2")); | |
151 | |
152 // If we remove it, it works. | |
153 feature2->Remove("contexts", NULL); | |
154 provider.reset( | |
155 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); | |
156 EXPECT_TRUE(provider->GetFeature("feature2")); | |
157 } | |
158 | |
159 TEST(BaseFeatureProviderTest, ComplexFeatures) { | |
160 scoped_ptr<base::DictionaryValue> rule( | |
161 DictionaryBuilder() | |
162 .Set("feature1", ListBuilder() | |
163 .Append(DictionaryBuilder() | |
164 .Set("channel", "beta") | |
165 .Set("extension_types", ListBuilder() | |
166 .Append("extension"))) | |
167 .Append(DictionaryBuilder() | |
168 .Set("channel", "beta") | |
169 .Set("extension_types", ListBuilder() | |
170 .Append("legacy_packaged_app")))) | |
171 .Build()); | |
172 | |
173 scoped_ptr<BaseFeatureProvider> provider( | |
174 new BaseFeatureProvider(*rule, CreateFeature<SimpleFeature>)); | |
175 | |
176 Feature* feature = provider->GetFeature("feature1"); | |
177 EXPECT_TRUE(feature); | |
178 | |
179 // Make sure both rules are applied correctly. | |
180 { | |
181 ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_BETA); | |
182 EXPECT_EQ( | |
183 Feature::IS_AVAILABLE, | |
184 feature->IsAvailableToManifest("1", | |
185 Manifest::TYPE_EXTENSION, | |
186 Manifest::INVALID_LOCATION, | |
187 Feature::UNSPECIFIED_PLATFORM).result()); | |
188 EXPECT_EQ( | |
189 Feature::IS_AVAILABLE, | |
190 feature->IsAvailableToManifest("2", | |
191 Manifest::TYPE_LEGACY_PACKAGED_APP, | |
192 Manifest::INVALID_LOCATION, | |
193 Feature::UNSPECIFIED_PLATFORM).result()); | |
194 } | |
195 { | |
196 ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_STABLE); | |
197 EXPECT_NE( | |
198 Feature::IS_AVAILABLE, | |
199 feature->IsAvailableToManifest("1", | |
200 Manifest::TYPE_EXTENSION, | |
201 Manifest::INVALID_LOCATION, | |
202 Feature::UNSPECIFIED_PLATFORM).result()); | |
203 EXPECT_NE( | |
204 Feature::IS_AVAILABLE, | |
205 feature->IsAvailableToManifest("2", | |
206 Manifest::TYPE_LEGACY_PACKAGED_APP, | |
207 Manifest::INVALID_LOCATION, | |
208 Feature::UNSPECIFIED_PLATFORM).result()); | |
209 } | |
210 } | 136 } |
211 | 137 |
212 } // namespace extensions | 138 } // namespace extensions |
OLD | NEW |