普通文本  |  487行  |  16.13 KB

// 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