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.
5 #include "base/files/file_path.h"
6 #include "base/files/file_util.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/browser/webdata/autofill_entry.h"
24 #include "components/autofill/core/common/password_form.h"
25 #include "components/search_engines/template_url.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 // TODO(estade): some of these are disabled on mac. http://crbug.com/48007
29 // TODO(jschuh): Disabled on Win64 build. http://crbug.com/179688
30 #if defined(OS_MACOSX) || (defined(OS_WIN) && defined(ARCH_CPU_X86_64))
31 #define MAYBE_IMPORTER(x) DISABLED_##x
33 #define MAYBE_IMPORTER(x) x
42 const char* username_element
;
44 const char* password_element
;
50 const wchar_t* keyword_in_sqlite
;
51 const wchar_t* keyword_in_json
;
55 struct AutofillFormDataInfo
{
60 const BookmarkInfo kFirefoxBookmarks
[] = {
61 {true, 1, {"Bookmarks Toolbar"},
66 "http://www.google.com/"},
69 const PasswordInfo kFirefoxPasswords
[] = {
70 {"http://localhost:8080/", "http://localhost:8080/", "http://localhost:8080/",
71 "loginuser", "abc", "loginpass", "123", false},
72 {"http://localhost:8080/", "", "http://localhost:8080/localhost",
73 "", "http", "", "Http1+1abcdefg", false},
76 const KeywordInfo kFirefoxKeywords
[] = {
77 {L
"amazon.com", L
"amazon.com",
78 "http://www.amazon.com/exec/obidos/external-search/?field-keywords="
79 "{searchTerms}&mode=blended"},
80 {L
"answers.com", L
"answers.com",
81 "http://www.answers.com/main/ntquery?s={searchTerms}&gwp=13"},
82 {L
"search.creativecommons.org", L
"search.creativecommons.org",
83 "http://search.creativecommons.org/?q={searchTerms}"},
84 {L
"search.ebay.com", L
"search.ebay.com",
85 "http://search.ebay.com/search/search.dll?query={searchTerms}&"
86 "MfcISAPICommand=GetResult&ht=1&ebaytag1=ebayreg&srchdesc=n&"
87 "maxRecordsReturned=300&maxRecordsPerPage=50&SortProperty=MetaEndSort"},
88 {L
"google.com", L
"google.com",
89 "http://www.google.com/search?q={searchTerms}&ie=utf-8&oe=utf-8&aq=t"},
90 {L
"en.wikipedia.org", L
"wiki",
91 "http://en.wikipedia.org/wiki/Special:Search?search={searchTerms}"},
92 {L
"search.yahoo.com", L
"search.yahoo.com",
93 "http://search.yahoo.com/search?p={searchTerms}&ei=UTF-8"},
94 {L
"flickr.com", L
"flickr.com",
95 "http://www.flickr.com/photos/tags/?q={searchTerms}"},
96 {L
"imdb.com", L
"imdb.com", "http://www.imdb.com/find?q={searchTerms}"},
97 {L
"webster.com", L
"webster.com",
98 "http://www.webster.com/cgi-bin/dictionary?va={searchTerms}"},
100 {L
"\x4E2D\x6587", L
"\x4E2D\x6587", "http://www.google.com/"},
103 const AutofillFormDataInfo kFirefoxAutofillEntries
[] = {
105 {"address", "#123 Cherry Ave"},
106 {"city", "Mountain View"},
108 {"n300", "+1 (408) 871-4567"},
111 {"address", "télévision@example.com"},
112 {"city", "&$%$$$ TESTO *&*&^&^& MOKO"},
113 {"zip", "WOHOOOO$$$$$$$$****"},
114 {"n300", "\xe0\xa4\x9f\xe2\x97\x8c\xe0\xa4\xbe\xe0\xa4\xaf\xe0\xa4\xb0"},
115 {"n300", "\xe4\xbb\xa5\xe7\x8e\xa9\xe4\xb8\xba\xe4\xb8\xbb"}
118 class FirefoxObserver
: public ProfileWriter
,
119 public importer::ImporterProgressObserver
{
121 explicit FirefoxObserver(bool use_keyword_in_json
)
122 : ProfileWriter(NULL
),
127 use_keyword_in_json_(use_keyword_in_json
) {}
129 // importer::ImporterProgressObserver:
130 virtual void ImportStarted() OVERRIDE
{}
131 virtual void ImportItemStarted(importer::ImportItem item
) OVERRIDE
{}
132 virtual void ImportItemEnded(importer::ImportItem item
) OVERRIDE
{}
133 virtual void ImportEnded() OVERRIDE
{
134 base::MessageLoop::current()->Quit();
135 EXPECT_EQ(arraysize(kFirefoxBookmarks
), bookmark_count_
);
136 EXPECT_EQ(1U, history_count_
);
137 EXPECT_EQ(arraysize(kFirefoxPasswords
), password_count_
);
138 EXPECT_EQ(arraysize(kFirefoxKeywords
), keyword_count_
);
141 virtual bool BookmarkModelIsLoaded() const OVERRIDE
{
142 // Profile is ready for writing.
146 virtual bool TemplateURLServiceIsLoaded() const OVERRIDE
{
150 virtual void AddPasswordForm(const autofill::PasswordForm
& form
) OVERRIDE
{
151 PasswordInfo p
= kFirefoxPasswords
[password_count_
];
152 EXPECT_EQ(p
.origin
, form
.origin
.spec());
153 EXPECT_EQ(p
.realm
, form
.signon_realm
);
154 EXPECT_EQ(p
.action
, form
.action
.spec());
155 EXPECT_EQ(base::ASCIIToUTF16(p
.username_element
), form
.username_element
);
156 EXPECT_EQ(base::ASCIIToUTF16(p
.username
), form
.username_value
);
157 EXPECT_EQ(base::ASCIIToUTF16(p
.password_element
), form
.password_element
);
158 EXPECT_EQ(base::ASCIIToUTF16(p
.password
), form
.password_value
);
159 EXPECT_EQ(p
.blacklisted
, form
.blacklisted_by_user
);
163 virtual void AddHistoryPage(const history::URLRows
& page
,
164 history::VisitSource visit_source
) OVERRIDE
{
165 ASSERT_EQ(3U, page
.size());
166 EXPECT_EQ("http://www.google.com/", page
[0].url().spec());
167 EXPECT_EQ(base::ASCIIToUTF16("Google"), page
[0].title());
168 EXPECT_EQ("http://www.google.com/", page
[1].url().spec());
169 EXPECT_EQ(base::ASCIIToUTF16("Google"), page
[1].title());
170 EXPECT_EQ("http://www.cs.unc.edu/~jbs/resources/perl/perl-cgi/programs/"
171 "form1-POST.html", page
[2].url().spec());
172 EXPECT_EQ(base::ASCIIToUTF16("example form (POST)"), page
[2].title());
173 EXPECT_EQ(history::SOURCE_FIREFOX_IMPORTED
, visit_source
);
177 virtual void AddBookmarks(
178 const std::vector
<ImportedBookmarkEntry
>& bookmarks
,
179 const base::string16
& top_level_folder_name
) OVERRIDE
{
180 ASSERT_LE(bookmark_count_
+ bookmarks
.size(), arraysize(kFirefoxBookmarks
));
181 // Importer should import the FF favorites the same as the list, in the same
183 for (size_t i
= 0; i
< bookmarks
.size(); ++i
) {
184 EXPECT_NO_FATAL_FAILURE(
185 TestEqualBookmarkEntry(bookmarks
[i
],
186 kFirefoxBookmarks
[bookmark_count_
])) << i
;
191 virtual void AddAutofillFormDataEntries(
192 const std::vector
<autofill::AutofillEntry
>& autofill_entries
) OVERRIDE
{
193 EXPECT_EQ(arraysize(kFirefoxAutofillEntries
), autofill_entries
.size());
194 for (size_t i
= 0; i
< arraysize(kFirefoxAutofillEntries
); ++i
) {
195 EXPECT_EQ(kFirefoxAutofillEntries
[i
].name
,
196 base::UTF16ToUTF8(autofill_entries
[i
].key().name()));
197 EXPECT_EQ(kFirefoxAutofillEntries
[i
].value
,
198 base::UTF16ToUTF8(autofill_entries
[i
].key().value()));
202 virtual void AddKeywords(ScopedVector
<TemplateURL
> template_urls
,
203 bool unique_on_host_and_path
) OVERRIDE
{
204 for (size_t i
= 0; i
< template_urls
.size(); ++i
) {
205 // The order might not be deterministic, look in the expected list for
206 // that template URL.
208 const base::string16
& imported_keyword
= template_urls
[i
]->keyword();
209 for (size_t j
= 0; j
< arraysize(kFirefoxKeywords
); ++j
) {
210 const base::string16 expected_keyword
= base::WideToUTF16(
211 use_keyword_in_json_
?
212 kFirefoxKeywords
[j
].keyword_in_json
:
213 kFirefoxKeywords
[j
].keyword_in_sqlite
);
214 if (imported_keyword
== expected_keyword
) {
215 EXPECT_EQ(kFirefoxKeywords
[j
].url
, template_urls
[i
]->url());
225 virtual void AddFavicons(
226 const std::vector
<ImportedFaviconUsage
>& favicons
) OVERRIDE
{
230 virtual ~FirefoxObserver() {}
232 size_t bookmark_count_
;
233 size_t history_count_
;
234 size_t password_count_
;
235 size_t keyword_count_
;
237 // Newer versions of Firefox can store custom keyword names in json, which
238 // override the sqlite values. To be able to test both older and newer
239 // versions, tests set this variable to indicate whether to expect the
240 // |keyword_in_sqlite| or |keyword_in_json| values from the reference data.
241 bool use_keyword_in_json_
;
246 // These tests need to be browser tests in order to be able to run the OOP
247 // import (via ExternalProcessImporterHost) which launches a utility process on
248 // supported platforms.
249 class FirefoxProfileImporterBrowserTest
: public InProcessBrowserTest
{
251 virtual void SetUp() OVERRIDE
{
252 // Creates a new profile in a new subdirectory in the temp directory.
253 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
254 base::FilePath test_path
= temp_dir_
.path().AppendASCII("ImporterTest");
255 base::DeleteFile(test_path
, true);
256 base::CreateDirectory(test_path
);
257 profile_path_
= test_path
.AppendASCII("profile");
258 app_path_
= test_path
.AppendASCII("app");
259 base::CreateDirectory(app_path_
);
261 // This will launch the browser test and thus needs to happen last.
262 InProcessBrowserTest::SetUp();
265 void FirefoxImporterBrowserTest(std::string profile_dir
,
266 importer::ImporterProgressObserver
* observer
,
267 ProfileWriter
* writer
) {
268 base::FilePath data_path
;
269 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA
, &data_path
));
270 data_path
= data_path
.AppendASCII(profile_dir
);
271 ASSERT_TRUE(base::CopyDirectory(data_path
, profile_path_
, true));
273 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA
, &data_path
));
274 data_path
= data_path
.AppendASCII("firefox3_nss");
275 ASSERT_TRUE(base::CopyDirectory(data_path
, profile_path_
, false));
277 // Create a directory to house default search engines.
278 base::FilePath default_search_engine_path
=
279 app_path_
.AppendASCII("searchplugins");
280 base::CreateDirectory(default_search_engine_path
);
282 // Create a directory to house custom/installed search engines.
283 base::FilePath custom_search_engine_path
=
284 profile_path_
.AppendASCII("searchplugins");
285 base::CreateDirectory(custom_search_engine_path
);
287 // Copy over search engines.
288 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA
, &data_path
));
289 data_path
= data_path
.AppendASCII("firefox_searchplugins");
290 base::FilePath default_search_engine_source_path
=
291 data_path
.AppendASCII("default");
292 base::FilePath custom_search_engine_source_path
=
293 data_path
.AppendASCII("custom");
294 ASSERT_TRUE(base::CopyDirectory(
295 default_search_engine_source_path
, default_search_engine_path
, false));
296 ASSERT_TRUE(base::CopyDirectory(
297 custom_search_engine_source_path
, custom_search_engine_path
, false));
299 importer::SourceProfile source_profile
;
300 source_profile
.importer_type
= importer::TYPE_FIREFOX
;
301 source_profile
.app_path
= app_path_
;
302 source_profile
.source_path
= profile_path_
;
303 source_profile
.locale
= "en-US";
305 int items
= importer::HISTORY
| importer::PASSWORDS
| importer::FAVORITES
|
306 importer::SEARCH_ENGINES
| importer::AUTOFILL_FORM_DATA
;
309 ExternalProcessImporterHost
* host
= new ExternalProcessImporterHost
;
310 host
->set_observer(observer
);
311 host
->StartImportSettings(
312 source_profile
, browser()->profile(), items
, writer
);
313 base::MessageLoop::current()->Run();
316 base::ScopedTempDir temp_dir_
;
317 base::FilePath profile_path_
;
318 base::FilePath app_path_
;
321 IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest
,
322 MAYBE_IMPORTER(Firefox30Importer
)) {
323 scoped_refptr
<FirefoxObserver
> observer(new FirefoxObserver(false));
324 FirefoxImporterBrowserTest(
325 "firefox3_profile", observer
.get(), observer
.get());
328 IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest
,
329 MAYBE_IMPORTER(Firefox35Importer
)) {
330 scoped_refptr
<FirefoxObserver
> observer(new FirefoxObserver(false));
331 FirefoxImporterBrowserTest(
332 "firefox35_profile", observer
.get(), observer
.get());
335 IN_PROC_BROWSER_TEST_F(FirefoxProfileImporterBrowserTest
,
336 MAYBE_IMPORTER(FirefoxImporter
)) {
337 scoped_refptr
<FirefoxObserver
> observer(new FirefoxObserver(true));
338 FirefoxImporterBrowserTest("firefox_profile", observer
.get(), observer
.get());