diff options
author | jianli <jianli@chromium.org> | 2015-07-28 16:19:19 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-28 23:19:51 +0000 |
commit | 51172d27fefca69971769cd1e6304a9cd1a81884 (patch) | |
tree | 552a388481a5294f43e27c222dd003962a60c88c | |
parent | f88efde342905afe8861f38690c6641a14469a60 (diff) | |
download | chromium_src-51172d27fefca69971769cd1e6304a9cd1a81884.zip chromium_src-51172d27fefca69971769cd1e6304a9cd1a81884.tar.gz chromium_src-51172d27fefca69971769cd1e6304a9cd1a81884.tar.bz2 |
Hook up with web contents observer in OfflinePageMHTMLArchiver
BUG=491352
TEST=new tests
Review URL: https://codereview.chromium.org/1260103002
Cr-Commit-Position: refs/heads/master@{#340800}
9 files changed, 416 insertions, 40 deletions
diff --git a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.cc b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.cc index c035825..90ff9d1 100644 --- a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.cc +++ b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.cc @@ -10,6 +10,7 @@ #include "base/message_loop/message_loop.h" #include "base/single_thread_task_runner.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/android/offline_pages/offline_page_web_contents_observer.h" #include "content/public/browser/web_contents.h" namespace offline_pages { @@ -35,6 +36,13 @@ OfflinePageMHTMLArchiver::OfflinePageMHTMLArchiver( } OfflinePageMHTMLArchiver::~OfflinePageMHTMLArchiver() { + if (web_contents_) { + OfflinePageWebContentsObserver* web_contents_observer = + OfflinePageWebContentsObserver::FromWebContents(web_contents_); + if (web_contents_observer) + web_contents_observer->set_main_frame_document_loaded_callback( + base::Closure()); + } } void OfflinePageMHTMLArchiver::CreateArchive( @@ -43,26 +51,36 @@ void OfflinePageMHTMLArchiver::CreateArchive( DCHECK(!callback.is_null()); callback_ = callback; - if (!IsWebContentsValid()) { - DVLOG(1) << "WebContents is invalid. Can't create archive."; - ReportFailure(ArchiverResult::ERROR_CONTENT_UNAVAILABLE); - return; - } - GenerateMHTML(); } -bool OfflinePageMHTMLArchiver::IsWebContentsValid() const { - // TODO(fgorski): Make sure that web_contents is valid (use WCObserver). - return true; -} - void OfflinePageMHTMLArchiver::GenerateMHTML() { if (!web_contents_) { DVLOG(1) << "WebContents is missing. Can't create archive."; ReportFailure(ArchiverResult::ERROR_CONTENT_UNAVAILABLE); return; } + + OfflinePageWebContentsObserver* web_contents_observer = + OfflinePageWebContentsObserver::FromWebContents(web_contents_); + if (!web_contents_observer) { + DVLOG(1) << "WebContentsObserver is missing. Can't create archive."; + ReportFailure(ArchiverResult::ERROR_CONTENT_UNAVAILABLE); + return; + } + + // If main frame document has not been loaded yet, wait until it is. + if (!web_contents_observer->is_document_loaded_in_main_frame()) { + web_contents_observer->set_main_frame_document_loaded_callback( + base::Bind(&OfflinePageMHTMLArchiver::DoGenerateMHTML, + weak_ptr_factory_.GetWeakPtr())); + return; + } + + DoGenerateMHTML(); +} + +void OfflinePageMHTMLArchiver::DoGenerateMHTML() { // TODO(fgorski): Figure out if the actual URL or title can be different at // the end of MHTML generation. Perhaps we should pull it out after the MHTML // is generated. diff --git a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h index b00d391..f66522d 100644 --- a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h +++ b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h @@ -22,7 +22,6 @@ class WebContents; } // namespace content namespace offline_pages { -class TestMHTMLArchiver; // Class implementing an offline page archiver using MHTML as an archive format. // @@ -49,14 +48,25 @@ class OfflinePageMHTMLArchiver : public OfflinePageArchiver { // OfflinePageArchiver implementation: void CreateArchive(const CreateArchiveCallback& callback) override; - private: - friend class offline_pages::TestMHTMLArchiver; - + protected: // Allows to overload the archiver for testing. OfflinePageMHTMLArchiver( const base::FilePath& file_path, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + // Try to generate MHTML. + // Might be overridden for testing purpose. + virtual void GenerateMHTML(); + + // Actual call to generate MHTML. + // Might be overridden for testing purpose. + virtual void DoGenerateMHTML(); + + // Callback for Generating MHTML. + void OnGenerateMHTMLDone(const GURL& url, + const base::string16& title, + int64 file_size); + // Sends the result of archiving a page to the client that requested archive // creation. void ReportResult(ArchiverResult result, @@ -65,15 +75,7 @@ class OfflinePageMHTMLArchiver : public OfflinePageArchiver { int64 file_size); void ReportFailure(ArchiverResult result); - // Checks that |web_contents_| is still valid. - virtual bool IsWebContentsValid() const; - // Actual call to generate MHTML. - virtual void GenerateMHTML(); - // Callback for Generating MHTML. - void OnGenerateMHTMLDone(const GURL& url, - const base::string16& title, - int64 file_size); - + private: // Path to the archive file. const base::FilePath file_path_; // Contents of the web page to be serialized. Not owned. diff --git a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc index 84cfb8d..0b01879 100644 --- a/chrome/browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc +++ b/chrome/browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc @@ -12,17 +12,19 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/thread_task_runner_handle.h" +#include "chrome/browser/android/offline_pages/offline_page_web_contents_observer.h" #include "testing/gtest/include/gtest/gtest.h" namespace offline_pages { namespace { + const char kTestURL[] = "http://example.com/"; const base::string16 kTestTitle = base::ASCIIToUTF16("Test page title"); const base::FilePath::CharType kTestFilePath[] = FILE_PATH_LITERAL( "/archive_dir/offline_page.mhtml"); const int64 kTestFileSize = 123456LL; -} // namespace class TestMHTMLArchiver : public OfflinePageMHTMLArchiver { public: @@ -41,7 +43,6 @@ class TestMHTMLArchiver : public OfflinePageMHTMLArchiver { ~TestMHTMLArchiver() override; private: - bool IsWebContentsValid() const override; void GenerateMHTML() override; const GURL url_; @@ -66,22 +67,28 @@ TestMHTMLArchiver::TestMHTMLArchiver( TestMHTMLArchiver::~TestMHTMLArchiver() { } -bool TestMHTMLArchiver::IsWebContentsValid() const { - return test_scenario_ != TestScenario::WEB_CONTENTS_MISSING; -} - void TestMHTMLArchiver::GenerateMHTML() { - int64 file_size = kTestFileSize; - if (test_scenario_ == TestScenario::NOT_ABLE_TO_ARCHIVE) - file_size = -1; - task_runner_->PostTask(FROM_HERE, - base::Bind(&TestMHTMLArchiver::OnGenerateMHTMLDone, - base::Unretained(this), - url_, - title_, - file_size)); + if (test_scenario_ == TestScenario::WEB_CONTENTS_MISSING) { + ReportFailure(ArchiverResult::ERROR_CONTENT_UNAVAILABLE); + return; + } + + if (test_scenario_ == TestScenario::NOT_ABLE_TO_ARCHIVE) { + ReportFailure(ArchiverResult::ERROR_ARCHIVE_CREATION_FAILED); + return; + } + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&TestMHTMLArchiver::OnGenerateMHTMLDone, + base::Unretained(this), + url_, + title_, + kTestFileSize)); } +} // namespace + class OfflinePageMHTMLArchiverTest : public testing::Test { public: OfflinePageMHTMLArchiverTest(); @@ -148,7 +155,8 @@ scoped_ptr<TestMHTMLArchiver> OfflinePageMHTMLArchiverTest::CreateArchiver( const base::string16& title, TestMHTMLArchiver::TestScenario scenario) { return scoped_ptr<TestMHTMLArchiver>(new TestMHTMLArchiver( - url, title, scenario, GetTestFilePath(), message_loop_.task_runner())); + url, title, scenario, GetTestFilePath(), + base::ThreadTaskRunnerHandle::Get())); } void OfflinePageMHTMLArchiverTest::OnCreateArchiveDone( diff --git a/chrome/browser/android/offline_pages/offline_page_web_contents_observer.cc b/chrome/browser/android/offline_pages/offline_page_web_contents_observer.cc new file mode 100644 index 0000000..57b1679 --- /dev/null +++ b/chrome/browser/android/offline_pages/offline_page_web_contents_observer.cc @@ -0,0 +1,52 @@ +// Copyright 2015 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/android/offline_pages/offline_page_web_contents_observer.h" + +#include "content/public/browser/navigation_details.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" + +DEFINE_WEB_CONTENTS_USER_DATA_KEY( + offline_pages::OfflinePageWebContentsObserver); + +namespace offline_pages { + +OfflinePageWebContentsObserver::OfflinePageWebContentsObserver( + content::WebContents* web_contents) + : content::WebContentsObserver(web_contents), + is_document_loaded_in_main_frame_(false) { +} + +OfflinePageWebContentsObserver::~OfflinePageWebContentsObserver() { +} + +void OfflinePageWebContentsObserver::DocumentLoadedInFrame( + content::RenderFrameHost* render_frame_host) { + if (!render_frame_host->GetParent()) { + is_document_loaded_in_main_frame_ = true; + if (!main_frame_document_loaded_callback_.is_null()) + main_frame_document_loaded_callback_.Run(); + } +} + +void OfflinePageWebContentsObserver::DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + if (details.is_navigation_to_different_page()) + is_document_loaded_in_main_frame_ = false; +} + +void OfflinePageWebContentsObserver::RenderProcessGone( + base::TerminationStatus status) { + CleanUp(); +} + +void OfflinePageWebContentsObserver::CleanUp() { + content::WebContentsObserver::Observe(nullptr); +} + +} // namespace offline_pages diff --git a/chrome/browser/android/offline_pages/offline_page_web_contents_observer.h b/chrome/browser/android/offline_pages/offline_page_web_contents_observer.h new file mode 100644 index 0000000..81e11f3 --- /dev/null +++ b/chrome/browser/android/offline_pages/offline_page_web_contents_observer.h @@ -0,0 +1,55 @@ +// Copyright 2015 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_ANDROID_OFFLINE_PAGES_OFFLINE_PAGE_WEB_CONTENTS_OBSERVER_H_ +#define CHROME_BROWSER_ANDROID_OFFLINE_PAGES_OFFLINE_PAGE_WEB_CONTENTS_OBSERVER_H_ + +#include "base/callback.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" + +namespace offline_pages { + +// Observes activities occurred in the page that is to be archived. +class OfflinePageWebContentsObserver + : public content::WebContentsObserver, + public content::WebContentsUserData<OfflinePageWebContentsObserver> { + public: + ~OfflinePageWebContentsObserver() override; + + bool is_document_loaded_in_main_frame() const { + return is_document_loaded_in_main_frame_; + } + + void set_main_frame_document_loaded_callback(const base::Closure& callback) { + main_frame_document_loaded_callback_ = callback; + } + + // content::WebContentsObserver: + void DocumentLoadedInFrame( + content::RenderFrameHost* render_frame_host) override; + void DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) override; + void RenderProcessGone(base::TerminationStatus status) override; + + private: + explicit OfflinePageWebContentsObserver(content::WebContents* web_contents); + friend class content::WebContentsUserData<OfflinePageWebContentsObserver>; + + // Removes the observer and clears the WebContents member. + void CleanUp(); + + // Tracks whether the document of main frame has been loaded. + bool is_document_loaded_in_main_frame_; + + base::Closure main_frame_document_loaded_callback_; + + DISALLOW_COPY_AND_ASSIGN(OfflinePageWebContentsObserver); +}; + +} // namespace offline_pages + +#endif // CHROME_BROWSER_ANDROID_OFFLINE_PAGES_OFFLINE_PAGE_WEB_CONTENTS_OBSERVER_H_ diff --git a/chrome/browser/android/offline_pages/offline_page_web_contents_observer_unittest.cc b/chrome/browser/android/offline_pages/offline_page_web_contents_observer_unittest.cc new file mode 100644 index 0000000..c685088 --- /dev/null +++ b/chrome/browser/android/offline_pages/offline_page_web_contents_observer_unittest.cc @@ -0,0 +1,235 @@ +// Copyright 2015 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 "base/bind.h" +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "base/thread_task_runner_handle.h" +#include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" +#include "chrome/browser/android/offline_pages/offline_page_web_contents_observer.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "content/public/browser/navigation_details.h" +#include "content/public/test/test_renderer_host.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace offline_pages { + +namespace { + +const GURL kTestURL("http://example.com/"); +const base::string16 kTestTitle = base::ASCIIToUTF16("Test page title"); +const base::FilePath::CharType kTestFilePath[] = FILE_PATH_LITERAL( + "/archive_dir/offline_page.mhtml"); +const int64 kTestFileSize = 123456LL; + +class TestMHTMLArchiver : public OfflinePageMHTMLArchiver { + public: + TestMHTMLArchiver( + content::WebContents* web_contents, + const GURL& url, + const base::string16& title, + const base::FilePath& archive_dir); + ~TestMHTMLArchiver() override; + + private: + void DoGenerateMHTML() override; + + const GURL url_; + const base::string16 title_; + + DISALLOW_COPY_AND_ASSIGN(TestMHTMLArchiver); +}; + +TestMHTMLArchiver::TestMHTMLArchiver( + content::WebContents* web_contents, + const GURL& url, + const base::string16& title, + const base::FilePath& archive_dir) + : OfflinePageMHTMLArchiver( + web_contents, archive_dir, base::ThreadTaskRunnerHandle::Get()), + url_(url), + title_(title) { +} + +TestMHTMLArchiver::~TestMHTMLArchiver() { +} + +void TestMHTMLArchiver::DoGenerateMHTML() { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&TestMHTMLArchiver::OnGenerateMHTMLDone, + base::Unretained(this), + url_, + title_, + kTestFileSize)); +} + +} // namespace + +class OfflinePageWebContentsObserverTest : + public ChromeRenderViewHostTestHarness { + public: + OfflinePageWebContentsObserverTest(); + ~OfflinePageWebContentsObserverTest() override; + + void SetUp() override; + void TearDown() override; + + // Helper to create an archiver and call its CreateArchive. + void CreateArchive(const GURL& url, const base::string16& title); + + // Test tooling methods. + void PumpLoop(); + + OfflinePageWebContentsObserver* web_contents_observer() const { + return web_contents_observer_; + } + + OfflinePageArchiver::ArchiverResult last_result() const { + return last_result_; + } + + private: + void OnCreateArchiveDone(OfflinePageArchiver* archiver, + OfflinePageArchiver::ArchiverResult result, + const GURL& url, + const base::string16& title, + const base::FilePath& file_path, + int64 file_size); + + OfflinePageWebContentsObserver* web_contents_observer_; // Not owned. + scoped_ptr<TestMHTMLArchiver> archiver_; + OfflinePageArchiver::ArchiverResult last_result_; + + DISALLOW_COPY_AND_ASSIGN(OfflinePageWebContentsObserverTest); +}; + +OfflinePageWebContentsObserverTest::OfflinePageWebContentsObserverTest() + : last_result_(OfflinePageArchiver::ArchiverResult:: + ERROR_ARCHIVE_CREATION_FAILED) { +} + +OfflinePageWebContentsObserverTest::~OfflinePageWebContentsObserverTest() { +} + +void OfflinePageWebContentsObserverTest::SetUp() { + content::RenderViewHostTestHarness::SetUp(); + OfflinePageWebContentsObserver::CreateForWebContents(web_contents()); + web_contents_observer_ = + OfflinePageWebContentsObserver::FromWebContents(web_contents()); + ASSERT_FALSE(web_contents_observer_->is_document_loaded_in_main_frame()); +} + +void OfflinePageWebContentsObserverTest::TearDown() { + archiver_.reset(); + content::RenderViewHostTestHarness::TearDown(); +} + +void OfflinePageWebContentsObserverTest::CreateArchive( + const GURL& url, + const base::string16& title) { + archiver_.reset(new TestMHTMLArchiver( + web_contents(), url, title, base::FilePath(kTestFilePath))); + archiver_->CreateArchive( + base::Bind(&OfflinePageWebContentsObserverTest::OnCreateArchiveDone, + base::Unretained(this))); +} + +void OfflinePageWebContentsObserverTest::OnCreateArchiveDone( + OfflinePageArchiver* archiver, + OfflinePageArchiver::ArchiverResult result, + const GURL& url, + const base::string16& title, + const base::FilePath& file_path, + int64 file_size) { + last_result_ = result; +} + +void OfflinePageWebContentsObserverTest::PumpLoop() { + base::RunLoop().RunUntilIdle(); +} + +TEST_F(OfflinePageWebContentsObserverTest, LoadMainFrameBeforeCreateArchive) { + // Navigate in main frame. Document was not loaded yet. + content::LoadCommittedDetails details = content::LoadCommittedDetails(); + details.is_main_frame = true; + details.is_in_page = false; + content::FrameNavigateParams params = content::FrameNavigateParams(); + web_contents_observer()->DidNavigateMainFrame(details, params); + ASSERT_FALSE(web_contents_observer()->is_document_loaded_in_main_frame()); + + // Load document in main frame. + web_contents_observer()->DocumentLoadedInFrame(main_rfh()); + ASSERT_TRUE(web_contents_observer()->is_document_loaded_in_main_frame()); + + // Create an archive. + CreateArchive(kTestURL, kTestTitle); + + PumpLoop(); + EXPECT_EQ(OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED, + last_result()); +} + +TEST_F(OfflinePageWebContentsObserverTest, LoadMainFrameAfterCreateArchive) { + // Navigate in main frame. Document was not loaded yet. + content::LoadCommittedDetails details = content::LoadCommittedDetails(); + details.is_main_frame = true; + details.is_in_page = false; + content::FrameNavigateParams params = content::FrameNavigateParams(); + web_contents_observer()->DidNavigateMainFrame(details, params); + ASSERT_FALSE(web_contents_observer()->is_document_loaded_in_main_frame()); + + // Create an archive. Waiting for document loaded in main frame. + CreateArchive(kTestURL, kTestTitle); + + PumpLoop(); + EXPECT_NE(OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED, + last_result()); + + // Load document in main frame. + web_contents_observer()->DocumentLoadedInFrame(main_rfh()); + ASSERT_TRUE(web_contents_observer()->is_document_loaded_in_main_frame()); + + PumpLoop(); + EXPECT_EQ(OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED, + last_result()); +} + +TEST_F(OfflinePageWebContentsObserverTest, ResetOnPageNavigation) { + // Navigate in main frame. Document was not loaded yet. + content::LoadCommittedDetails details = content::LoadCommittedDetails(); + details.is_main_frame = true; + details.is_in_page = false; + content::FrameNavigateParams params = content::FrameNavigateParams(); + web_contents_observer()->DidNavigateMainFrame(details, params); + ASSERT_FALSE(web_contents_observer()->is_document_loaded_in_main_frame()); + + // Load document in main frame. + web_contents_observer()->DocumentLoadedInFrame(main_rfh()); + ASSERT_TRUE(web_contents_observer()->is_document_loaded_in_main_frame()); + + // Another navigation should result in waiting for a page load. + web_contents_observer()->DidNavigateMainFrame(details, params); + ASSERT_FALSE(web_contents_observer()->is_document_loaded_in_main_frame()); + + // Create an archive. Waiting for document loaded in main frame. + CreateArchive(kTestURL, kTestTitle); + + PumpLoop(); + EXPECT_NE(OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED, + last_result()); + + // Load document in main frame. + web_contents_observer()->DocumentLoadedInFrame(main_rfh()); + ASSERT_TRUE(web_contents_observer()->is_document_loaded_in_main_frame()); + + PumpLoop(); + EXPECT_EQ(OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED, + last_result()); +} + +} // namespace offline_pages diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index c5e09f0..2d57807 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc @@ -48,6 +48,7 @@ #include "content/public/browser/web_contents.h" #if defined(OS_ANDROID) +#include "chrome/browser/android/offline_pages/offline_page_web_contents_observer.h" #include "chrome/browser/android/voice_search_tab_helper.h" #include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h" #include "chrome/browser/ui/android/context_menu_helper.h" @@ -175,6 +176,8 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) { #if defined(OS_ANDROID) ContextMenuHelper::CreateForWebContents(web_contents); + offline_pages::OfflinePageWebContentsObserver::CreateForWebContents( + web_contents); SingleTabModeTabHelper::CreateForWebContents(web_contents); VoiceSearchTabHelper::CreateForWebContents(web_contents); WindowAndroidHelper::CreateForWebContents(web_contents); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 4bc0c3a..2364f2a 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1366,6 +1366,8 @@ 'browser/android/offline_pages/offline_page_mhtml_archiver.h', 'browser/android/offline_pages/offline_page_model_factory.cc', 'browser/android/offline_pages/offline_page_model_factory.h', + 'browser/android/offline_pages/offline_page_web_contents_observer.cc', + 'browser/android/offline_pages/offline_page_web_contents_observer.h', ], 'chrome_browser_browser_process_sources': [ 'browser/browser_process.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index edd9868..6146688 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -1643,6 +1643,7 @@ # Sources for Offline pages. For now only for Android. 'chrome_unit_tests_offline_pages_sources': [ 'browser/android/offline_pages/offline_page_mhtml_archiver_unittest.cc', + 'browser/android/offline_pages/offline_page_web_contents_observer_unittest.cc', ], }, 'targets': [ |