Allow browser tests to run with dynamic CLD data.

This patch makes it possible to enable dynamic mode on any platform without
breaking all of the browser tests that rely upon translation functionality
working properly. Basically, we copy a static version of the CLD data file
into the place where it would be put by the dynamic data mechanism that has
been built. This allows the browser to find it immediately, and tests can
run as normal. Without this patch, all tests that rely directly or
indirectly upon language detection will fail.

BUG=367239

Review URL: https://codereview.chromium.org/285293004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271717 0039d316-1c4b-4281-b951-d872f2087c98
parent f70ef09e
...@@ -61,7 +61,7 @@ bool CldComponentInstallerTraits::OnCustomInstall( ...@@ -61,7 +61,7 @@ bool CldComponentInstallerTraits::OnCustomInstall(
} }
base::FilePath CldComponentInstallerTraits::GetInstalledPath( base::FilePath CldComponentInstallerTraits::GetInstalledPath(
const base::FilePath& base) const { const base::FilePath& base) {
// Currently, all platforms have the file at the same location because there // Currently, all platforms have the file at the same location because there
// is no binary difference in the generated file on any supported platform. // is no binary difference in the generated file on any supported platform.
// NB: This may change when 64-bit is officially supported. // NB: This may change when 64-bit is officially supported.
......
...@@ -12,6 +12,10 @@ ...@@ -12,6 +12,10 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "chrome/browser/component_updater/default_component_installer.h" #include "chrome/browser/component_updater/default_component_installer.h"
namespace test {
class ScopedCLDDynamicDataHarness;
} // namespace test
namespace component_updater { namespace component_updater {
class ComponentUpdateService; class ComponentUpdateService;
...@@ -24,6 +28,7 @@ class CldComponentInstallerTraits : public ComponentInstallerTraits { ...@@ -24,6 +28,7 @@ class CldComponentInstallerTraits : public ComponentInstallerTraits {
private: private:
friend class CldComponentInstallerTest; // For access within SetUp() friend class CldComponentInstallerTest; // For access within SetUp()
friend class test::ScopedCLDDynamicDataHarness; // For browser tests only
FRIEND_TEST_ALL_PREFIXES(CldComponentInstallerTest, ComponentReady); FRIEND_TEST_ALL_PREFIXES(CldComponentInstallerTest, ComponentReady);
FRIEND_TEST_ALL_PREFIXES(CldComponentInstallerTest, GetBaseDirectory); FRIEND_TEST_ALL_PREFIXES(CldComponentInstallerTest, GetBaseDirectory);
FRIEND_TEST_ALL_PREFIXES(CldComponentInstallerTest, GetHash); FRIEND_TEST_ALL_PREFIXES(CldComponentInstallerTest, GetHash);
...@@ -47,8 +52,8 @@ class CldComponentInstallerTraits : public ComponentInstallerTraits { ...@@ -47,8 +52,8 @@ class CldComponentInstallerTraits : public ComponentInstallerTraits {
virtual void GetHash(std::vector<uint8>* hash) const OVERRIDE; virtual void GetHash(std::vector<uint8>* hash) const OVERRIDE;
virtual std::string GetName() const OVERRIDE; virtual std::string GetName() const OVERRIDE;
base::FilePath GetInstalledPath(const base::FilePath& base) const; static base::FilePath GetInstalledPath(const base::FilePath& base);
void SetLatestCldDataFile(const base::FilePath& path); static void SetLatestCldDataFile(const base::FilePath& path);
DISALLOW_COPY_AND_ASSIGN(CldComponentInstallerTraits); DISALLOW_COPY_AND_ASSIGN(CldComponentInstallerTraits);
}; };
......
...@@ -76,7 +76,8 @@ TEST_F(CldComponentInstallerTest, OnCustomInstall) { ...@@ -76,7 +76,8 @@ TEST_F(CldComponentInstallerTest, OnCustomInstall) {
TEST_F(CldComponentInstallerTest, GetInstalledPath) { TEST_F(CldComponentInstallerTest, GetInstalledPath) {
const base::FilePath base_dir; const base::FilePath base_dir;
const base::FilePath result = traits.GetInstalledPath(base_dir); const base::FilePath result =
CldComponentInstallerTraits::GetInstalledPath(base_dir);
ASSERT_TRUE(EndsWith(result.value(), chrome::kCLDDataFilename, true)); ASSERT_TRUE(EndsWith(result.value(), chrome::kCLDDataFilename, true));
} }
......
// Copyright 2014 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/translate/translate_browser_test_utils.h"
#include "base/base_paths.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/platform_file.h"
#include "base/synchronization/lock.h"
#include "chrome/browser/component_updater/cld_component_installer.h"
#include "chrome/browser/translate/translate_tab_helper.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// This constant yields the version of the CRX that has been extracted into
// the test data directory, and must be kept in sync with what is there.
// A reciprocal comment has been placed in
// chrome/test/data/cld2_component/README.chromium; don't update one without
// updating the other.
#if defined(CLD2_DYNAMIC_MODE)
const base::FilePath::CharType kCrxVersion[] = FILE_PATH_LITERAL("160");
void GetTestDataSourceDirectory(base::FilePath* out_path) {
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, out_path));
*out_path = out_path->Append(FILE_PATH_LITERAL("cld2_component"))
.Append(kCrxVersion);
}
#endif // defined(CLD2_DYNAMIC_MODE)
#if defined(CLD2_DYNAMIC_MODE) && !defined(CLD2_IS_COMPONENT)
void GetStandaloneDataFileSource(base::FilePath* out_path) {
ASSERT_NO_FATAL_FAILURE(GetTestDataSourceDirectory(out_path));
*out_path = out_path->Append(FILE_PATH_LITERAL("_platform_specific"))
.Append(FILE_PATH_LITERAL("all"))
.Append(chrome::kCLDDataFilename);
}
// Using the USER_DATA_DIR not only mimics true functionality, but also is
// important to test isolation. Each test gets its own USER_DATA_DIR, which
// ensures proper isolation between test processes running in parallel.
void GetStandaloneDataFileDestination(base::FilePath* out_path) {
ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, out_path));
*out_path = out_path->Append(chrome::kCLDDataFilename);
}
void DeleteStandaloneDataFile() {
base::FilePath path;
ASSERT_NO_FATAL_FAILURE(GetStandaloneDataFileDestination(&path));
DLOG(INFO) << "Deleting CLD test data file from " << path.value();
base::DeleteFile(path, false);
}
void CopyStandaloneDataFile() {
DeleteStandaloneDataFile(); // sanity: blow away any old copies.
base::FilePath target_file;
ASSERT_NO_FATAL_FAILURE(GetStandaloneDataFileDestination(&target_file));
base::FilePath target_dir = target_file.DirName();
ASSERT_TRUE(base::CreateDirectoryAndGetError(target_dir, NULL));
base::FilePath source_file;
ASSERT_NO_FATAL_FAILURE(GetStandaloneDataFileSource(&source_file));
DLOG(INFO) << "Copying CLD test data file from " << source_file.value()
<< " to " << target_file.value();
ASSERT_TRUE(base::CopyFile(source_file, target_file));
ASSERT_TRUE(base::PathExists(target_file));
}
#endif // defined(CLD2_DYNAMIC_MODE) && !defined(CLD2_IS_COMPONENT)
#if defined(CLD2_DYNAMIC_MODE) && defined(CLD2_IS_COMPONENT)
// DIR_COMPONENT_CLD2 is also defined as being relative to USER_DATA_DIR, so
// like GetStandaloneDataFileDestination, this is safe to run in multiple
// parallel test processes.
void GetExtractedComponentDestination(base::FilePath* out_path) {
ASSERT_TRUE(PathService::Get(chrome::DIR_COMPONENT_CLD2, out_path));
}
void GetComponentDataFileDestination(base::FilePath* out_path) {
ASSERT_NO_FATAL_FAILURE(GetExtractedComponentDestination(out_path));
*out_path = out_path->Append(kCrxVersion)
.Append(FILE_PATH_LITERAL("_platform_specific"))
.Append(FILE_PATH_LITERAL("all"))
.Append(chrome::kCLDDataFilename);
}
void DeleteComponentTree() {
base::FilePath tree_path;
ASSERT_NO_FATAL_FAILURE(GetExtractedComponentDestination(&tree_path));
DLOG(INFO) << "Deleting CLD component test files from " << tree_path.value();
base::DeleteFile(tree_path, true);
}
void CopyComponentTree() {
DeleteComponentTree(); // sanity: blow away any old copies.
base::FilePath target_dir;
ASSERT_NO_FATAL_FAILURE(GetExtractedComponentDestination(&target_dir));
base::FilePath source_dir;
DLOG(INFO) << "Copying CLD component test files from " << source_dir.value()
<< " to " << target_dir.value();
ASSERT_NO_FATAL_FAILURE(GetTestDataSourceDirectory(&source_dir));
ASSERT_TRUE(base::CreateDirectoryAndGetError(target_dir, NULL));
ASSERT_TRUE(base::CopyDirectory(source_dir, target_dir, true));
ASSERT_TRUE(base::PathExists(target_dir));
base::FilePath check_path;
ASSERT_NO_FATAL_FAILURE(GetComponentDataFileDestination(&check_path));
ASSERT_TRUE(base::PathExists(check_path));
}
#endif // defined(CLD2_DYNAMIC_MODE) && defined(CLD2_IS_COMPONENT)
} // namespace
namespace test {
ScopedCLDDynamicDataHarness::ScopedCLDDynamicDataHarness() {
// Constructor does nothing in all cases. See Init() for initialization.
}
ScopedCLDDynamicDataHarness::~ScopedCLDDynamicDataHarness() {
DLOG(INFO) << "Tearing down CLD data harness";
#if defined(CLD2_DYNAMIC_MODE) && defined(CLD2_IS_COMPONENT)
// Dynamic data mode is enabled and we are using the component updater.
component_updater::CldComponentInstallerTraits::SetLatestCldDataFile(
base::FilePath());
DeleteComponentTree();
#elif defined(CLD2_DYNAMIC_MODE)
// Dynamic data mode is enabled and we are using a standalone file.
ClearStandaloneDataFileState();
DeleteStandaloneDataFile();
#endif // defined(CLD2_DYNAMIC_MODE)
}
void ScopedCLDDynamicDataHarness::Init() {
DLOG(INFO) << "Initializing CLD data harness";
#if defined(CLD2_DYNAMIC_MODE) && defined(CLD2_IS_COMPONENT)
// Dynamic data mode is enabled and we are using the component updater.
ASSERT_NO_FATAL_FAILURE(CopyComponentTree());
base::FilePath data_file;
ASSERT_NO_FATAL_FAILURE(GetComponentDataFileDestination(&data_file));
component_updater::CldComponentInstallerTraits::SetLatestCldDataFile(
data_file);
base::FilePath result = component_updater::GetLatestCldDataFile();
ASSERT_EQ(data_file, result);
#elif defined(CLD2_DYNAMIC_MODE)
// Dynamic data mode is enabled and we are using a standalone file.
ASSERT_NO_FATAL_FAILURE(ClearStandaloneDataFileState());
ASSERT_NO_FATAL_FAILURE(CopyStandaloneDataFile());
#endif // defined(CLD2_DYNAMIC_MODE)
}
void ScopedCLDDynamicDataHarness::ClearStandaloneDataFileState() {
#if defined(CLD2_DYNAMIC_MODE)
DLOG(INFO) << "Clearing CLD data file state";
// This code must live within the class in order to gain "friend" access.
base::AutoLock lock(TranslateTabHelper::s_file_lock_.Get());
if (TranslateTabHelper::s_cached_file_) {
// Leaks any open handle, no way to avoid safely.
TranslateTabHelper::s_cached_file_ = NULL;
TranslateTabHelper::s_cached_data_offset_ = 0;
TranslateTabHelper::s_cached_data_length_ = 0;
}
#endif // defined(CLD2_DYNAMIC_MODE)
}
} // namespace test
// Copyright 2014 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.
#ifndef CHROME_BROWSER_TRANSLATE_TRANSLATE_BROWSER_TEST_UTILS_H_
#define CHROME_BROWSER_TRANSLATE_TRANSLATE_BROWSER_TEST_UTILS_H_
#include "base/macros.h"
namespace test {
// A utility class that sets up CLD dynamic data upon calling Init() and cleans
// it up when destroyed.
//
// This class is intended to be instantiated within IN_PROC_BROWSER_TEST_F
// test fixtures; it uses ASSERT macros for correctness, so that tests will
// fail gracefully in error conditions. Sample use:
//
// #include "chrome/browser/translate/translate_browser_test_utils.h"
//
// IN_PROC_BROWSER_TEST_F(BrowserTest, PageLanguageDetection) {
// test::ScopedCLDDynamicDataHarness dynamic_data_scope;
// ASSERT_NO_FATAL_FAILURE(dynamic_data_scope.Init());
// // ... your code that depends on language detection goes here
// }
//
// If you have a lot of tests that need language translation features, you can
// add an instance of the ScopedCLDDynamicDataHarness to your test class'
// private member variables and add the call to Init() into your Setup method.
//
// NB: Test data lives under src/chrome/test/data/cld2_component
class ScopedCLDDynamicDataHarness {
public:
// Constructs the object, but does nothing. Call Init() to prepare the
// harness, and enclose that call in ASSERT_NO_FATAL_FAILURE(...).
ScopedCLDDynamicDataHarness();
// Reverses the work done by the constructor: any files and/or directories
// that would be created by the constructor are immediately and irrevocably
// deleted.
// If dynamic data is not currently available for any reason, this method has
// no net effect on the runtime.
~ScopedCLDDynamicDataHarness();
// Call this method, wrapping it in ASSERT_NO_FATAL_FAILURE, to initialize
// the harness and trigger test failure of initialization fails.
void Init();
private:
void ClearStandaloneDataFileState();
DISALLOW_COPY_AND_ASSIGN(ScopedCLDDynamicDataHarness);
};
} // namespace test
#endif // CHROME_BROWSER_TRANSLATE_TRANSLATE_BROWSER_TEST_UTILS_H_
...@@ -440,6 +440,7 @@ void TranslateTabHelper::HandleCLDDataRequest() { ...@@ -440,6 +440,7 @@ void TranslateTabHelper::HandleCLDDataRequest() {
} }
} }
} }
#endif // defined(CLD2_DYNAMIC_MODE) #endif // defined(CLD2_DYNAMIC_MODE)
void TranslateTabHelper::InitiateTranslation(const std::string& page_lang, void TranslateTabHelper::InitiateTranslation(const std::string& page_lang,
......
...@@ -26,12 +26,16 @@ ...@@ -26,12 +26,16 @@
namespace base { namespace base {
class File; class File;
} } // namespace base
namespace content { namespace content {
class BrowserContext; class BrowserContext;
class WebContents; class WebContents;
} } // namespace content
namespace test {
class ScopedCLDDynamicDataHarness;
} // namespace test
struct LanguageDetectionDetails; struct LanguageDetectionDetails;
class PrefService; class PrefService;
...@@ -100,6 +104,7 @@ class TranslateTabHelper ...@@ -100,6 +104,7 @@ class TranslateTabHelper
private: private:
explicit TranslateTabHelper(content::WebContents* web_contents); explicit TranslateTabHelper(content::WebContents* web_contents);
friend class content::WebContentsUserData<TranslateTabHelper>; friend class content::WebContentsUserData<TranslateTabHelper>;
friend class test::ScopedCLDDynamicDataHarness; // For cleaning static state.
// content::WebContentsObserver implementation. // content::WebContentsObserver implementation.
virtual void NavigationEntryCommitted( virtual void NavigationEntryCommitted(
...@@ -145,9 +150,9 @@ class TranslateTabHelper ...@@ -145,9 +150,9 @@ class TranslateTabHelper
// The data file, cached as long as the process stays alive. // The data file, cached as long as the process stays alive.
// We also track the offset at which the data starts, and its length. // We also track the offset at which the data starts, and its length.
static base::File* s_cached_file_; // guarded by file_lock_ static base::File* s_cached_file_; // guarded by file_lock_
static uint64 s_cached_data_offset_; // guarded by file_lock_ static uint64 s_cached_data_offset_; // guarded by file_lock_
static uint64 s_cached_data_length_; // guarded by file_lock_ static uint64 s_cached_data_length_; // guarded by file_lock_
// Guards s_cached_file_ // Guards s_cached_file_
static base::LazyInstance<base::Lock> s_file_lock_; static base::LazyInstance<base::Lock> s_file_lock_;
......
...@@ -1322,6 +1322,8 @@ ...@@ -1322,6 +1322,8 @@
'browser/task_manager/task_manager_browsertest_util.h', 'browser/task_manager/task_manager_browsertest_util.h',
'browser/themes/theme_service_browsertest.cc', 'browser/themes/theme_service_browsertest.cc',
'browser/translate/translate_browsertest.cc', 'browser/translate/translate_browsertest.cc',
'browser/translate/translate_browser_test_utils.cc',
'browser/translate/translate_browser_test_utils.h',
'browser/translate/translate_manager_browsertest.cc', 'browser/translate/translate_manager_browsertest.cc',
'browser/ui/app_list/app_list_controller_browsertest.cc', 'browser/ui/app_list/app_list_controller_browsertest.cc',
'browser/ui/app_list/app_list_service_views_browsertest.cc', 'browser/ui/app_list/app_list_service_views_browsertest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment