root/chrome/browser/sync/test/integration/sync_extension_helper.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. incognito_enabled
  2. Equals
  3. GetInstance
  4. SetupIfNecessary
  5. InstallExtension
  6. UninstallExtension
  7. GetInstalledExtensionNames
  8. EnableExtension
  9. DisableExtension
  10. IsExtensionEnabled
  11. IncognitoEnableExtension
  12. IncognitoDisableExtension
  13. IsIncognitoEnabled
  14. IsExtensionPendingInstallForSync
  15. InstallExtensionsPendingForSync
  16. GetExtensionStates
  17. ExtensionStatesMatch
  18. SetupProfile
  19. NameToPublicKey
  20. CreateExtension
  21. GetExtension

// Copyright (c) 2012 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/test/integration/sync_extension_helper.h"

#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/pending_extension_info.h"
#include "chrome/browser/extensions/pending_extension_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/id_util.h"
#include "extensions/common/manifest_constants.h"
#include "sync/api/string_ordinal.h"
#include "testing/gtest/include/gtest/gtest.h"

using extensions::Extension;
using extensions::ExtensionRegistry;
using extensions::Manifest;

SyncExtensionHelper::ExtensionState::ExtensionState()
    : enabled_state(ENABLED), incognito_enabled(false) {}

SyncExtensionHelper::ExtensionState::~ExtensionState() {}

bool SyncExtensionHelper::ExtensionState::Equals(
    const SyncExtensionHelper::ExtensionState &other) const {
  return ((enabled_state == other.enabled_state) &&
          (incognito_enabled == other.incognito_enabled));
}

// static
SyncExtensionHelper* SyncExtensionHelper::GetInstance() {
  SyncExtensionHelper* instance = Singleton<SyncExtensionHelper>::get();
  instance->SetupIfNecessary(sync_datatype_helper::test());
  return instance;
}

SyncExtensionHelper::SyncExtensionHelper() : setup_completed_(false) {}

SyncExtensionHelper::~SyncExtensionHelper() {}

void SyncExtensionHelper::SetupIfNecessary(SyncTest* test) {
  if (setup_completed_)
    return;

  for (int i = 0; i < test->num_clients(); ++i) {
    SetupProfile(test->GetProfile(i));
  }
  SetupProfile(test->verifier());

  setup_completed_ = true;
}

std::string SyncExtensionHelper::InstallExtension(
    Profile* profile, const std::string& name, Manifest::Type type) {
  scoped_refptr<Extension> extension = GetExtension(profile, name, type);
  if (!extension.get()) {
    NOTREACHED() << "Could not install extension " << name;
    return std::string();
  }
  extensions::ExtensionSystem::Get(profile)
      ->extension_service()
      ->OnExtensionInstalled(extension.get(),
                             syncer::StringOrdinal(),
                             false /* no requirement errors */,
                             extensions::NOT_BLACKLISTED,
                             false /* don't wait for idle to install */);
  return extension->id();
}

void SyncExtensionHelper::UninstallExtension(
    Profile* profile, const std::string& name) {
  ExtensionService::UninstallExtensionHelper(
      extensions::ExtensionSystem::Get(profile)->extension_service(),
      extensions::id_util::GenerateId(name));
}

std::vector<std::string> SyncExtensionHelper::GetInstalledExtensionNames(
    Profile* profile) const {
  std::vector<std::string> names;

  scoped_ptr<const extensions::ExtensionSet> extensions(
      extensions::ExtensionRegistry::Get(profile)
          ->GenerateInstalledExtensionsSet());
  for (extensions::ExtensionSet::const_iterator it = extensions->begin();
       it != extensions->end(); ++it) {
    names.push_back((*it)->name());
  }

  return names;
}

void SyncExtensionHelper::EnableExtension(Profile* profile,
                                          const std::string& name) {
  extensions::ExtensionSystem::Get(profile)
      ->extension_service()
      ->EnableExtension(extensions::id_util::GenerateId(name));
}

void SyncExtensionHelper::DisableExtension(Profile* profile,
                                           const std::string& name) {
  extensions::ExtensionSystem::Get(profile)
      ->extension_service()
      ->DisableExtension(extensions::id_util::GenerateId(name),
                         Extension::DISABLE_USER_ACTION);
}

bool SyncExtensionHelper::IsExtensionEnabled(
    Profile* profile, const std::string& name) const {
  return extensions::ExtensionSystem::Get(profile)
      ->extension_service()
      ->IsExtensionEnabled(extensions::id_util::GenerateId(name));
}

void SyncExtensionHelper::IncognitoEnableExtension(
    Profile* profile, const std::string& name) {
  extensions::util::SetIsIncognitoEnabled(
      extensions::id_util::GenerateId(name), profile, true);
}

void SyncExtensionHelper::IncognitoDisableExtension(
    Profile* profile, const std::string& name) {
  extensions::util::SetIsIncognitoEnabled(
      extensions::id_util::GenerateId(name), profile, false);
}

bool SyncExtensionHelper::IsIncognitoEnabled(
    Profile* profile, const std::string& name) const {
  return extensions::util::IsIncognitoEnabled(
      extensions::id_util::GenerateId(name), profile);
}


bool SyncExtensionHelper::IsExtensionPendingInstallForSync(
    Profile* profile, const std::string& id) const {
  const extensions::PendingExtensionManager* pending_extension_manager =
      extensions::ExtensionSystem::Get(profile)
          ->extension_service()
          ->pending_extension_manager();
  const extensions::PendingExtensionInfo* info =
      pending_extension_manager->GetById(id);
  if (!info)
    return false;
  return info->is_from_sync();
}

void SyncExtensionHelper::InstallExtensionsPendingForSync(Profile* profile) {
  // TODO(akalin): Mock out the servers that the extensions auto-update
  // mechanism talk to so as to more closely match what actually happens.
  // Background networking will need to be re-enabled for extensions tests.

  // We make a copy here since InstallExtension() removes the
  // extension from the extensions service's copy.
  const extensions::PendingExtensionManager* pending_extension_manager =
      extensions::ExtensionSystem::Get(profile)
          ->extension_service()
          ->pending_extension_manager();

  std::list<std::string> pending_crx_ids;
  pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_crx_ids);

  std::list<std::string>::const_iterator iter;
  const extensions::PendingExtensionInfo* info = NULL;
  for (iter = pending_crx_ids.begin(); iter != pending_crx_ids.end(); ++iter) {
    ASSERT_TRUE((info = pending_extension_manager->GetById(*iter)));
    if (!info->is_from_sync())
      continue;

    StringMap::const_iterator iter2 = id_to_name_.find(*iter);
    if (iter2 == id_to_name_.end()) {
      ADD_FAILURE() << "Could not get name for id " << *iter
                    << " (profile = " << profile->GetDebugName() << ")";
      continue;
    }
    TypeMap::const_iterator iter3 = id_to_type_.find(*iter);
    if (iter3 == id_to_type_.end()) {
      ADD_FAILURE() << "Could not get type for id " << *iter
                    << " (profile = " << profile->GetDebugName() << ")";
    }
    InstallExtension(profile, iter2->second, iter3->second);
  }
}

SyncExtensionHelper::ExtensionStateMap
    SyncExtensionHelper::GetExtensionStates(Profile* profile) {
  const std::string& profile_debug_name = profile->GetDebugName();

  ExtensionStateMap extension_state_map;

  scoped_ptr<const extensions::ExtensionSet> extensions(
      extensions::ExtensionRegistry::Get(profile)
          ->GenerateInstalledExtensionsSet());

  ExtensionService* extension_service =
      extensions::ExtensionSystem::Get(profile)->extension_service();
  for (extensions::ExtensionSet::const_iterator it = extensions->begin();
       it != extensions->end(); ++it) {
    const std::string& id = (*it)->id();
    extension_state_map[id].enabled_state =
        extension_service->IsExtensionEnabled(id) ?
        ExtensionState::ENABLED :
        ExtensionState::DISABLED;
    extension_state_map[id].incognito_enabled =
        extensions::util::IsIncognitoEnabled(id, profile);

    DVLOG(2) << "Extension " << (*it)->id() << " in profile "
             << profile_debug_name << " is "
             << (extension_service->IsExtensionEnabled(id) ?
                 "enabled" : "disabled");
  }

  const extensions::PendingExtensionManager* pending_extension_manager =
      extension_service->pending_extension_manager();

  std::list<std::string> pending_crx_ids;
  pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_crx_ids);

  std::list<std::string>::const_iterator id;
  for (id = pending_crx_ids.begin(); id != pending_crx_ids.end(); ++id) {
    extension_state_map[*id].enabled_state = ExtensionState::PENDING;
    extension_state_map[*id].incognito_enabled =
        extensions::util::IsIncognitoEnabled(*id, profile);
    DVLOG(2) << "Extension " << *id << " in profile "
             << profile_debug_name << " is pending";
  }

  return extension_state_map;
}

bool SyncExtensionHelper::ExtensionStatesMatch(
    Profile* profile1, Profile* profile2) {
  const ExtensionStateMap& state_map1 = GetExtensionStates(profile1);
  const ExtensionStateMap& state_map2 = GetExtensionStates(profile2);
  if (state_map1.size() != state_map2.size()) {
    DVLOG(1) << "Number of extensions for profile " << profile1->GetDebugName()
             << " does not match profile " << profile2->GetDebugName();
    return false;
  }

  ExtensionStateMap::const_iterator it1 = state_map1.begin();
  ExtensionStateMap::const_iterator it2 = state_map2.begin();
  while (it1 != state_map1.end()) {
    if (it1->first != it2->first) {
      DVLOG(1) << "Extensions for profile " << profile1->GetDebugName()
               << " do not match profile " << profile2->GetDebugName();
      return false;
    } else if (!it1->second.Equals(it2->second)) {
      DVLOG(1) << "Extension states for profile " << profile1->GetDebugName()
               << " do not match profile " << profile2->GetDebugName();
      return false;
    }
    ++it1;
    ++it2;
  }
  return true;
}

void SyncExtensionHelper::SetupProfile(Profile* profile) {
  extensions::ExtensionSystem::Get(profile)->InitForRegularProfile(true);
  profile_extensions_.insert(make_pair(profile, ExtensionNameMap()));
}

namespace {

std::string NameToPublicKey(const std::string& name) {
  std::string public_key;
  std::string pem;
  EXPECT_TRUE(Extension::ProducePEM(name, &pem) &&
              Extension::FormatPEMForFileOutput(pem, &public_key,
                                                true /* is_public */));
  return public_key;
}

// TODO(akalin): Somehow unify this with MakeExtension() in
// extension_util_unittest.cc.
scoped_refptr<Extension> CreateExtension(const base::FilePath& base_dir,
                                         const std::string& name,
                                         Manifest::Type type) {
  base::DictionaryValue source;
  source.SetString(extensions::manifest_keys::kName, name);
  const std::string& public_key = NameToPublicKey(name);
  source.SetString(extensions::manifest_keys::kPublicKey, public_key);
  source.SetString(extensions::manifest_keys::kVersion, "0.0.0.0");
  switch (type) {
    case Manifest::TYPE_EXTENSION:
      // Do nothing.
      break;
    case Manifest::TYPE_THEME:
      source.Set(extensions::manifest_keys::kTheme,
                 new base::DictionaryValue());
      break;
    case Manifest::TYPE_HOSTED_APP:
    case Manifest::TYPE_LEGACY_PACKAGED_APP:
      source.Set(extensions::manifest_keys::kApp, new base::DictionaryValue());
      source.SetString(extensions::manifest_keys::kLaunchWebURL,
                       "http://www.example.com");
      break;
    case Manifest::TYPE_PLATFORM_APP: {
      source.Set(extensions::manifest_keys::kApp, new base::DictionaryValue());
      source.Set(extensions::manifest_keys::kPlatformAppBackground,
                 new base::DictionaryValue());
      base::ListValue* scripts = new base::ListValue();
      scripts->AppendString("main.js");
      source.Set(extensions::manifest_keys::kPlatformAppBackgroundScripts,
                 scripts);
      break;
    }
    default:
      ADD_FAILURE();
      return NULL;
  }
  const base::FilePath sub_dir = base::FilePath().AppendASCII(name);
  base::FilePath extension_dir;
  if (!base::PathExists(base_dir) &&
      !base::CreateDirectory(base_dir)) {
    ADD_FAILURE();
    return NULL;
  }
  if (!base::CreateTemporaryDirInDir(base_dir, sub_dir.value(),
                                     &extension_dir)) {
    ADD_FAILURE();
    return NULL;
  }
  std::string error;
  scoped_refptr<Extension> extension =
      Extension::Create(extension_dir, Manifest::INTERNAL, source,
                        Extension::NO_FLAGS, &error);
  if (!error.empty()) {
    ADD_FAILURE() << error;
    return NULL;
  }
  if (!extension.get()) {
    ADD_FAILURE();
    return NULL;
  }
  if (extension->name() != name) {
    EXPECT_EQ(name, extension->name());
    return NULL;
  }
  if (extension->GetType() != type) {
    EXPECT_EQ(type, extension->GetType());
    return NULL;
  }
  return extension;
}

}  // namespace

scoped_refptr<Extension> SyncExtensionHelper::GetExtension(
    Profile* profile, const std::string& name, Manifest::Type type) {
  if (name.empty()) {
    ADD_FAILURE();
    return NULL;
  }
  ProfileExtensionNameMap::iterator it = profile_extensions_.find(profile);
  if (it == profile_extensions_.end()) {
    ADD_FAILURE();
    return NULL;
  }
  ExtensionNameMap::const_iterator it2 = it->second.find(name);
  if (it2 != it->second.end()) {
    return it2->second;
  }

  scoped_refptr<Extension> extension =
      CreateExtension(extensions::ExtensionSystem::Get(profile)
                          ->extension_service()
                          ->install_directory(),
                      name,
                      type);
  if (!extension.get()) {
    ADD_FAILURE();
    return NULL;
  }
  const std::string& expected_id = extensions::id_util::GenerateId(name);
  if (extension->id() != expected_id) {
    EXPECT_EQ(expected_id, extension->id());
    return NULL;
  }
  DVLOG(2) << "created extension with name = "
           << name << ", id = " << expected_id;
  (it->second)[name] = extension;
  id_to_name_[expected_id] = name;
  id_to_type_[expected_id] = type;
  return extension;
}

/* [<][>][^][v][top][bottom][index][help] */