OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 <vector> | |
6 | |
7 #include "base/files/file_util.h" | |
8 #include "base/files/scoped_temp_dir.h" | |
9 #include "base/message_loop/message_loop.h" | |
10 #include "base/path_service.h" | |
11 #include "base/strings/string16.h" | |
12 #include "base/strings/string_util.h" | |
13 #include "base/strings/utf_string_conversions.h" | |
14 #include "base/win/registry.h" | |
15 #include "base/win/windows_version.h" | |
16 #include "chrome/browser/importer/external_process_importer_host.h" | |
17 #include "chrome/browser/importer/importer_progress_observer.h" | |
18 #include "chrome/browser/importer/importer_unittest_utils.h" | |
19 #include "chrome/browser/ui/browser.h" | |
20 #include "chrome/common/chrome_paths.h" | |
21 #include "chrome/common/importer/edge_importer_utils_win.h" | |
22 #include "chrome/common/importer/ie_importer_test_registry_overrider_win.h" | |
23 #include "chrome/common/importer/imported_bookmark_entry.h" | |
24 #include "chrome/common/importer/importer_bridge.h" | |
25 #include "chrome/common/importer/importer_data_types.h" | |
26 #include "chrome/test/base/in_process_browser_test.h" | |
27 #include "chrome/test/base/testing_profile.h" | |
28 #include "components/favicon_base/favicon_usage_data.h" | |
29 #include "testing/gtest/include/gtest/gtest.h" | |
30 #include "third_party/zlib/zlib.h" | |
31 | |
32 namespace { | |
33 | |
34 struct FaviconGroup { | |
35 const base::char16* favicon_url; | |
36 const base::char16* site_url; | |
37 }; | |
38 | |
39 class TestObserver : public ProfileWriter, | |
40 public importer::ImporterProgressObserver { | |
41 public: | |
42 explicit TestObserver(uint16 importer_items, | |
43 const std::vector<BookmarkInfo>& bookmark_entries, | |
44 const std::vector<FaviconGroup>& favicon_groups) | |
45 : ProfileWriter(NULL), | |
Ilya Sherman
2015/11/26 02:04:43
nit: nullptr
forshaw
2015/11/30 12:57:57
Acknowledged.
| |
46 bookmark_count_(0), | |
47 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.
| |
48 favicon_count_(0), | |
49 favicon_groups_(favicon_groups), | |
Ilya Sherman
2015/11/26 02:04:43
Ditto
forshaw
2015/11/30 12:57:57
Acknowledged.
| |
50 importer_items_(importer_items) {} | |
51 | |
52 // importer::ImporterProgressObserver: | |
53 void ImportStarted() override {} | |
54 void ImportItemStarted(importer::ImportItem item) override {} | |
55 void ImportItemEnded(importer::ImportItem item) override {} | |
56 void ImportEnded() override { | |
57 base::MessageLoop::current()->QuitWhenIdle(); | |
58 if (importer_items_ & importer::FAVORITES) { | |
59 EXPECT_EQ(bookmark_entries_.size(), bookmark_count_); | |
60 EXPECT_EQ(favicon_groups_.size(), favicon_count_); | |
61 } | |
62 } | |
63 | |
64 // ProfileWriter: | |
65 bool BookmarkModelIsLoaded() const override { | |
66 // Profile is ready for writing. | |
67 return true; | |
68 } | |
69 | |
70 bool TemplateURLServiceIsLoaded() const override { return true; } | |
71 | |
72 void AddBookmarks(const std::vector<ImportedBookmarkEntry>& bookmarks, | |
73 const base::string16& top_level_folder_name) override { | |
74 EXPECT_EQ(bookmark_entries_.size(), bookmarks.size()); | |
75 for (size_t i = 0; i < bookmarks.size(); ++i) { | |
76 EXPECT_NO_FATAL_FAILURE( | |
77 TestEqualBookmarkEntry(bookmarks[i], bookmark_entries_[i])) | |
78 << i; | |
79 ++bookmark_count_; | |
80 } | |
81 } | |
82 | |
83 void AddFavicons(const favicon_base::FaviconUsageDataList& usage) override { | |
84 // Importer should group the favicon information for each favicon URL. | |
85 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
| |
86 for (size_t i = 0; i < favicon_groups_.size(); ++i) { | |
87 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.
| |
88 GURL favicon_url(favicon_groups_[i].favicon_url); | |
89 std::set<GURL> urls; | |
90 urls.insert(GURL(favicon_groups_[i].site_url)); | |
91 | |
92 bool expected_favicon_url_found = false; | |
93 for (size_t j = 0; j < usage.size(); ++j) { | |
94 if (usage[j].favicon_url == favicon_url) { | |
95 EXPECT_EQ(urls, usage[j].urls); | |
96 expected_favicon_url_found = true; | |
97 break; | |
98 } | |
99 } | |
100 EXPECT_TRUE(expected_favicon_url_found); | |
101 } | |
102 favicon_count_ += usage.size(); | |
103 } | |
104 | |
105 private: | |
106 ~TestObserver() override {} | |
107 | |
108 size_t bookmark_count_; | |
109 std::vector<BookmarkInfo> bookmark_entries_; | |
110 size_t favicon_count_; | |
111 std::vector<FaviconGroup> favicon_groups_; | |
112 uint16 importer_items_; | |
Ilya Sherman
2015/11/26 02:04:43
nit: Please document these member vars.
| |
113 }; | |
114 | |
115 class ScopedGzFile { | |
Ilya Sherman
2015/11/26 02:04:43
nit: s/Gz/Gzip
| |
116 public: | |
117 explicit ScopedGzFile(const base::FilePath& gzip_file) { | |
118 gz_file_ = gzopen(base::UTF16ToUTF8(gzip_file.value()).c_str(), "rb"); | |
119 } | |
120 | |
121 ~ScopedGzFile() { | |
122 if (gz_file_) { | |
123 gzclose(gz_file_); | |
124 gz_file_ = nullptr; | |
Ilya Sherman
2015/11/26 02:04:43
nit: Why is this line needed?
| |
125 } | |
126 } | |
127 | |
128 bool IsEof() { return !!gzeof(gz_file_); } | |
129 | |
130 bool IsValid() { return gz_file_ != nullptr; } | |
131 | |
132 int Read(void* buffer, int size) { | |
133 if (!IsValid()) | |
134 return -1; | |
135 return gzread(gz_file_, buffer, size); | |
136 } | |
137 | |
138 private: | |
139 gzFile gz_file_; | |
140 | |
141 DISALLOW_COPY_AND_ASSIGN(ScopedGzFile); | |
142 }; | |
143 | |
144 bool DecompressGzipFile(const base::FilePath& gzip_file, | |
145 const base::FilePath& decompressed_file) { | |
146 const int kBufferLength = 0x1000; | |
147 ScopedGzFile input_file(gzip_file); | |
148 if (!input_file.IsValid()) { | |
149 LOG(ERROR) << "Error opening gzip file"; | |
150 return false; | |
151 } | |
152 base::File output_file(decompressed_file, | |
153 base::File::FLAG_CREATE | base::File::FLAG_WRITE); | |
154 if (!output_file.IsValid()) { | |
155 LOG(ERROR) << "Error opening output decompressed file"; | |
156 return false; | |
157 } | |
158 while (true) { | |
159 char buffer[kBufferLength]; | |
160 int bytes_read = input_file.Read(buffer, kBufferLength); | |
161 if (bytes_read > 0) { | |
162 if (output_file.WriteAtCurrentPos(buffer, bytes_read) != bytes_read) { | |
163 LOG(ERROR) << "Error writing to output file"; | |
164 return false; | |
165 } | |
166 } | |
167 if (bytes_read < kBufferLength) { | |
168 if (input_file.IsEof()) { | |
169 break; | |
170 } else { | |
171 DLOG(ERROR) << "Error decompressing gzip data"; | |
172 return false; | |
173 } | |
174 } | |
175 } | |
176 | |
177 return true; | |
178 } | |
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.
| |
179 | |
180 bool DecompressDatabase(const base::FilePath& data_path) { | |
181 base::FilePath output_file = data_path.Append( | |
182 L"DataStore\\Data\\nouser1\\120712-0049\\DBStore\\spartan.edb"); | |
183 base::FilePath gzip_file = output_file.AddExtension(L".gz"); | |
184 | |
185 return DecompressGzipFile(gzip_file, output_file); | |
186 } | |
187 | |
188 const char kDummyFaviconImageData[] = | |
189 "\x42\x4D" // Magic signature 'BM' | |
190 "\x1E\x00\x00\x00" // File size | |
191 "\x00\x00\x00\x00" // Reserved | |
192 "\x1A\x00\x00\x00" // Offset of the pixel data | |
193 "\x0C\x00\x00\x00" // Header Size | |
194 "\x01\x00\x01\x00" // Size: 1x1 | |
195 "\x01\x00" // Reserved | |
196 "\x18\x00" // 24-bits | |
197 "\x00\xFF\x00\x00"; // The pixel | |
198 | |
199 } // namespace | |
200 | |
201 // These tests need to be browser tests in order to be able to run the OOP | |
202 // import (via ExternalProcessImporterHost) which launches a utility process. | |
203 class EdgeImporterBrowserTest : public InProcessBrowserTest { | |
204 protected: | |
205 void SetUp() override { | |
206 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
Ilya Sherman
2015/11/26 02:04:43
nit: Would it be appropriate to simply call this a
| |
207 | |
208 // This will launch the browser test and thus needs to happen last. | |
209 InProcessBrowserTest::SetUp(); | |
210 } | |
211 | |
212 base::ScopedTempDir temp_dir_; | |
213 | |
214 // Overrides the default registry key for IE registry keys like favorites, | |
215 // settings, password store, etc. | |
216 IEImporterTestRegistryOverrider test_registry_overrider_; | |
217 }; | |
218 | |
219 IN_PROC_BROWSER_TEST_F(EdgeImporterBrowserTest, EdgeImporter) { | |
220 // Only verified to work with ESE library on Windows 8.1 and above. | |
221 if (base::win::GetVersion() < base::win::VERSION_WIN8_1) | |
222 return; | |
223 | |
224 const BookmarkInfo kEdgeBookmarks[] = { | |
225 {true, | |
226 2, | |
227 {"Links", "SubFolderOfLinks"}, | |
228 L"SubLink", | |
229 "http://www.links-sublink.com/"}, | |
230 {true, 1, {"Links"}, L"TheLink", "http://www.links-thelink.com/"}, | |
231 {false, 0, {}, L"Google Home Page", "http://www.google.com/"}, | |
232 {false, 0, {}, L"TheLink", "http://www.links-thelink.com/"}, | |
233 {false, 1, {"SubFolder"}, L"Title", "http://www.link.com/"}, | |
234 {false, 0, {}, L"WithPortAndQuery", "http://host:8080/cgi?q=query"}, | |
235 {false, 1, {"a"}, L"\x4E2D\x6587", "http://chinese-title-favorite/"}, | |
236 {false, 0, {}, L"SubFolder", "http://www.subfolder.com/"}, | |
237 {false, 0, {}, L"InvalidFavicon", "http://www.invalid-favicon.com/"}, | |
238 }; | |
239 std::vector<BookmarkInfo> bookmark_entries( | |
240 kEdgeBookmarks, kEdgeBookmarks + arraysize(kEdgeBookmarks)); | |
241 | |
242 const FaviconGroup kEdgeFaviconGroup[] = { | |
243 {L"http://www.links-sublink.com/favicon.ico", | |
244 L"http://www.links-sublink.com"}, | |
245 {L"http://www.links-thelink.com/favicon.ico", | |
246 L"http://www.links-thelink.com"}, | |
247 {L"http://www.google.com/favicon.ico", L"http://www.google.com"}, | |
248 {L"http://www.links-thelink.com/favicon.ico", | |
249 L"http://www.links-thelink.com"}, | |
250 {L"http://www.link.com/favicon.ico", L"http://www.link.com"}, | |
251 {L"http://host:8080/favicon.ico", L"http://host:8080/cgi?q=query"}, | |
252 {L"http://chinese-title-favorite/favicon.ico", | |
253 L"http://chinese-title-favorite"}, | |
254 {L"http://www.subfolder.com/favicon.ico", L"http://www.subfolder.com"}, | |
255 }; | |
256 | |
257 std::vector<FaviconGroup> favicon_groups( | |
258 kEdgeFaviconGroup, kEdgeFaviconGroup + arraysize(kEdgeFaviconGroup)); | |
259 | |
260 base::FilePath data_path; | |
261 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); | |
262 data_path = data_path.AppendASCII("edge_profile"); | |
263 | |
264 base::FilePath temp_path = temp_dir_.path(); | |
265 ASSERT_TRUE(base::CopyDirectory(data_path, temp_path, true)); | |
266 ASSERT_TRUE(DecompressDatabase(temp_path.AppendASCII("edge_profile"))); | |
267 | |
268 base::string16 key_path(importer::GetEdgeSettingsKey()); | |
269 base::win::RegKey key; | |
270 ASSERT_EQ(ERROR_SUCCESS, | |
271 key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE)); | |
272 key.WriteValue(L"FavoritesESEEnabled", 1); | |
273 ASSERT_FALSE(importer::IsEdgeFavoritesLegacyMode()); | |
274 | |
275 // Starts to import the above settings. | |
276 // Deletes itself. | |
277 ExternalProcessImporterHost* host = new ExternalProcessImporterHost; | |
278 TestObserver* observer = | |
279 new TestObserver(importer::FAVORITES, bookmark_entries, favicon_groups); | |
280 host->set_observer(observer); | |
281 | |
282 importer::SourceProfile source_profile; | |
283 source_profile.importer_type = importer::TYPE_EDGE; | |
284 source_profile.source_path = temp_path.AppendASCII("edge_profile"); | |
285 | |
286 host->StartImportSettings(source_profile, browser()->profile(), | |
287 importer::FAVORITES, observer); | |
288 base::MessageLoop::current()->Run(); | |
289 } | |
290 | |
291 IN_PROC_BROWSER_TEST_F(EdgeImporterBrowserTest, EdgeImporterLegacyFallback) { | |
292 const BookmarkInfo kEdgeBookmarks[] = { | |
293 {false, 0, {}, L"Google", "http://www.google.com/"}}; | |
294 std::vector<BookmarkInfo> bookmark_entries( | |
295 kEdgeBookmarks, kEdgeBookmarks + arraysize(kEdgeBookmarks)); | |
296 const FaviconGroup kEdgeFaviconGroup[] = { | |
297 {L"http://www.google.com/favicon.ico", L"http://www.google.com/"}}; | |
298 std::vector<FaviconGroup> favicon_groups( | |
299 kEdgeFaviconGroup, kEdgeFaviconGroup + arraysize(kEdgeFaviconGroup)); | |
300 | |
301 base::FilePath data_path; | |
302 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); | |
303 data_path = data_path.AppendASCII("edge_profile"); | |
304 | |
305 ASSERT_TRUE(base::CopyDirectory(data_path, temp_dir_.path(), true)); | |
306 ASSERT_TRUE(importer::IsEdgeFavoritesLegacyMode()); | |
307 | |
308 // Starts to import the above settings. | |
309 // Deletes itself. | |
310 ExternalProcessImporterHost* host = new ExternalProcessImporterHost; | |
311 TestObserver* observer = | |
312 new TestObserver(importer::FAVORITES, bookmark_entries, favicon_groups); | |
313 host->set_observer(observer); | |
314 | |
315 importer::SourceProfile source_profile; | |
316 source_profile.importer_type = importer::TYPE_EDGE; | |
317 base::FilePath source_path = temp_dir_.path().AppendASCII("edge_profile"); | |
318 ASSERT_NE(base::WriteFile( | |
319 source_path.AppendASCII("Favorites\\Google.url:favicon:$DATA"), | |
320 kDummyFaviconImageData, sizeof(kDummyFaviconImageData)), | |
321 -1); | |
322 source_profile.source_path = source_path; | |
323 | |
324 host->StartImportSettings(source_profile, browser()->profile(), | |
325 importer::FAVORITES, observer); | |
326 base::MessageLoop::current()->Run(); | |
327 } | |
328 | |
329 IN_PROC_BROWSER_TEST_F(EdgeImporterBrowserTest, EdgeImporterNoDatabase) { | |
330 // Only verified to work with ESE library on Windows 8.1 and above. | |
331 if (base::win::GetVersion() < base::win::VERSION_WIN8_1) | |
332 return; | |
333 | |
334 std::vector<BookmarkInfo> bookmark_entries; | |
335 std::vector<FaviconGroup> favicon_groups; | |
336 | |
337 base::string16 key_path(importer::GetEdgeSettingsKey()); | |
338 base::win::RegKey key; | |
339 ASSERT_EQ(ERROR_SUCCESS, | |
340 key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_WRITE)); | |
341 key.WriteValue(L"FavoritesESEEnabled", 1); | |
342 ASSERT_FALSE(importer::IsEdgeFavoritesLegacyMode()); | |
343 | |
344 // Starts to import the above settings. | |
345 // Deletes itself. | |
346 ExternalProcessImporterHost* host = new ExternalProcessImporterHost; | |
347 TestObserver* observer = | |
348 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
| |
349 host->set_observer(observer); | |
350 | |
351 importer::SourceProfile source_profile; | |
352 source_profile.importer_type = importer::TYPE_EDGE; | |
353 source_profile.source_path = temp_dir_.path(); | |
354 | |
355 host->StartImportSettings(source_profile, browser()->profile(), | |
356 importer::FAVORITES, observer); | |
357 base::MessageLoop::current()->Run(); | |
358 } | |
OLD | NEW |