// Copyright (c) 2011 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 "chrome/browser/sync/glue/extension_util.h"
#include "base/file_path.h"
#include "base/values.h"
#include "chrome/browser/extensions/mock_extension_service.h"
#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace browser_sync {
namespace {
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
#if defined(OS_WIN)
const FilePath::CharType kExtensionFilePath[] = FILE_PATH_LITERAL("c:\\foo");
#elif defined(OS_POSIX)
const FilePath::CharType kExtensionFilePath[] = FILE_PATH_LITERAL("/foo");
#endif
const char kValidId[] = "abcdefghijklmnopabcdefghijklmnop";
const char kValidVersion[] = "0.0.0.0";
const char kVersion1[] = "1.0.0.1";
const char kVersion2[] = "1.0.1.0";
const char kVersion3[] = "1.1.0.0";
const char kValidUpdateUrl1[] =
"http://clients2.google.com/service/update2/crx";
const char kValidUpdateUrl2[] =
"https://clients2.google.com/service/update2/crx";
const char kName[] = "MyExtension";
const char kName2[] = "MyExtension2";
class ExtensionUtilTest : public testing::Test {
};
scoped_refptr<Extension> 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) {
DictionaryValue source;
source.SetString(extension_manifest_keys::kName,
"PossiblySyncableExtension");
source.SetString(extension_manifest_keys::kVersion, "0.0.0.0");
if (is_theme) {
source.Set(extension_manifest_keys::kTheme, new DictionaryValue());
}
if (!update_url.is_empty()) {
source.SetString(extension_manifest_keys::kUpdateURL,
update_url.spec());
}
if (!launch_url.is_empty()) {
source.SetString(extension_manifest_keys::kLaunchWebURL,
launch_url.spec());
}
if (!is_theme) {
source.SetBoolean(extension_manifest_keys::kConvertedFromUserScript,
converted_from_user_script);
ListValue* plugins = new ListValue();
for (int i = 0; i < num_plugins; ++i) {
DictionaryValue* plugin = new DictionaryValue();
plugin->SetString(extension_manifest_keys::kPluginsPath, "");
plugins->Set(i, plugin);
}
source.Set(extension_manifest_keys::kPlugins, plugins);
}
std::string error;
scoped_refptr<Extension> extension = Extension::Create(
extension_path, location, source, Extension::STRICT_ERROR_CHECKS, &error);
EXPECT_TRUE(extension);
EXPECT_EQ("", error);
return extension;
}
TEST_F(ExtensionUtilTest, IsExtensionValid) {
{
FilePath file_path(kExtensionFilePath);
scoped_refptr<Extension> extension(
MakeExtension(false, GURL(), GURL(), false,
Extension::INTERNAL, 0, file_path));
EXPECT_TRUE(IsExtensionValid(*extension));
}
{
FilePath file_path(kExtensionFilePath);
scoped_refptr<Extension> extension(
MakeExtension(false, GURL(kValidUpdateUrl1), GURL(),
true, Extension::INTERNAL, 0, file_path));
EXPECT_TRUE(IsExtensionValid(*extension));
}
{
FilePath file_path(kExtensionFilePath);
scoped_refptr<Extension> extension(
MakeExtension(false, GURL(), GURL(), true,
Extension::INTERNAL, 0, file_path));
EXPECT_TRUE(IsExtensionValid(*extension));
}
{
FilePath file_path(kExtensionFilePath);
scoped_refptr<Extension> extension(
MakeExtension(true, GURL(), GURL(), false,
Extension::INTERNAL, 0, file_path));
EXPECT_TRUE(IsExtensionValid(*extension));
}
{
FilePath file_path(kExtensionFilePath);
scoped_refptr<Extension> extension(
MakeExtension(false, GURL(),
GURL("http://www.google.com"), false,
Extension::INTERNAL, 0, file_path));
EXPECT_TRUE(IsExtensionValid(*extension));
}
{
FilePath file_path(kExtensionFilePath);
scoped_refptr<Extension> extension(
MakeExtension(false, GURL(), GURL(), false,
Extension::EXTERNAL_PREF, 0, file_path));
EXPECT_FALSE(IsExtensionValid(*extension));
}
{
FilePath file_path(kExtensionFilePath);
scoped_refptr<Extension> extension(
MakeExtension(
false, GURL("http://third-party.update_url.com"), GURL(), true,
Extension::INTERNAL, 0, file_path));
EXPECT_FALSE(IsExtensionValid(*extension));
}
// These last 2 tests don't make sense on Chrome OS, where extension plugins
// are not allowed.
#if !defined(OS_CHROMEOS)
{
FilePath file_path(kExtensionFilePath);
scoped_refptr<Extension> extension(
MakeExtension(false, GURL(), GURL(), true,
Extension::INTERNAL, 1, file_path));
EXPECT_FALSE(extension && IsExtensionValid(*extension));
}
{
FilePath file_path(kExtensionFilePath);
scoped_refptr<Extension> extension(
MakeExtension(false, GURL(), GURL(), true,
Extension::INTERNAL, 2, file_path));
EXPECT_FALSE(extension && IsExtensionValid(*extension));
}
#endif
}
TEST_F(ExtensionUtilTest, IsExtensionSpecificsUnset) {
{
sync_pb::ExtensionSpecifics specifics;
EXPECT_TRUE(IsExtensionSpecificsUnset(specifics));
}
{
sync_pb::ExtensionSpecifics specifics;
specifics.set_id("a");
EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
}
{
sync_pb::ExtensionSpecifics specifics;
specifics.set_version("a");
EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
}
{
sync_pb::ExtensionSpecifics specifics;
specifics.set_update_url("a");
EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
}
{
sync_pb::ExtensionSpecifics specifics;
specifics.set_enabled(true);
EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
}
{
sync_pb::ExtensionSpecifics specifics;
specifics.set_incognito_enabled(true);
EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
}
{
sync_pb::ExtensionSpecifics specifics;
specifics.set_name("a");
EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
}
}
TEST_F(ExtensionUtilTest, IsExtensionSpecificsValid) {
sync_pb::ExtensionSpecifics specifics;
EXPECT_FALSE(IsExtensionSpecificsValid(specifics));
specifics.set_id(kValidId);
EXPECT_FALSE(IsExtensionSpecificsValid(specifics));
specifics.set_version(kValidVersion);
EXPECT_TRUE(IsExtensionSpecificsValid(specifics));
EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
specifics.set_update_url(kValidUpdateUrl1);
EXPECT_TRUE(IsExtensionSpecificsValid(specifics));
EXPECT_FALSE(IsExtensionSpecificsUnset(specifics));
{
sync_pb::ExtensionSpecifics specifics_copy(specifics);
specifics_copy.set_id("invalid");
EXPECT_FALSE(IsExtensionSpecificsValid(specifics_copy));
}
{
sync_pb::ExtensionSpecifics specifics_copy(specifics);
specifics_copy.set_version("invalid");
EXPECT_FALSE(IsExtensionSpecificsValid(specifics_copy));
}
{
sync_pb::ExtensionSpecifics specifics_copy(specifics);
specifics_copy.set_update_url("http:invalid.com:invalid");
EXPECT_FALSE(IsExtensionSpecificsValid(specifics_copy));
}
}
TEST_F(ExtensionUtilTest, AreExtensionSpecificsEqual) {
sync_pb::ExtensionSpecifics a, b;
EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
a.set_id("a");
EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
b.set_id("a");
EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
a.set_version("1.5");
EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
b.set_version("1.5");
EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
a.set_update_url("http://www.foo.com");
EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
b.set_update_url("http://www.foo.com");
EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
a.set_enabled(true);
EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
b.set_enabled(true);
EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
a.set_incognito_enabled(true);
EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
b.set_incognito_enabled(true);
EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
a.set_name("name");
EXPECT_FALSE(AreExtensionSpecificsEqual(a, b));
b.set_name("name");
EXPECT_TRUE(AreExtensionSpecificsEqual(a, b));
}
TEST_F(ExtensionUtilTest, CopyUserProperties) {
sync_pb::ExtensionSpecifics dest_specifics;
dest_specifics.set_version(kVersion2);
dest_specifics.set_update_url(kValidUpdateUrl1);
dest_specifics.set_enabled(true);
dest_specifics.set_incognito_enabled(false);
dest_specifics.set_name(kName);
sync_pb::ExtensionSpecifics specifics;
specifics.set_id(kValidId);
specifics.set_version(kVersion3);
specifics.set_update_url(kValidUpdateUrl2);
specifics.set_enabled(false);
specifics.set_incognito_enabled(true);
specifics.set_name(kName2);
CopyUserProperties(specifics, &dest_specifics);
EXPECT_EQ("", dest_specifics.id());
EXPECT_EQ(kVersion2, dest_specifics.version());
EXPECT_EQ(kValidUpdateUrl1, dest_specifics.update_url());
EXPECT_FALSE(dest_specifics.enabled());
EXPECT_TRUE(dest_specifics.incognito_enabled());
EXPECT_EQ(kName, dest_specifics.name());
}
TEST_F(ExtensionUtilTest, CopyNonUserProperties) {
sync_pb::ExtensionSpecifics dest_specifics;
dest_specifics.set_id(kValidId);
dest_specifics.set_version(kVersion2);
dest_specifics.set_update_url(kValidUpdateUrl1);
dest_specifics.set_enabled(true);
dest_specifics.set_incognito_enabled(false);
dest_specifics.set_name(kName);
sync_pb::ExtensionSpecifics specifics;
specifics.set_id("");
specifics.set_version(kVersion3);
specifics.set_update_url(kValidUpdateUrl2);
specifics.set_enabled(false);
specifics.set_incognito_enabled(true);
specifics.set_name(kName2);
CopyNonUserProperties(specifics, &dest_specifics);
EXPECT_EQ("", dest_specifics.id());
EXPECT_EQ(kVersion3, dest_specifics.version());
EXPECT_EQ(kValidUpdateUrl2, dest_specifics.update_url());
EXPECT_TRUE(dest_specifics.enabled());
EXPECT_FALSE(dest_specifics.incognito_enabled());
EXPECT_EQ(kName2, dest_specifics.name());
}
TEST_F(ExtensionUtilTest, AreExtensionSpecificsUserPropertiesEqual) {
sync_pb::ExtensionSpecifics a, b;
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
a.set_id("a");
b.set_id("b");
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
a.set_version("1.5");
b.set_version("1.6");
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
a.set_name("name");
b.set_name("name2");
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
a.set_update_url("http://www.foo.com");
b.set_update_url("http://www.foo2.com");
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
a.set_enabled(true);
EXPECT_FALSE(AreExtensionSpecificsUserPropertiesEqual(a, b));
b.set_enabled(true);
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
a.set_incognito_enabled(true);
EXPECT_FALSE(AreExtensionSpecificsUserPropertiesEqual(a, b));
b.set_incognito_enabled(true);
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(a, b));
}
TEST_F(ExtensionUtilTest, AreExtensionSpecificsNonUserPropertiesEqual) {
sync_pb::ExtensionSpecifics a, b;
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
a.set_enabled(true);
b.set_enabled(false);
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
a.set_incognito_enabled(true);
b.set_incognito_enabled(false);
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
a.set_id("a");
EXPECT_FALSE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
b.set_id("a");
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
a.set_version("1.5");
EXPECT_FALSE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
b.set_version("1.5");
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
a.set_update_url("http://www.foo.com");
EXPECT_FALSE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
b.set_update_url("http://www.foo.com");
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
a.set_name("name");
EXPECT_FALSE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
b.set_name("name");
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(a, b));
}
scoped_refptr<Extension> MakeSyncableExtension(
const std::string& version_string,
const std::string& update_url_spec,
const std::string& name,
const FilePath& extension_path) {
DictionaryValue source;
source.SetString(extension_manifest_keys::kVersion, version_string);
source.SetString(extension_manifest_keys::kUpdateURL, update_url_spec);
source.SetString(extension_manifest_keys::kName, name);
std::string error;
scoped_refptr<Extension> extension = Extension::Create(
extension_path, Extension::INTERNAL, source,
Extension::STRICT_ERROR_CHECKS, &error);
EXPECT_TRUE(extension);
EXPECT_EQ("", error);
return extension;
}
TEST_F(ExtensionUtilTest, GetExtensionSpecifics) {
FilePath file_path(kExtensionFilePath);
StrictMock<MockExtensionService> mock_extension_service;
EXPECT_CALL(mock_extension_service, IsExtensionEnabled(_))
.WillOnce(Return(true));
EXPECT_CALL(mock_extension_service, IsIncognitoEnabled(_))
.WillOnce(Return(false));
scoped_refptr<Extension> extension(
MakeSyncableExtension(
kValidVersion, kValidUpdateUrl1, kName, file_path));
sync_pb::ExtensionSpecifics specifics;
GetExtensionSpecifics(*extension, mock_extension_service, &specifics);
EXPECT_EQ(extension->id(), specifics.id());
EXPECT_EQ(extension->VersionString(), kValidVersion);
EXPECT_EQ(extension->update_url().spec(), kValidUpdateUrl1);
EXPECT_TRUE(specifics.enabled());
EXPECT_FALSE(specifics.incognito_enabled());
EXPECT_EQ(kName, specifics.name());
}
// TODO(akalin): Make ExtensionService/ExtensionUpdater testable
// enough to be able to write a unittest for SetExtensionProperties().
TEST_F(ExtensionUtilTest, MergeExtensionSpecificsWithUserProperties) {
sync_pb::ExtensionSpecifics merged_specifics;
merged_specifics.set_id(kValidId);
merged_specifics.set_update_url(kValidUpdateUrl1);
merged_specifics.set_enabled(true);
merged_specifics.set_incognito_enabled(false);
merged_specifics.set_version(kVersion2);
sync_pb::ExtensionSpecifics specifics;
specifics.set_id(kValidId);
specifics.set_update_url(kValidUpdateUrl2);
merged_specifics.set_enabled(false);
merged_specifics.set_incognito_enabled(true);
specifics.set_version(kVersion1);
{
sync_pb::ExtensionSpecifics result = merged_specifics;
MergeExtensionSpecifics(specifics, false, &result);
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(
result, merged_specifics));
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(
result, merged_specifics));
}
{
sync_pb::ExtensionSpecifics result = merged_specifics;
MergeExtensionSpecifics(specifics, true, &result);
EXPECT_TRUE(AreExtensionSpecificsEqual(result, merged_specifics));
}
specifics.set_version(kVersion2);
{
sync_pb::ExtensionSpecifics result = merged_specifics;
MergeExtensionSpecifics(specifics, false, &result);
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(
result, merged_specifics));
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(
result, specifics));
}
{
sync_pb::ExtensionSpecifics result = merged_specifics;
MergeExtensionSpecifics(specifics, true, &result);
EXPECT_TRUE(AreExtensionSpecificsEqual(result, specifics));
}
specifics.set_version(kVersion3);
{
sync_pb::ExtensionSpecifics result = merged_specifics;
MergeExtensionSpecifics(specifics, false, &result);
EXPECT_TRUE(AreExtensionSpecificsUserPropertiesEqual(
result, merged_specifics));
EXPECT_TRUE(AreExtensionSpecificsNonUserPropertiesEqual(
result, specifics));
}
{
sync_pb::ExtensionSpecifics result = merged_specifics;
MergeExtensionSpecifics(specifics, true, &result);
EXPECT_TRUE(AreExtensionSpecificsEqual(result, specifics));
}
}
} // namespace
} // namespace browser_sync