1 // Copyright (c) 2011 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 "chrome/browser/sync/glue/extension_util.h"
6
7 #include "base/file_path.h"
8 #include "base/values.h"
9 #include "chrome/browser/extensions/mock_extension_service.h"
10 #include "chrome/browser/sync/protocol/extension_specifics.pb.h"
11 #include "chrome/common/extensions/extension.h"
12 #include "chrome/common/extensions/extension_constants.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace browser_sync {
17
18 namespace {
19
20 using ::testing::_;
21 using ::testing::Return;
22 using ::testing::StrictMock;
23
24 #if defined(OS_WIN)
25 const FilePath::CharType kExtensionFilePath[] = FILE_PATH_LITERAL("c:\\foo");
26 #elif defined(OS_POSIX)
27 const FilePath::CharType kExtensionFilePath[] = FILE_PATH_LITERAL("/foo");
28 #endif
29
30 const char kValidId[] = "abcdefghijklmnopabcdefghijklmnop";
31 const char kValidVersion[] = "0.0.0.0";
32 const char kVersion1[] = "1.0.0.1";
33 const char kVersion2[] = "1.0.1.0";
34 const char kVersion3[] = "1.1.0.0";
35 const char kValidUpdateUrl1[] =
36 "http://clients2.google.com/service/update2/crx";
37 const char kValidUpdateUrl2[] =
38 "https://clients2.google.com/service/update2/crx";
39 const char kName[] = "MyExtension";
40 const char kName2[] = "MyExtension2";
41
42 class ExtensionUtilTest : public testing::Test {
43 };
44
MakeExtension(bool is_theme,const GURL & update_url,const GURL & launch_url,bool converted_from_user_script,Extension::Location location,int num_plugins,const FilePath & extension_path)45 scoped_refptr<Extension> MakeExtension(
46 bool is_theme, const GURL& update_url,
47 const GURL& launch_url,
48 bool converted_from_user_script,
49 Extension::Location location, int num_plugins,
50 const FilePath& extension_path) {
51 DictionaryValue source;
52 source.SetString(extension_manifest_keys::kName,
53 "PossiblySyncableExtension");
54 source.SetString(extension_manifest_keys::kVersion, "0.0.0.0");
55 if (is_theme) {
56 source.Set(extension_manifest_keys::kTheme, new DictionaryValue());
57 }
58 if (!update_url.is_empty()) {
59 source.SetString(extension_manifest_keys::kUpdateURL,
60 update_url.spec());
61 }
62 if (!launch_url.is_empty()) {
63 source.SetString(extension_manifest_keys::kLaunchWebURL,
64 launch_url.spec());
65 }
66 if (!is_theme) {
67 source.SetBoolean(extension_manifest_keys::kConvertedFromUserScript,
68 converted_from_user_script);
69 ListValue* plugins = new ListValue();
70 for (int i = 0; i < num_plugins; ++i) {
71 DictionaryValue* plugin = new DictionaryValue();
72 plugin->SetString(extension_manifest_keys::kPluginsPath, "");
73 plugins->Set(i, plugin);
74 }
75 source.Set(extension_manifest_keys::kPlugins, plugins);
76 }
77
78 std::string error;
79 scoped_refptr<Extension> extension = Extension::Create(
80 extension_path, location, source, Extension::STRICT_ERROR_CHECKS, &error);
81 EXPECT_TRUE(extension);
82 EXPECT_EQ("", error);
83 return extension;
84 }
85
TEST_F(ExtensionUtilTest,IsExtensionValid)86 TEST_F(ExtensionUtilTest, IsExtensionValid) {
87 {
88 FilePath file_path(kExtensionFilePath);
89 scoped_refptr<Extension> extension(
90 MakeExtension(false, GURL(), GURL(), false,
91 Extension::INTERNAL, 0, file_path));
92 EXPECT_TRUE(IsExtensionValid(*extension));
93 }
94 {
95 FilePath file_path(kExtensionFilePath);
96 scoped_refptr<Extension> extension(
97 MakeExtension(false, GURL(kValidUpdateUrl1), GURL(),
98 true, Extension::INTERNAL, 0, file_path));
99 EXPECT_TRUE(IsExtensionValid(*extension));
100 }
101 {
102 FilePath file_path(kExtensionFilePath);
103 scoped_refptr<Extension> extension(
104 MakeExtension(false, GURL(), GURL(), true,
105 Extension::INTERNAL, 0, file_path));
106 EXPECT_TRUE(IsExtensionValid(*extension));
107 }
108 {
109 FilePath file_path(kExtensionFilePath);
110 scoped_refptr<Extension> extension(
111 MakeExtension(true, GURL(), GURL(), false,
112 Extension::INTERNAL, 0, file_path));
113 EXPECT_TRUE(IsExtensionValid(*extension));
114 }
115 {
116 FilePath file_path(kExtensionFilePath);
117 scoped_refptr<Extension> extension(
118 MakeExtension(false, GURL(),
119 GURL("http://www.google.com"), false,
120 Extension::INTERNAL, 0, file_path));
121 EXPECT_TRUE(IsExtensionValid(*extension));
122 }
123 {
124 FilePath file_path(kExtensionFilePath);
125 scoped_refptr<Extension> extension(
126 MakeExtension(false, GURL(), GURL(), false,
127 Extension::EXTERNAL_PREF, 0, file_path));
128 EXPECT_FALSE(IsExtensionValid(*extension));
129 }
130 {
131 FilePath file_path(kExtensionFilePath);
132 scoped_refptr<Extension> extension(
133 MakeExtension(
134 false, GURL("http://third-party.update_url.com"), GURL(), true,
135 Extension::INTERNAL, 0, file_path));
136 EXPECT_FALSE(IsExtensionValid(*extension));
137 }
138 // These last 2 tests don't make sense on Chrome OS, where extension plugins
139 // are not allowed.
140 #if !defined(OS_CHROMEOS)
141 {
142 FilePath file_path(kExtensionFilePath);
143 scoped_refptr<Extension> extension(
144 MakeExtension(false, GURL(), GURL(), true,
145 Extension::INTERNAL, 1, file_path));
146 EXPECT_FALSE(extension && IsExtensionValid(*extension));
147 }
148 {
149 FilePath file_path(kExtensionFilePath);
150 scoped_refptr<Extension> extension(
151 MakeExtension(false, GURL(), GURL(), true,
152 Extension::INTERNAL, 2, file_path));
153 EXPECT_FALSE(extension && IsExtensionValid(*extension));
154 }
155 #endif
156 }
157
TEST_F(ExtensionUtilTest,IsExtensionSpecificsUnset)158 TEST_F(ExtensionUtilTest, IsExtensionSpecificsUnset) {
159 {
160 sync_pb::ExtensionSpecifics specifics;
161 EXPECT_TRUE(IsExtensionSpecificsUnset(specifics));
162 }
163
164 {
165 sync_pb::ExtensionSpecifics specifics;
166 specifics.set_id("a");
167 EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
168 }
169
170 {
171 sync_pb::ExtensionSpecifics specifics;
172 specifics.set_version("a");
173 EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
174 }
175
176 {
177 sync_pb::ExtensionSpecifics specifics;
178 specifics.set_update_url("a");
179 EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
180 }
181
182 {
183 sync_pb::ExtensionSpecifics specifics;
184 specifics.set_enabled(true);
185 EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
186 }
187
188 {
189 sync_pb::ExtensionSpecifics specifics;
190 specifics.set_incognito_enabled(true);
191 EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
192 }
193
194 {
195 sync_pb::ExtensionSpecifics specifics;
196 specifics.set_name("a");
197 EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
198 }
199 }
200
TEST_F(ExtensionUtilTest,IsExtensionSpecificsValid)201 TEST_F(ExtensionUtilTest, IsExtensionSpecificsValid) {
202 sync_pb::ExtensionSpecifics specifics;
203 EXPECT_FALSE(IsExtensionSpecificsValid(specifics));
204 specifics.set_id(kValidId);
205 EXPECT_FALSE(IsExtensionSpecificsValid(specifics));
206 specifics.set_version(kValidVersion);
207 EXPECT_TRUE(IsExtensionSpecificsValid(specifics));
208 EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
209 specifics.set_update_url(kValidUpdateUrl1);
210 EXPECT_TRUE(IsExtensionSpecificsValid(specifics));
211 EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
212
213 {
214 sync_pb::ExtensionSpecifics specifics_copy(specifics);
215 specifics_copy.set_id("invalid");
216 EXPECT_FALSE(IsExtensionSpecificsValid(specifics_copy));
217 }
218
219 {
220 sync_pb::ExtensionSpecifics specifics_copy(specifics);
221 specifics_copy.set_version("invalid");
222 EXPECT_FALSE(IsExtensionSpecificsValid(specifics_copy));
223 }
224
225 {
226 sync_pb::ExtensionSpecifics specifics_copy(specifics);
227 specifics_copy.set_update_url("http:invalid.com:invalid");
228 EXPECT_FALSE(IsExtensionSpecificsValid(specifics_copy));
229 }
230 }
231
TEST_F(ExtensionUtilTest,AreExtensionSpecificsEqual)232 TEST_F(ExtensionUtilTest, AreExtensionSpecificsEqual) {
233 sync_pb::ExtensionSpecifics a, b;
234 EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
235
236 a.set_id("a");
237 EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
238 b.set_id("a");
239 EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
240
241 a.set_version("1.5");
242 EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
243 b.set_version("1.5");
244 EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
245
246 a.set_update_url("http://www.foo.com");
247 EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
248 b.set_update_url("http://www.foo.com");
249 EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
250
251 a.set_enabled(true);
252 EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
253 b.set_enabled(true);
254 EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
255
256 a.set_incognito_enabled(true);
257 EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
258 b.set_incognito_enabled(true);
259 EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
260
261 a.set_name("name");
262 EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
263 b.set_name("name");
264 EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
265 }
266
TEST_F(ExtensionUtilTest,CopyUserProperties)267 TEST_F(ExtensionUtilTest, CopyUserProperties) {
268 sync_pb::ExtensionSpecifics dest_specifics;
269 dest_specifics.set_version(kVersion2);
270 dest_specifics.set_update_url(kValidUpdateUrl1);
271 dest_specifics.set_enabled(true);
272 dest_specifics.set_incognito_enabled(false);
273 dest_specifics.set_name(kName);
274
275 sync_pb::ExtensionSpecifics specifics;
276 specifics.set_id(kValidId);
277 specifics.set_version(kVersion3);
278 specifics.set_update_url(kValidUpdateUrl2);
279 specifics.set_enabled(false);
280 specifics.set_incognito_enabled(true);
281 specifics.set_name(kName2);
282
283 CopyUserProperties(specifics, &dest_specifics);
284 EXPECT_EQ("", dest_specifics.id());
285 EXPECT_EQ(kVersion2, dest_specifics.version());
286 EXPECT_EQ(kValidUpdateUrl1, dest_specifics.update_url());
287 EXPECT_FALSE(dest_specifics.enabled());
288 EXPECT_TRUE(dest_specifics.incognito_enabled());
289 EXPECT_EQ(kName, dest_specifics.name());
290 }
291
TEST_F(ExtensionUtilTest,CopyNonUserProperties)292 TEST_F(ExtensionUtilTest, CopyNonUserProperties) {
293 sync_pb::ExtensionSpecifics dest_specifics;
294 dest_specifics.set_id(kValidId);
295 dest_specifics.set_version(kVersion2);
296 dest_specifics.set_update_url(kValidUpdateUrl1);
297 dest_specifics.set_enabled(true);
298 dest_specifics.set_incognito_enabled(false);
299 dest_specifics.set_name(kName);
300
301 sync_pb::ExtensionSpecifics specifics;
302 specifics.set_id("");
303 specifics.set_version(kVersion3);
304 specifics.set_update_url(kValidUpdateUrl2);
305 specifics.set_enabled(false);
306 specifics.set_incognito_enabled(true);
307 specifics.set_name(kName2);
308
309 CopyNonUserProperties(specifics, &dest_specifics);
310 EXPECT_EQ("", dest_specifics.id());
311 EXPECT_EQ(kVersion3, dest_specifics.version());
312 EXPECT_EQ(kValidUpdateUrl2, dest_specifics.update_url());
313 EXPECT_TRUE(dest_specifics.enabled());
314 EXPECT_FALSE(dest_specifics.incognito_enabled());
315 EXPECT_EQ(kName2, dest_specifics.name());
316 }
317
TEST_F(ExtensionUtilTest,AreExtensionSpecificsUserPropertiesEqual)318 TEST_F(ExtensionUtilTest, AreExtensionSpecificsUserPropertiesEqual) {
319 sync_pb::ExtensionSpecifics a, b;
320 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
321
322 a.set_id("a");
323 b.set_id("b");
324 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
325
326 a.set_version("1.5");
327 b.set_version("1.6");
328 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
329
330 a.set_name("name");
331 b.set_name("name2");
332 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
333
334 a.set_update_url("http://www.foo.com");
335 b.set_update_url("http://www.foo2.com");
336 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
337
338 a.set_enabled(true);
339 EXPECT_FALSE(AreExtensionSpecificsUserPropertiesEqual(a, b));
340 b.set_enabled(true);
341 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
342
343 a.set_incognito_enabled(true);
344 EXPECT_FALSE(AreExtensionSpecificsUserPropertiesEqual(a, b));
345 b.set_incognito_enabled(true);
346 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
347 }
348
TEST_F(ExtensionUtilTest,AreExtensionSpecificsNonUserPropertiesEqual)349 TEST_F(ExtensionUtilTest, AreExtensionSpecificsNonUserPropertiesEqual) {
350 sync_pb::ExtensionSpecifics a, b;
351 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
352
353 a.set_enabled(true);
354 b.set_enabled(false);
355 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
356
357 a.set_incognito_enabled(true);
358 b.set_incognito_enabled(false);
359 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
360
361 a.set_id("a");
362 EXPECT_FALSE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
363 b.set_id("a");
364 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
365
366 a.set_version("1.5");
367 EXPECT_FALSE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
368 b.set_version("1.5");
369 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
370
371 a.set_update_url("http://www.foo.com");
372 EXPECT_FALSE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
373 b.set_update_url("http://www.foo.com");
374 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
375
376 a.set_name("name");
377 EXPECT_FALSE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
378 b.set_name("name");
379 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
380 }
381
MakeSyncableExtension(const std::string & version_string,const std::string & update_url_spec,const std::string & name,const FilePath & extension_path)382 scoped_refptr<Extension> MakeSyncableExtension(
383 const std::string& version_string,
384 const std::string& update_url_spec,
385 const std::string& name,
386 const FilePath& extension_path) {
387 DictionaryValue source;
388 source.SetString(extension_manifest_keys::kVersion, version_string);
389 source.SetString(extension_manifest_keys::kUpdateURL, update_url_spec);
390 source.SetString(extension_manifest_keys::kName, name);
391 std::string error;
392 scoped_refptr<Extension> extension = Extension::Create(
393 extension_path, Extension::INTERNAL, source,
394 Extension::STRICT_ERROR_CHECKS, &error);
395 EXPECT_TRUE(extension);
396 EXPECT_EQ("", error);
397 return extension;
398 }
399
TEST_F(ExtensionUtilTest,GetExtensionSpecifics)400 TEST_F(ExtensionUtilTest, GetExtensionSpecifics) {
401 FilePath file_path(kExtensionFilePath);
402 StrictMock<MockExtensionService> mock_extension_service;
403 EXPECT_CALL(mock_extension_service, IsExtensionEnabled(_))
404 .WillOnce(Return(true));
405 EXPECT_CALL(mock_extension_service, IsIncognitoEnabled(_))
406 .WillOnce(Return(false));
407
408 scoped_refptr<Extension> extension(
409 MakeSyncableExtension(
410 kValidVersion, kValidUpdateUrl1, kName, file_path));
411 sync_pb::ExtensionSpecifics specifics;
412 GetExtensionSpecifics(*extension, mock_extension_service, &specifics);
413 EXPECT_EQ(extension->id(), specifics.id());
414 EXPECT_EQ(extension->VersionString(), kValidVersion);
415 EXPECT_EQ(extension->update_url().spec(), kValidUpdateUrl1);
416 EXPECT_TRUE(specifics.enabled());
417 EXPECT_FALSE(specifics.incognito_enabled());
418 EXPECT_EQ(kName, specifics.name());
419 }
420
421 // TODO(akalin): Make ExtensionService/ExtensionUpdater testable
422 // enough to be able to write a unittest for SetExtensionProperties().
423
TEST_F(ExtensionUtilTest,MergeExtensionSpecificsWithUserProperties)424 TEST_F(ExtensionUtilTest, MergeExtensionSpecificsWithUserProperties) {
425 sync_pb::ExtensionSpecifics merged_specifics;
426 merged_specifics.set_id(kValidId);
427 merged_specifics.set_update_url(kValidUpdateUrl1);
428 merged_specifics.set_enabled(true);
429 merged_specifics.set_incognito_enabled(false);
430 merged_specifics.set_version(kVersion2);
431
432 sync_pb::ExtensionSpecifics specifics;
433 specifics.set_id(kValidId);
434 specifics.set_update_url(kValidUpdateUrl2);
435 merged_specifics.set_enabled(false);
436 merged_specifics.set_incognito_enabled(true);
437
438 specifics.set_version(kVersion1);
439 {
440 sync_pb::ExtensionSpecifics result = merged_specifics;
441 MergeExtensionSpecifics(specifics, false, &result);
442 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(
443 result, merged_specifics));
444 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(
445 result, merged_specifics));
446 }
447 {
448 sync_pb::ExtensionSpecifics result = merged_specifics;
449 MergeExtensionSpecifics(specifics, true, &result);
450 EXPECT_TRUE(AreExtensionSpecificsEqual(result, merged_specifics));
451 }
452
453 specifics.set_version(kVersion2);
454 {
455 sync_pb::ExtensionSpecifics result = merged_specifics;
456 MergeExtensionSpecifics(specifics, false, &result);
457 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(
458 result, merged_specifics));
459 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(
460 result, specifics));
461 }
462 {
463 sync_pb::ExtensionSpecifics result = merged_specifics;
464 MergeExtensionSpecifics(specifics, true, &result);
465 EXPECT_TRUE(AreExtensionSpecificsEqual(result, specifics));
466 }
467
468 specifics.set_version(kVersion3);
469 {
470 sync_pb::ExtensionSpecifics result = merged_specifics;
471 MergeExtensionSpecifics(specifics, false, &result);
472 EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(
473 result, merged_specifics));
474 EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(
475 result, specifics));
476 }
477 {
478 sync_pb::ExtensionSpecifics result = merged_specifics;
479 MergeExtensionSpecifics(specifics, true, &result);
480 EXPECT_TRUE(AreExtensionSpecificsEqual(result, specifics));
481 }
482 }
483
484 } // namespace
485
486 } // namespace browser_sync
487