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