Chromium Code Reviews| Index: chrome/browser/importer/edge_importer_browsertest_win.cc |
| diff --git a/chrome/browser/importer/edge_importer_browsertest_win.cc b/chrome/browser/importer/edge_importer_browsertest_win.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2e8ce8cfd8e2d9b56a583d1e2df52d1c2f162315 |
| --- /dev/null |
| +++ b/chrome/browser/importer/edge_importer_browsertest_win.cc |
| @@ -0,0 +1,358 @@ |
| +// 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 <vector> |
| + |
| +#include "base/files/file_util.h" |
| +#include "base/files/scoped_temp_dir.h" |
| +#include "base/message_loop/message_loop.h" |
| +#include "base/path_service.h" |
| +#include "base/strings/string16.h" |
| +#include "base/strings/string_util.h" |
| +#include "base/strings/utf_string_conversions.h" |
| +#include "base/win/registry.h" |
| +#include "base/win/windows_version.h" |
| +#include "chrome/browser/importer/external_process_importer_host.h" |
| +#include "chrome/browser/importer/importer_progress_observer.h" |
| +#include "chrome/browser/importer/importer_unittest_utils.h" |
| +#include "chrome/browser/ui/browser.h" |
| +#include "chrome/common/chrome_paths.h" |
| +#include "chrome/common/importer/edge_importer_utils_win.h" |
| +#include "chrome/common/importer/ie_importer_test_registry_overrider_win.h" |
| +#include "chrome/common/importer/imported_bookmark_entry.h" |
| +#include "chrome/common/importer/importer_bridge.h" |
| +#include "chrome/common/importer/importer_data_types.h" |
| +#include "chrome/test/base/in_process_browser_test.h" |
| +#include "chrome/test/base/testing_profile.h" |
| +#include "components/favicon_base/favicon_usage_data.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "third_party/zlib/zlib.h" |
| + |
| +namespace { |
| + |
| +struct FaviconGroup { |
| + const base::char16* favicon_url; |
| + const base::char16* site_url; |
| +}; |
| + |
| +class TestObserver : public ProfileWriter, |
| + public importer::ImporterProgressObserver { |
| + public: |
| + explicit TestObserver(uint16 importer_items, |
| + const std::vector<BookmarkInfo>& bookmark_entries, |
| + const std::vector<FaviconGroup>& favicon_groups) |
| + : ProfileWriter(NULL), |
|
Ilya Sherman
2015/11/26 02:04:43
nit: nullptr
forshaw
2015/11/30 12:57:57
Acknowledged.
|
| + bookmark_count_(0), |
| + bookmark_entries_(bookmark_entries), |
|
Ilya Sherman
2015/11/26 02:04:43
nit: Maybe prefix this with "expected_"?
forshaw
2015/11/30 12:57:57
Acknowledged.
|
| + favicon_count_(0), |
| + favicon_groups_(favicon_groups), |
|
Ilya Sherman
2015/11/26 02:04:43
Ditto
forshaw
2015/11/30 12:57:57
Acknowledged.
|
| + importer_items_(importer_items) {} |
| + |
| + // importer::ImporterProgressObserver: |
| + void ImportStarted() override {} |
| + void ImportItemStarted(importer::ImportItem item) override {} |
| + void ImportItemEnded(importer::ImportItem item) override {} |
| + void ImportEnded() override { |
| + base::MessageLoop::current()->QuitWhenIdle(); |
| + if (importer_items_ & importer::FAVORITES) { |
| + EXPECT_EQ(bookmark_entries_.size(), bookmark_count_); |
| + EXPECT_EQ(favicon_groups_.size(), favicon_count_); |
| + } |
| + } |
| + |
| + // ProfileWriter: |
| + bool BookmarkModelIsLoaded() const override { |
| + // Profile is ready for writing. |
| + return true; |
| + } |
| + |
| + bool TemplateURLServiceIsLoaded() const override { return true; } |
| + |
| + void AddBookmarks(const std::vector<ImportedBookmarkEntry>& bookmarks, |
| + const base::string16& top_level_folder_name) override { |
| + EXPECT_EQ(bookmark_entries_.size(), bookmarks.size()); |
| + for (size_t i = 0; i < bookmarks.size(); ++i) { |
| + EXPECT_NO_FATAL_FAILURE( |
| + TestEqualBookmarkEntry(bookmarks[i], bookmark_entries_[i])) |
| + << i; |
| + ++bookmark_count_; |
| + } |
| + } |
| + |
| + void AddFavicons(const favicon_base::FaviconUsageDataList& usage) override { |
| + // Importer should group the favicon information for each favicon URL. |
| + EXPECT_EQ(favicon_groups_.size(), usage.size()); |
|
Ilya Sherman
2015/11/26 02:04:43
nit: This seems like it should be an ASSERT_EQ, si
|
| + for (size_t i = 0; i < favicon_groups_.size(); ++i) { |
| + EXPECT_EQ(usage[i].urls.size(), 1); |
|
Ilya Sherman
2015/11/26 02:04:43
Actually, this expectation seems oddly placed -- i
Ilya Sherman
2015/11/26 02:04:43
nit: I think you might need to write "1U"
forshaw
2015/11/30 12:57:57
Acknowledged.
forshaw
2015/11/30 12:57:57
Acknowledged.
|
| + GURL favicon_url(favicon_groups_[i].favicon_url); |
| + std::set<GURL> urls; |
| + urls.insert(GURL(favicon_groups_[i].site_url)); |
| + |
| + bool expected_favicon_url_found = false; |
| + for (size_t j = 0; j < usage.size(); ++j) { |
| + if (usage[j].favicon_url == favicon_url) { |
| + EXPECT_EQ(urls, usage[j].urls); |
| + expected_favicon_url_found = true; |
| + break; |
| + } |
| + } |
| + EXPECT_TRUE(expected_favicon_url_found); |
| + } |
| + favicon_count_ += usage.size(); |
| + } |
| + |
| + private: |
| + ~TestObserver() override {} |
| + |
| + size_t bookmark_count_; |
| + std::vector<BookmarkInfo> bookmark_entries_; |
| + size_t favicon_count_; |
| + std::vector<FaviconGroup> favicon_groups_; |
| + uint16 importer_items_; |
|
Ilya Sherman
2015/11/26 02:04:43
nit: Please document these member vars.
|
| +}; |
| + |
| +class ScopedGzFile { |
|
Ilya Sherman
2015/11/26 02:04:43
nit: s/Gz/Gzip
|
| + public: |
| + explicit ScopedGzFile(const base::FilePath& gzip_file) { |
| + gz_file_ = gzopen(base::UTF16ToUTF8(gzip_file.value()).c_str(), "rb"); |
| + } |
| + |
| + ~ScopedGzFile() { |
| + if (gz_file_) { |
| + gzclose(gz_file_); |
| + gz_file_ = nullptr; |
|
Ilya Sherman
2015/11/26 02:04:43
nit: Why is this line needed?
|
| + } |
| + } |
| + |
| + bool IsEof() { return !!gzeof(gz_file_); } |
| + |
| + bool IsValid() { return gz_file_ != nullptr; } |
| + |
| + int Read(void* buffer, int size) { |
| + if (!IsValid()) |
| + return -1; |
| + return gzread(gz_file_, buffer, size); |
| + } |
| + |
| + private: |
| + gzFile gz_file_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ScopedGzFile); |
| +}; |
| + |
| +bool DecompressGzipFile(const base::FilePath& gzip_file, |
| + const base::FilePath& decompressed_file) { |
| + const int kBufferLength = 0x1000; |
| + ScopedGzFile input_file(gzip_file); |
| + if (!input_file.IsValid()) { |
| + LOG(ERROR) << "Error opening gzip file"; |
| + return false; |
| + } |
| + base::File output_file(decompressed_file, |
| + base::File::FLAG_CREATE | base::File::FLAG_WRITE); |
| + if (!output_file.IsValid()) { |
| + LOG(ERROR) << "Error opening output decompressed file"; |
| + return false; |
| + } |
| + while (true) { |
| + char buffer[kBufferLength]; |
| + int bytes_read = input_file.Read(buffer, kBufferLength); |
| + if (bytes_read > 0) { |
| + if (output_file.WriteAtCurrentPos(buffer, bytes_read) != bytes_read) { |
| + LOG(ERROR) << "Error writing to output file"; |
| + return false; |
| + } |
| + } |
| + if (bytes_read < kBufferLength) { |
| + if (input_file.IsEof()) { |
| + break; |
| + } else { |
| + DLOG(ERROR) << "Error decompressing gzip data"; |
| + return false; |
| + } |
| + } |
| + } |
| + |
| + return true; |
| +} |
|
Ilya Sherman
2015/11/26 02:04:43
Can you just slurp in the whole file and then call
forshaw
2015/11/30 12:57:57
Acknowledged.
|
| + |
| +bool DecompressDatabase(const base::FilePath& data_path) { |
| + base::FilePath output_file = data_path.Append( |
| + L"DataStore\\Data\\nouser1\\120712-0049\\DBStore\\spartan.edb"); |
| + base::FilePath gzip_file = output_file.AddExtension(L".gz"); |
| + |
| + return DecompressGzipFile(gzip_file, output_file); |
| +} |
| + |
| +const char kDummyFaviconImageData[] = |
| + "\x42\x4D" // Magic signature 'BM' |
| + "\x1E\x00\x00\x00" // File size |
| + "\x00\x00\x00\x00" // Reserved |
| + "\x1A\x00\x00\x00" // Offset of the pixel data |
| + "\x0C\x00\x00\x00" // Header Size |
| + "\x01\x00\x01\x00" // Size: 1x1 |
| + "\x01\x00" // Reserved |
| + "\x18\x00" // 24-bits |
| + "\x00\xFF\x00\x00"; // The pixel |
| + |
| +} // namespace |
| + |
| +// These tests need to be browser tests in order to be able to run the OOP |
| +// import (via ExternalProcessImporterHost) which launches a utility process. |
| +class EdgeImporterBrowserTest : public InProcessBrowserTest { |
| + protected: |
| + void SetUp() override { |
| + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
|
Ilya Sherman
2015/11/26 02:04:43
nit: Would it be appropriate to simply call this a
|
| + |
| + // This will launch the browser test and thus needs to happen last. |
| + InProcessBrowserTest::SetUp(); |
| + } |
| + |
| + base::ScopedTempDir temp_dir_; |
| + |
| + // Overrides the default registry key for IE registry keys like favorites, |
| + // settings, password store, etc. |
| + IEImporterTestRegistryOverrider test_registry_overrider_; |
| +}; |
| + |
| +IN_PROC_BROWSER_TEST_F(EdgeImporterBrowserTest, EdgeImporter) { |
| + // Only verified to work with ESE library on Windows 8.1 and above. |
| + if (base::win::GetVersion() < base::win::VERSION_WIN8_1) |
| + return; |
| + |
| + const BookmarkInfo kEdgeBookmarks[] = { |
| + {true, |
| + 2, |
| + {"Links", "SubFolderOfLinks"}, |
| + L"SubLink", |
| + "http://www.links-sublink.com/"}, |
| + {true, 1, {"Links"}, L"TheLink", "http://www.links-thelink.com/"}, |
| + {false, 0, {}, L"Google Home Page", "http://www.google.com/"}, |
| + {false, 0, {}, L"TheLink", "http://www.links-thelink.com/"}, |
| + {false, 1, {"SubFolder"}, L"Title", "http://www.link.com/"}, |
| + {false, 0, {}, L"WithPortAndQuery", "http://host:8080/cgi?q=query"}, |
| + {false, 1, {"a"}, L"\x4E2D\x6587", "http://chinese-title-favorite/"}, |
| + {false, 0, {}, L"SubFolder", "http://www.subfolder.com/"}, |
| + {false, 0, {}, L"InvalidFavicon", "http://www.invalid-favicon.com/"}, |
| + }; |
| + std::vector<BookmarkInfo> bookmark_entries( |
| + kEdgeBookmarks, kEdgeBookmarks + arraysize(kEdgeBookmarks)); |
| + |
| + const FaviconGroup kEdgeFaviconGroup[] = { |
| + {L"http://www.links-sublink.com/favicon.ico", |
| + L"http://www.links-sublink.com"}, |
| + {L"http://www.links-thelink.com/favicon.ico", |
| + L"http://www.links-thelink.com"}, |
| + {L"http://www.google.com/favicon.ico", L"http://www.google.com"}, |
| + {L"http://www.links-thelink.com/favicon.ico", |
| + L"http://www.links-thelink.com"}, |
| + {L"http://www.link.com/favicon.ico", L"http://www.link.com"}, |
| + {L"http://host:8080/favicon.ico", L"http://host:8080/cgi?q=query"}, |
| + {L"http://chinese-title-favorite/favicon.ico", |
| + L"http://chinese-title-favorite"}, |
| + {L"http://www.subfolder.com/favicon.ico", L"http://www.subfolder.com"}, |
| + }; |
| + |
| + std::vector<FaviconGroup> favicon_groups( |
| + kEdgeFaviconGroup, kEdgeFaviconGroup + arraysize(kEdgeFaviconGroup)); |
| + |
| + base::FilePath data_path; |
| + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); |
| + data_path = data_path.AppendASCII("edge_profile"); |
| + |
| + base::FilePath temp_path = temp_dir_.path(); |
| + ASSERT_TRUE(base::CopyDirectory(data_path, temp_path, true)); |
| + ASSERT_TRUE(DecompressDatabase(temp_path.AppendASCII("edge_profile"))); |
| + |
| + base::string16 key_path(importer::GetEdgeSettingsKey()); |
| + base::win::RegKey key; |
| + ASSERT_EQ(ERROR_SUCCESS, |
| + key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE)); |
| + key.WriteValue(L"FavoritesESEEnabled", 1); |
| + ASSERT_FALSE(importer::IsEdgeFavoritesLegacyMode()); |
| + |
| + // Starts to import the above settings. |
| + // Deletes itself. |
| + ExternalProcessImporterHost* host = new ExternalProcessImporterHost; |
| + TestObserver* observer = |
| + new TestObserver(importer::FAVORITES, bookmark_entries, favicon_groups); |
| + host->set_observer(observer); |
| + |
| + importer::SourceProfile source_profile; |
| + source_profile.importer_type = importer::TYPE_EDGE; |
| + source_profile.source_path = temp_path.AppendASCII("edge_profile"); |
| + |
| + host->StartImportSettings(source_profile, browser()->profile(), |
| + importer::FAVORITES, observer); |
| + base::MessageLoop::current()->Run(); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(EdgeImporterBrowserTest, EdgeImporterLegacyFallback) { |
| + const BookmarkInfo kEdgeBookmarks[] = { |
| + {false, 0, {}, L"Google", "http://www.google.com/"}}; |
| + std::vector<BookmarkInfo> bookmark_entries( |
| + kEdgeBookmarks, kEdgeBookmarks + arraysize(kEdgeBookmarks)); |
| + const FaviconGroup kEdgeFaviconGroup[] = { |
| + {L"http://www.google.com/favicon.ico", L"http://www.google.com/"}}; |
| + std::vector<FaviconGroup> favicon_groups( |
| + kEdgeFaviconGroup, kEdgeFaviconGroup + arraysize(kEdgeFaviconGroup)); |
| + |
| + base::FilePath data_path; |
| + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); |
| + data_path = data_path.AppendASCII("edge_profile"); |
| + |
| + ASSERT_TRUE(base::CopyDirectory(data_path, temp_dir_.path(), true)); |
| + ASSERT_TRUE(importer::IsEdgeFavoritesLegacyMode()); |
| + |
| + // Starts to import the above settings. |
| + // Deletes itself. |
| + ExternalProcessImporterHost* host = new ExternalProcessImporterHost; |
| + TestObserver* observer = |
| + new TestObserver(importer::FAVORITES, bookmark_entries, favicon_groups); |
| + host->set_observer(observer); |
| + |
| + importer::SourceProfile source_profile; |
| + source_profile.importer_type = importer::TYPE_EDGE; |
| + base::FilePath source_path = temp_dir_.path().AppendASCII("edge_profile"); |
| + ASSERT_NE(base::WriteFile( |
| + source_path.AppendASCII("Favorites\\Google.url:favicon:$DATA"), |
| + kDummyFaviconImageData, sizeof(kDummyFaviconImageData)), |
| + -1); |
| + source_profile.source_path = source_path; |
| + |
| + host->StartImportSettings(source_profile, browser()->profile(), |
| + importer::FAVORITES, observer); |
| + base::MessageLoop::current()->Run(); |
| +} |
| + |
| +IN_PROC_BROWSER_TEST_F(EdgeImporterBrowserTest, EdgeImporterNoDatabase) { |
| + // Only verified to work with ESE library on Windows 8.1 and above. |
| + if (base::win::GetVersion() < base::win::VERSION_WIN8_1) |
| + return; |
| + |
| + std::vector<BookmarkInfo> bookmark_entries; |
| + std::vector<FaviconGroup> favicon_groups; |
| + |
| + base::string16 key_path(importer::GetEdgeSettingsKey()); |
| + base::win::RegKey key; |
| + ASSERT_EQ(ERROR_SUCCESS, |
| + key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE)); |
| + key.WriteValue(L"FavoritesESEEnabled", 1); |
| + ASSERT_FALSE(importer::IsEdgeFavoritesLegacyMode()); |
| + |
| + // Starts to import the above settings. |
| + // Deletes itself. |
| + ExternalProcessImporterHost* host = new ExternalProcessImporterHost; |
| + TestObserver* observer = |
| + new TestObserver(importer::FAVORITES, bookmark_entries, favicon_groups); |
|
Ilya Sherman
2015/11/26 02:04:43
Who owns the memory for the observer?
forshaw
2015/11/30 12:57:57
Good question, this was basically taken from the I
|
| + host->set_observer(observer); |
| + |
| + importer::SourceProfile source_profile; |
| + source_profile.importer_type = importer::TYPE_EDGE; |
| + source_profile.source_path = temp_dir_.path(); |
| + |
| + host->StartImportSettings(source_profile, browser()->profile(), |
| + importer::FAVORITES, observer); |
| + base::MessageLoop::current()->Run(); |
| +} |