firefox_importer_browsertest.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
1// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/file_util.h" 6#include "base/files/file_path.h" 7#include "base/files/scoped_temp_dir.h" 8#include "base/message_loop/message_loop.h" 9#include "base/path_service.h" 10#include "base/stl_util.h" 11#include "base/strings/string16.h" 12#include "base/strings/string_util.h" 13#include "base/strings/utf_string_conversions.h" 14#include "chrome/browser/importer/external_process_importer_host.h" 15#include "chrome/browser/importer/importer_progress_observer.h" 16#include "chrome/browser/importer/importer_unittest_utils.h" 17#include "chrome/browser/search_engines/template_url.h" 18#include "chrome/browser/ui/browser.h" 19#include "chrome/common/chrome_paths.h" 20#include "chrome/common/importer/imported_bookmark_entry.h" 21#include "chrome/common/importer/imported_favicon_usage.h" 22#include "chrome/common/importer/importer_data_types.h" 23#include "chrome/test/base/in_process_browser_test.h" 24#include "components/autofill/core/common/password_form.h" 25#include "testing/gtest/include/gtest/gtest.h" 26 27// TODO(estade): some of these are disabled on mac. http://crbug.com/48007 28// TODO(jschuh): Disabled on Win64 build. http://crbug.com/179688 29#if defined(OS_MACOSX) || (defined(OS_WIN) && defined(ARCH_CPU_X86_64)) 30#define MAYBE_IMPORTER(x) DISABLED_##x 31#else 32#define MAYBE_IMPORTER(x) x 33#endif 34 35namespace { 36 37struct PasswordInfo { 38 const char* origin; 39 const char* action; 40 const char* realm; 41 const wchar_t* username_element; 42 const wchar_t* username; 43 const wchar_t* password_element; 44 const wchar_t* password; 45 bool blacklisted; 46}; 47 48struct KeywordInfo { 49 const wchar_t* keyword; 50 const char* url; 51}; 52 53const BookmarkInfo kFirefoxBookmarks[] = { 54 {true, 1, {L"Bookmarks Toolbar"}, 55 L"Toolbar", 56 "http://site/"}, 57 {false, 0, {}, 58 L"Title", 59 "http://www.google.com/"}, 60}; 61 62const PasswordInfo kFirefoxPasswords[] = { 63 {"http://localhost:8080/", "http://localhost:8080/", "http://localhost:8080/", 64 L"loginuser", L"abc", L"loginpass", L"123", false}, 65 {"http://localhost:8080/", "", "http://localhost:8080/localhost", 66 L"", L"http", L"", L"Http1+1abcdefg", false}, 67}; 68 69const KeywordInfo kFirefoxKeywords[] = { 70 { L"amazon.com", 71 "http://www.amazon.com/exec/obidos/external-search/?field-keywords=" 72 "{searchTerms}&mode=blended" }, 73 { L"answers.com", 74 "http://www.answers.com/main/ntquery?s={searchTerms}&gwp=13" }, 75 { L"search.creativecommons.org", 76 "http://search.creativecommons.org/?q={searchTerms}" }, 77 { L"search.ebay.com", 78 "http://search.ebay.com/search/search.dll?query={searchTerms}&" 79 "MfcISAPICommand=GetResult&ht=1&ebaytag1=ebayreg&srchdesc=n&" 80 "maxRecordsReturned=300&maxRecordsPerPage=50&SortProperty=MetaEndSort" }, 81 { L"google.com", 82 "http://www.google.com/search?q={searchTerms}&ie=utf-8&oe=utf-8&aq=t" }, 83 { L"en.wikipedia.org", 84 "http://en.wikipedia.org/wiki/Special:Search?search={searchTerms}" }, 85 { L"search.yahoo.com", 86 "http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8" }, 87 { L"flickr.com", 88 "http://www.flickr.com/photos/tags/?q={searchTerms}" }, 89 { L"imdb.com", 90 "http://www.imdb.com/find?q={searchTerms}" }, 91 { L"webster.com", 92 "http://www.webster.com/cgi-bin/dictionary?va={searchTerms}" }, 93 // Search keywords. 94 { L"\x4E2D\x6587", "http://www.google.com/" }, 95}; 96 97class FirefoxObserver : public ProfileWriter, 98 public importer::ImporterProgressObserver { 99 public: 100 FirefoxObserver() 101 : ProfileWriter(NULL), bookmark_count_(0), history_count_(0), 102 password_count_(0), keyword_count_(0), import_search_engines_(true) { 103 } 104 105 explicit FirefoxObserver(bool import_search_engines) 106 : ProfileWriter(NULL), bookmark_count_(0), history_count_(0), 107 password_count_(0), keyword_count_(0), 108 import_search_engines_(import_search_engines) { 109 } 110 111 // importer::ImporterProgressObserver: 112 virtual void ImportStarted() OVERRIDE {} 113 virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {} 114 virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {} 115 virtual void ImportEnded() OVERRIDE { 116 base::MessageLoop::current()->Quit(); 117 EXPECT_EQ(arraysize(kFirefoxBookmarks), bookmark_count_); 118 EXPECT_EQ(1U, history_count_); 119 EXPECT_EQ(arraysize(kFirefoxPasswords), password_count_); 120 if (import_search_engines_) 121 EXPECT_EQ(arraysize(kFirefoxKeywords), keyword_count_); 122 } 123 124 virtual bool BookmarkModelIsLoaded() const OVERRIDE { 125 // Profile is ready for writing. 126 return true; 127 } 128 129 virtual bool TemplateURLServiceIsLoaded() const OVERRIDE { 130 return true; 131 } 132 133 virtual void AddPasswordForm(const autofill::PasswordForm& form) OVERRIDE { 134 PasswordInfo p = kFirefoxPasswords[password_count_]; 135 EXPECT_EQ(p.origin, form.origin.spec()); 136 EXPECT_EQ(p.realm, form.signon_realm); 137 EXPECT_EQ(p.action, form.action.spec()); 138 EXPECT_EQ(WideToUTF16(p.username_element), form.username_element); 139 EXPECT_EQ(WideToUTF16(p.username), form.username_value); 140 EXPECT_EQ(WideToUTF16(p.password_element), form.password_element); 141 EXPECT_EQ(WideToUTF16(p.password), form.password_value); 142 EXPECT_EQ(p.blacklisted, form.blacklisted_by_user); 143 ++password_count_; 144 } 145 146 virtual void AddHistoryPage(const history::URLRows& page, 147 history::VisitSource visit_source) OVERRIDE { 148 ASSERT_EQ(3U, page.size()); 149 EXPECT_EQ("http://www.google.com/", page[0].url().spec()); 150 EXPECT_EQ(ASCIIToUTF16("Google"), page[0].title()); 151 EXPECT_EQ("http://www.google.com/", page[1].url().spec()); 152 EXPECT_EQ(ASCIIToUTF16("Google"), page[1].title()); 153 EXPECT_EQ("http://www.cs.unc.edu/~jbs/resources/perl/perl-cgi/programs/" 154 "form1-POST.html", page[2].url().spec()); 155 EXPECT_EQ(ASCIIToUTF16("example form (POST)"), page[2].title()); 156 EXPECT_EQ(history::SOURCE_FIREFOX_IMPORTED, visit_source); 157 ++history_count_; 158 } 159 160 virtual void AddBookmarks(const std::vector<ImportedBookmarkEntry>& bookmarks, 161 const string16& top_level_folder_name) OVERRIDE { 162 ASSERT_LE(bookmark_count_ + bookmarks.size(), arraysize(kFirefoxBookmarks)); 163 // Importer should import the FF favorites the same as the list, in the same 164 // order. 165 for (size_t i = 0; i < bookmarks.size(); ++i) { 166 EXPECT_NO_FATAL_FAILURE( 167 TestEqualBookmarkEntry(bookmarks[i], 168 kFirefoxBookmarks[bookmark_count_])) << i; 169 ++bookmark_count_; 170 } 171 } 172 173 virtual void AddKeywords(ScopedVector<TemplateURL> template_urls, 174 bool unique_on_host_and_path) OVERRIDE { 175 for (size_t i = 0; i < template_urls.size(); ++i) { 176 // The order might not be deterministic, look in the expected list for 177 // that template URL. 178 bool found = false; 179 string16 keyword = template_urls[i]->keyword(); 180 for (size_t j = 0; j < arraysize(kFirefoxKeywords); ++j) { 181 if (template_urls[i]->keyword() == 182 WideToUTF16Hack(kFirefoxKeywords[j].keyword)) { 183 EXPECT_EQ(kFirefoxKeywords[j].url, template_urls[i]->url()); 184 found = true; 185 break; 186 } 187 } 188 EXPECT_TRUE(found); 189 ++keyword_count_; 190 } 191 } 192 193 virtual void AddFavicons( 194 const std::vector<ImportedFaviconUsage>& favicons) OVERRIDE { 195 } 196 197 private: 198 virtual ~FirefoxObserver() {} 199 200 size_t bookmark_count_; 201 size_t history_count_; 202 size_t password_count_; 203 size_t keyword_count_; 204 bool import_search_engines_; 205}; 206 207} // namespace 208 209// These tests need to be browser tests in order to be able to run the OOP 210// import (via ExternalProcessImporterHost) which launches a utility process on 211// supported platforms. 212class FirefoxProfileImporterBrowserTest : public InProcessBrowserTest { 213 protected: 214 virtual void SetUp() OVERRIDE { 215 // Creates a new profile in a new subdirectory in the temp directory. 216 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 217 base::FilePath test_path = temp_dir_.path().AppendASCII("ImporterTest"); 218 base::DeleteFile(test_path, true); 219 file_util::CreateDirectory(test_path); 220 profile_path_ = test_path.AppendASCII("profile"); 221 app_path_ = test_path.AppendASCII("app"); 222 file_util::CreateDirectory(app_path_); 223 224 // This will launch the browser test and thus needs to happen last. 225 InProcessBrowserTest::SetUp(); 226 } 227 228 void Firefox3xImporterBrowserTest( 229 std::string profile_dir, 230 importer::ImporterProgressObserver* observer, 231 ProfileWriter* writer, 232 bool import_search_plugins) { 233 base::FilePath data_path; 234 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 235 data_path = data_path.AppendASCII(profile_dir); 236 ASSERT_TRUE(base::CopyDirectory(data_path, profile_path_, true)); 237 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 238 data_path = data_path.AppendASCII("firefox3_nss"); 239 ASSERT_TRUE(base::CopyDirectory(data_path, profile_path_, false)); 240 241 base::FilePath search_engine_path = app_path_; 242 search_engine_path = search_engine_path.AppendASCII("searchplugins"); 243 file_util::CreateDirectory(search_engine_path); 244 if (import_search_plugins) { 245 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); 246 data_path = data_path.AppendASCII("firefox3_searchplugins"); 247 if (!base::PathExists(data_path)) { 248 // TODO(maruel): Create search test data that we can open source! 249 LOG(ERROR) << L"Missing internal test data"; 250 return; 251 } 252 ASSERT_TRUE(base::CopyDirectory(data_path, search_engine_path, false)); 253 } 254 255 importer::SourceProfile source_profile; 256 source_profile.importer_type = importer::TYPE_FIREFOX; 257 source_profile.app_path = app_path_; 258 source_profile.source_path = profile_path_; 259 source_profile.locale = "en-US"; 260 261 int items = importer::HISTORY | importer::PASSWORDS | importer::FAVORITES; 262 if (import_search_plugins) 263 items = items | importer::SEARCH_ENGINES; 264 265 // Deletes itself. 266 ExternalProcessImporterHost* host = new ExternalProcessImporterHost; 267 host->set_observer(observer); 268 host->StartImportSettings(source_profile, 269 browser()->profile(), 270 items, 271 make_scoped_refptr(writer).get()); 272 base::MessageLoop::current()->Run(); 273 } 274 275 base::ScopedTempDir temp_dir_; 276 base::FilePath profile_path_; 277 base::FilePath app_path_; 278}; 279 280IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest, 281 MAYBE_IMPORTER(Firefox30Importer)) { 282 scoped_refptr<FirefoxObserver> observer(new FirefoxObserver()); 283 Firefox3xImporterBrowserTest("firefox3_profile", observer.get(), 284 observer.get(), true); 285} 286 287IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest, 288 MAYBE_IMPORTER(Firefox35Importer)) { 289 bool import_search_engines = false; 290 scoped_refptr<FirefoxObserver> observer( 291 new FirefoxObserver(import_search_engines)); 292 Firefox3xImporterBrowserTest("firefox35_profile", observer.get(), 293 observer.get(), import_search_engines); 294} 295