firefox_importer_browsertest.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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/ui/browser.h"
18#include "chrome/common/chrome_paths.h"
19#include "chrome/common/importer/imported_bookmark_entry.h"
20#include "chrome/common/importer/imported_favicon_usage.h"
21#include "chrome/common/importer/importer_data_types.h"
22#include "chrome/test/base/in_process_browser_test.h"
23#include "components/autofill/core/common/password_form.h"
24#include "components/search_engines/template_url.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 char* username_element;
42  const char* username;
43  const char* password_element;
44  const char* 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, {"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    "loginuser", "abc", "loginpass", "123", false},
65  {"http://localhost:8080/", "", "http://localhost:8080/localhost",
66    "", "http", "", "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),
102        bookmark_count_(0),
103        history_count_(0),
104        password_count_(0),
105        keyword_count_(0) {}
106
107  // importer::ImporterProgressObserver:
108  virtual void ImportStarted() OVERRIDE {}
109  virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
110  virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
111  virtual void ImportEnded() OVERRIDE {
112    base::MessageLoop::current()->Quit();
113    EXPECT_EQ(arraysize(kFirefoxBookmarks), bookmark_count_);
114    EXPECT_EQ(1U, history_count_);
115    EXPECT_EQ(arraysize(kFirefoxPasswords), password_count_);
116    EXPECT_EQ(arraysize(kFirefoxKeywords), keyword_count_);
117  }
118
119  virtual bool BookmarkModelIsLoaded() const OVERRIDE {
120    // Profile is ready for writing.
121    return true;
122  }
123
124  virtual bool TemplateURLServiceIsLoaded() const OVERRIDE {
125    return true;
126  }
127
128  virtual void AddPasswordForm(const autofill::PasswordForm& form) OVERRIDE {
129    PasswordInfo p = kFirefoxPasswords[password_count_];
130    EXPECT_EQ(p.origin, form.origin.spec());
131    EXPECT_EQ(p.realm, form.signon_realm);
132    EXPECT_EQ(p.action, form.action.spec());
133    EXPECT_EQ(base::ASCIIToUTF16(p.username_element), form.username_element);
134    EXPECT_EQ(base::ASCIIToUTF16(p.username), form.username_value);
135    EXPECT_EQ(base::ASCIIToUTF16(p.password_element), form.password_element);
136    EXPECT_EQ(base::ASCIIToUTF16(p.password), form.password_value);
137    EXPECT_EQ(p.blacklisted, form.blacklisted_by_user);
138    ++password_count_;
139  }
140
141  virtual void AddHistoryPage(const history::URLRows& page,
142                              history::VisitSource visit_source) OVERRIDE {
143    ASSERT_EQ(3U, page.size());
144    EXPECT_EQ("http://www.google.com/", page[0].url().spec());
145    EXPECT_EQ(base::ASCIIToUTF16("Google"), page[0].title());
146    EXPECT_EQ("http://www.google.com/", page[1].url().spec());
147    EXPECT_EQ(base::ASCIIToUTF16("Google"), page[1].title());
148    EXPECT_EQ("http://www.cs.unc.edu/~jbs/resources/perl/perl-cgi/programs/"
149              "form1-POST.html", page[2].url().spec());
150    EXPECT_EQ(base::ASCIIToUTF16("example form (POST)"), page[2].title());
151    EXPECT_EQ(history::SOURCE_FIREFOX_IMPORTED, visit_source);
152    ++history_count_;
153  }
154
155  virtual void AddBookmarks(
156      const std::vector<ImportedBookmarkEntry>& bookmarks,
157      const base::string16& top_level_folder_name) OVERRIDE {
158    ASSERT_LE(bookmark_count_ + bookmarks.size(), arraysize(kFirefoxBookmarks));
159    // Importer should import the FF favorites the same as the list, in the same
160    // order.
161    for (size_t i = 0; i < bookmarks.size(); ++i) {
162      EXPECT_NO_FATAL_FAILURE(
163          TestEqualBookmarkEntry(bookmarks[i],
164                                 kFirefoxBookmarks[bookmark_count_])) << i;
165      ++bookmark_count_;
166    }
167  }
168
169  virtual void AddKeywords(ScopedVector<TemplateURL> template_urls,
170                           bool unique_on_host_and_path) OVERRIDE {
171    for (size_t i = 0; i < template_urls.size(); ++i) {
172      // The order might not be deterministic, look in the expected list for
173      // that template URL.
174      bool found = false;
175      const base::string16& keyword = template_urls[i]->keyword();
176      for (size_t j = 0; j < arraysize(kFirefoxKeywords); ++j) {
177        if (keyword == base::WideToUTF16(kFirefoxKeywords[j].keyword)) {
178          EXPECT_EQ(kFirefoxKeywords[j].url, template_urls[i]->url());
179          found = true;
180          break;
181        }
182      }
183      EXPECT_TRUE(found);
184      ++keyword_count_;
185    }
186  }
187
188  virtual void AddFavicons(
189      const std::vector<ImportedFaviconUsage>& favicons) OVERRIDE {
190  }
191
192 private:
193  virtual ~FirefoxObserver() {}
194
195  size_t bookmark_count_;
196  size_t history_count_;
197  size_t password_count_;
198  size_t keyword_count_;
199};
200
201}  // namespace
202
203// These tests need to be browser tests in order to be able to run the OOP
204// import (via ExternalProcessImporterHost) which launches a utility process on
205// supported platforms.
206class FirefoxProfileImporterBrowserTest : public InProcessBrowserTest {
207 protected:
208  virtual void SetUp() OVERRIDE {
209    // Creates a new profile in a new subdirectory in the temp directory.
210    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
211    base::FilePath test_path = temp_dir_.path().AppendASCII("ImporterTest");
212    base::DeleteFile(test_path, true);
213    base::CreateDirectory(test_path);
214    profile_path_ = test_path.AppendASCII("profile");
215    app_path_ = test_path.AppendASCII("app");
216    base::CreateDirectory(app_path_);
217
218    // This will launch the browser test and thus needs to happen last.
219    InProcessBrowserTest::SetUp();
220  }
221
222  void FirefoxImporterBrowserTest(std::string profile_dir,
223                                  importer::ImporterProgressObserver* observer,
224                                  ProfileWriter* writer) {
225    base::FilePath data_path;
226    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
227    data_path = data_path.AppendASCII(profile_dir);
228    ASSERT_TRUE(base::CopyDirectory(data_path, profile_path_, true));
229
230    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
231    data_path = data_path.AppendASCII("firefox3_nss");
232    ASSERT_TRUE(base::CopyDirectory(data_path, profile_path_, false));
233
234    // Create a directory to house default search engines.
235    base::FilePath default_search_engine_path =
236        app_path_.AppendASCII("searchplugins");
237    base::CreateDirectory(default_search_engine_path);
238
239    // Create a directory to house custom/installed search engines.
240    base::FilePath custom_search_engine_path =
241        profile_path_.AppendASCII("searchplugins");
242    base::CreateDirectory(custom_search_engine_path);
243
244    // Copy over search engines.
245    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
246    data_path = data_path.AppendASCII("firefox_searchplugins");
247    base::FilePath default_search_engine_source_path =
248        data_path.AppendASCII("default");
249    base::FilePath custom_search_engine_source_path =
250        data_path.AppendASCII("custom");
251    ASSERT_TRUE(base::CopyDirectory(
252        default_search_engine_source_path, default_search_engine_path, false));
253    ASSERT_TRUE(base::CopyDirectory(
254        custom_search_engine_source_path, custom_search_engine_path, false));
255
256    importer::SourceProfile source_profile;
257    source_profile.importer_type = importer::TYPE_FIREFOX;
258    source_profile.app_path = app_path_;
259    source_profile.source_path = profile_path_;
260    source_profile.locale = "en-US";
261
262    int items = importer::HISTORY | importer::PASSWORDS | importer::FAVORITES |
263                importer::SEARCH_ENGINES;
264
265    // Deletes itself.
266    ExternalProcessImporterHost* host = new ExternalProcessImporterHost;
267    host->set_observer(observer);
268    host->StartImportSettings(
269        source_profile, browser()->profile(), items, writer);
270    base::MessageLoop::current()->Run();
271  }
272
273  base::ScopedTempDir temp_dir_;
274  base::FilePath profile_path_;
275  base::FilePath app_path_;
276};
277
278IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest,
279                       MAYBE_IMPORTER(Firefox30Importer)) {
280  scoped_refptr<FirefoxObserver> observer(new FirefoxObserver());
281  FirefoxImporterBrowserTest(
282      "firefox3_profile", observer.get(), observer.get());
283}
284
285IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest,
286                       MAYBE_IMPORTER(Firefox35Importer)) {
287  scoped_refptr<FirefoxObserver> observer(new FirefoxObserver());
288  FirefoxImporterBrowserTest(
289      "firefox35_profile", observer.get(), observer.get());
290}
291
292IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest,
293                       MAYBE_IMPORTER(FirefoxImporter)) {
294  scoped_refptr<FirefoxObserver> observer(new FirefoxObserver());
295  FirefoxImporterBrowserTest("firefox_profile", observer.get(), observer.get());
296}
297