1 // Copyright (c) 2011 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 <algorithm>
6 #include <vector>
7
8 #include "base/basictypes.h"
9 #include "base/command_line.h"
10 #include "base/file_path.h"
11 #include "base/file_util.h"
12 #include "base/memory/ref_counted_memory.h"
13 #include "base/memory/scoped_temp_dir.h"
14 #include "base/path_service.h"
15 #include "chrome/browser/history/history_database.h"
16 #include "chrome/browser/history/history_unittest_base.h"
17 #include "chrome/browser/history/thumbnail_database.h"
18 #include "chrome/common/chrome_constants.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/thumbnail_score.h"
21 #include "chrome/test/testing_profile.h"
22 #include "chrome/tools/profiles/thumbnail-inl.h"
23 #include "googleurl/src/gurl.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "third_party/skia/include/core/SkBitmap.h"
26 #include "ui/gfx/codec/jpeg_codec.h"
27
28 using base::Time;
29 using base::TimeDelta;
30
31 namespace history {
32
33 namespace {
34
35 // data we'll put into the thumbnail database
36 static const unsigned char blob1[] =
37 "12346102356120394751634516591348710478123649165419234519234512349134";
38 static const unsigned char blob2[] =
39 "goiwuegrqrcomizqyzkjalitbahxfjytrqvpqeroicxmnlkhlzunacxaneviawrtxcywhgef";
40 static const unsigned char blob3[] =
41 "3716871354098370776510470746794707624107647054607467847164027";
42 const double kBoringness = 0.25;
43 const double kWorseBoringness = 0.50;
44 const double kBetterBoringness = 0.10;
45 const double kTotallyBoring = 1.0;
46
47 const int64 kPage1 = 1234;
48
49 } // namespace
50
51 class ThumbnailDatabaseTest : public testing::Test {
52 public:
ThumbnailDatabaseTest()53 ThumbnailDatabaseTest() {
54 }
~ThumbnailDatabaseTest()55 ~ThumbnailDatabaseTest() {
56 }
57
58 protected:
SetUp()59 virtual void SetUp() {
60 // Get a temporary directory for the test DB files.
61 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
62
63 file_name_ = temp_dir_.path().AppendASCII("TestThumbnails.db");
64 new_file_name_ = temp_dir_.path().AppendASCII("TestFavicons.db");
65 history_db_name_ = temp_dir_.path().AppendASCII("TestHistory.db");
66 google_bitmap_.reset(
67 gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail)));
68 }
69
70 scoped_ptr<SkBitmap> google_bitmap_;
71
72 ScopedTempDir temp_dir_;
73 FilePath file_name_;
74 FilePath new_file_name_;
75 FilePath history_db_name_;
76 };
77
78 class IconMappingMigrationTest : public HistoryUnitTestBase {
79 public:
IconMappingMigrationTest()80 IconMappingMigrationTest() {
81 }
~IconMappingMigrationTest()82 ~IconMappingMigrationTest() {
83 }
84
85 protected:
SetUp()86 virtual void SetUp() {
87 profile_.reset(new TestingProfile);
88
89 FilePath data_path;
90 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
91 data_path = data_path.AppendASCII("History");
92
93 history_db_name_ = profile_->GetPath().Append(chrome::kHistoryFilename);
94 // Set up history and thumbnails as they would be before migration.
95 ASSERT_NO_FATAL_FAILURE(
96 ExecuteSQLScript(data_path.AppendASCII("history.20.sql"),
97 history_db_name_));
98 thumbnail_db_name_ =
99 profile_->GetPath().Append(chrome::kThumbnailsFilename);
100 ASSERT_NO_FATAL_FAILURE(
101 ExecuteSQLScript(data_path.AppendASCII("thumbnails.3.sql"),
102 thumbnail_db_name_));
103 }
104
105 protected:
106 FilePath history_db_name_;
107 FilePath thumbnail_db_name_;
108
109 private:
110 scoped_ptr<TestingProfile> profile_;
111 };
112
TEST_F(ThumbnailDatabaseTest,GetFaviconAfterMigrationToTopSites)113 TEST_F(ThumbnailDatabaseTest, GetFaviconAfterMigrationToTopSites) {
114 ThumbnailDatabase db;
115 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
116 db.BeginTransaction();
117
118 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
119 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
120
121 GURL url("http://google.com");
122 FaviconID id = db.AddFavicon(url, FAVICON);
123 base::Time time = base::Time::Now();
124 db.SetFavicon(id, favicon, time);
125 EXPECT_TRUE(db.RenameAndDropThumbnails(file_name_, new_file_name_));
126
127 base::Time time_out;
128 std::vector<unsigned char> favicon_out;
129 GURL url_out;
130 EXPECT_TRUE(db.GetFavicon(id, &time_out, &favicon_out, &url_out));
131 EXPECT_EQ(url, url_out);
132 EXPECT_EQ(time.ToTimeT(), time_out.ToTimeT());
133 ASSERT_EQ(data.size(), favicon_out.size());
134 EXPECT_TRUE(std::equal(data.begin(),
135 data.end(),
136 favicon_out.begin()));
137 }
138
TEST_F(ThumbnailDatabaseTest,AddIconMapping)139 TEST_F(ThumbnailDatabaseTest, AddIconMapping) {
140 ThumbnailDatabase db;
141 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
142 db.BeginTransaction();
143
144 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
145 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
146
147 GURL url("http://google.com");
148 FaviconID id = db.AddFavicon(url, TOUCH_ICON);
149 EXPECT_NE(0, id);
150 base::Time time = base::Time::Now();
151 db.SetFavicon(id, favicon, time);
152
153 EXPECT_NE(0, db.AddIconMapping(url, id));
154 std::vector<IconMapping> icon_mapping;
155 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
156 EXPECT_EQ(1u, icon_mapping.size());
157 EXPECT_EQ(url, icon_mapping.front().page_url);
158 EXPECT_EQ(id, icon_mapping.front().icon_id);
159 }
160
TEST_F(ThumbnailDatabaseTest,UpdateIconMapping)161 TEST_F(ThumbnailDatabaseTest, UpdateIconMapping) {
162 ThumbnailDatabase db;
163 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
164 db.BeginTransaction();
165
166 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
167 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
168
169 GURL url("http://google.com");
170 FaviconID id = db.AddFavicon(url, TOUCH_ICON);
171 base::Time time = base::Time::Now();
172 db.SetFavicon(id, favicon, time);
173
174 EXPECT_TRUE(0 < db.AddIconMapping(url, id));
175 std::vector<IconMapping> icon_mapping;
176 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
177 ASSERT_EQ(1u, icon_mapping.size());
178 EXPECT_EQ(url, icon_mapping.front().page_url);
179 EXPECT_EQ(id, icon_mapping.front().icon_id);
180
181 GURL url1("http://www.google.com/");
182 FaviconID new_id = db.AddFavicon(url1, TOUCH_ICON);
183 EXPECT_TRUE(db.UpdateIconMapping(icon_mapping.front().mapping_id, new_id));
184
185 icon_mapping.clear();
186 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
187 ASSERT_EQ(1u, icon_mapping.size());
188 EXPECT_EQ(url, icon_mapping.front().page_url);
189 EXPECT_EQ(new_id, icon_mapping.front().icon_id);
190 EXPECT_NE(id, icon_mapping.front().icon_id);
191 }
192
TEST_F(ThumbnailDatabaseTest,DeleteIconMappings)193 TEST_F(ThumbnailDatabaseTest, DeleteIconMappings) {
194 ThumbnailDatabase db;
195 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
196 db.BeginTransaction();
197
198 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
199 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
200
201 GURL url("http://google.com");
202 FaviconID id = db.AddFavicon(url, TOUCH_ICON);
203 base::Time time = base::Time::Now();
204 db.SetFavicon(id, favicon, time);
205 EXPECT_TRUE(0 < db.AddIconMapping(url, id));
206
207 FaviconID id2 = db.AddFavicon(url, FAVICON);
208 db.SetFavicon(id2, favicon, time);
209 EXPECT_TRUE(0 < db.AddIconMapping(url, id2));
210 ASSERT_NE(id, id2);
211
212 std::vector<IconMapping> icon_mapping;
213 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
214 ASSERT_EQ(2u, icon_mapping.size());
215 EXPECT_EQ(icon_mapping.front().icon_type, TOUCH_ICON);
216 EXPECT_TRUE(db.GetIconMappingForPageURL(url, FAVICON, NULL));
217
218 db.DeleteIconMappings(url);
219
220 EXPECT_FALSE(db.GetIconMappingsForPageURL(url, NULL));
221 EXPECT_FALSE(db.GetIconMappingForPageURL(url, FAVICON, NULL));
222 }
223
TEST_F(ThumbnailDatabaseTest,GetIconMappingsForPageURL)224 TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURL) {
225 ThumbnailDatabase db;
226 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
227 db.BeginTransaction();
228
229 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
230 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
231
232 GURL url("http://google.com");
233
234 FaviconID id1 = db.AddFavicon(url, TOUCH_ICON);
235 base::Time time = base::Time::Now();
236 db.SetFavicon(id1, favicon, time);
237 EXPECT_TRUE(0 < db.AddIconMapping(url, id1));
238
239 FaviconID id2 = db.AddFavicon(url, FAVICON);
240 EXPECT_NE(id1, id2);
241 db.SetFavicon(id2, favicon, time);
242 EXPECT_TRUE(0 < db.AddIconMapping(url, id2));
243
244 std::vector<IconMapping> icon_mapping;
245 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
246 ASSERT_EQ(2u, icon_mapping.size());
247 EXPECT_NE(icon_mapping[0].icon_id, icon_mapping[1].icon_id);
248 EXPECT_TRUE(icon_mapping[0].icon_id == id1 && icon_mapping[1].icon_id == id2);
249 }
250
TEST_F(ThumbnailDatabaseTest,UpgradeToVersion4)251 TEST_F(ThumbnailDatabaseTest, UpgradeToVersion4) {
252 ThumbnailDatabase db;
253 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
254 db.BeginTransaction();
255
256 const char* name = "favicons";
257 std::string sql;
258 sql.append("DROP TABLE IF EXISTS ");
259 sql.append(name);
260 EXPECT_TRUE(db.db_.Execute(sql.c_str()));
261
262 sql.resize(0);
263 sql.append("CREATE TABLE ");
264 sql.append(name);
265 sql.append("("
266 "id INTEGER PRIMARY KEY,"
267 "url LONGVARCHAR NOT NULL,"
268 "last_updated INTEGER DEFAULT 0,"
269 "image_data BLOB)");
270 EXPECT_TRUE(db.db_.Execute(sql.c_str()));
271
272 EXPECT_TRUE(db.UpgradeToVersion4());
273
274 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
275 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
276
277 GURL url("http://google.com");
278 FaviconID id = db.AddFavicon(url, TOUCH_ICON);
279 base::Time time = base::Time::Now();
280 db.SetFavicon(id, favicon, time);
281
282 EXPECT_TRUE(0 < db.AddIconMapping(url, id));
283 IconMapping icon_mapping;
284 EXPECT_TRUE(db.GetIconMappingForPageURL(url, TOUCH_ICON, &icon_mapping));
285 EXPECT_EQ(url, icon_mapping.page_url);
286 EXPECT_EQ(id, icon_mapping.icon_id);
287 }
288
TEST_F(ThumbnailDatabaseTest,TemporayIconMapping)289 TEST_F(ThumbnailDatabaseTest, TemporayIconMapping) {
290 ThumbnailDatabase db;
291
292 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
293
294 db.BeginTransaction();
295
296 EXPECT_TRUE(db.InitTemporaryIconMappingTable());
297
298 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
299 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
300
301 GURL url("http://google.com");
302 FaviconID id = db.AddFavicon(url, FAVICON);
303 base::Time time = base::Time::Now();
304 db.SetFavicon(id, favicon, time);
305
306 db.AddToTemporaryIconMappingTable(url, id);
307 db.CommitTemporaryIconMappingTable();
308 IconMapping icon_mapping;
309 EXPECT_TRUE(db.GetIconMappingForPageURL(url, FAVICON, &icon_mapping));
310 EXPECT_EQ(id, icon_mapping.icon_id);
311 EXPECT_EQ(url, icon_mapping.page_url);
312 }
313
TEST_F(ThumbnailDatabaseTest,GetIconMappingsForPageURLForReturnOrder)314 TEST_F(ThumbnailDatabaseTest, GetIconMappingsForPageURLForReturnOrder) {
315 ThumbnailDatabase db;
316 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
317 db.BeginTransaction();
318
319 // Add a favicon
320 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
321 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
322
323 GURL url("http://google.com");
324 FaviconID id = db.AddFavicon(url, FAVICON);
325 base::Time time = base::Time::Now();
326 db.SetFavicon(id, favicon, time);
327
328 EXPECT_NE(0, db.AddIconMapping(url, id));
329 std::vector<IconMapping> icon_mapping;
330 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
331
332 EXPECT_EQ(url, icon_mapping.front().page_url);
333 EXPECT_EQ(id, icon_mapping.front().icon_id);
334 EXPECT_EQ(FAVICON, icon_mapping.front().icon_type);
335
336 // Add a touch icon
337 std::vector<unsigned char> data2(blob2, blob2 + sizeof(blob2));
338 scoped_refptr<RefCountedBytes> favicon2(new RefCountedBytes(data));
339
340 FaviconID id2 = db.AddFavicon(url, TOUCH_ICON);
341 db.SetFavicon(id2, favicon2, time);
342 EXPECT_NE(0, db.AddIconMapping(url, id2));
343
344 icon_mapping.clear();
345 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
346
347 EXPECT_EQ(url, icon_mapping.front().page_url);
348 EXPECT_EQ(id2, icon_mapping.front().icon_id);
349 EXPECT_EQ(TOUCH_ICON, icon_mapping.front().icon_type);
350
351 // Add a touch precomposed icon
352 scoped_refptr<RefCountedBytes> favicon3(new RefCountedBytes(data2));
353
354 FaviconID id3 = db.AddFavicon(url, TOUCH_PRECOMPOSED_ICON);
355 db.SetFavicon(id3, favicon3, time);
356 EXPECT_NE(0, db.AddIconMapping(url, id3));
357
358 icon_mapping.clear();
359 EXPECT_TRUE(db.GetIconMappingsForPageURL(url, &icon_mapping));
360
361 EXPECT_EQ(url, icon_mapping.front().page_url);
362 EXPECT_EQ(id3, icon_mapping.front().icon_id);
363 EXPECT_EQ(TOUCH_PRECOMPOSED_ICON, icon_mapping.front().icon_type);
364 }
365
TEST_F(ThumbnailDatabaseTest,HasMappingFor)366 TEST_F(ThumbnailDatabaseTest, HasMappingFor) {
367 ThumbnailDatabase db;
368 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
369 db.BeginTransaction();
370
371 std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
372 scoped_refptr<RefCountedBytes> favicon(new RefCountedBytes(data));
373
374 // Add a favicon which will have icon_mappings
375 FaviconID id1 = db.AddFavicon(GURL("http://google.com"), FAVICON);
376 EXPECT_NE(id1, 0);
377 base::Time time = base::Time::Now();
378 db.SetFavicon(id1, favicon, time);
379
380 // Add another type of favicon
381 FaviconID id2 = db.AddFavicon(GURL("http://www.google.com/icon"), TOUCH_ICON);
382 EXPECT_NE(id2, 0);
383 time = base::Time::Now();
384 db.SetFavicon(id2, favicon, time);
385
386 // Add 3rd favicon
387 FaviconID id3 = db.AddFavicon(GURL("http://www.google.com/icon"), TOUCH_ICON);
388 EXPECT_NE(id3, 0);
389 time = base::Time::Now();
390 db.SetFavicon(id3, favicon, time);
391
392 // Add 2 icon mapping
393 GURL page_url("http://www.google.com");
394 EXPECT_TRUE(db.AddIconMapping(page_url, id1));
395 EXPECT_TRUE(db.AddIconMapping(page_url, id2));
396
397 EXPECT_TRUE(db.HasMappingFor(id1));
398 EXPECT_TRUE(db.HasMappingFor(id2));
399 EXPECT_FALSE(db.HasMappingFor(id3));
400
401 // Remove all mappings
402 db.DeleteIconMappings(page_url);
403 EXPECT_FALSE(db.HasMappingFor(id1));
404 EXPECT_FALSE(db.HasMappingFor(id2));
405 EXPECT_FALSE(db.HasMappingFor(id3));
406 }
407
TEST_F(IconMappingMigrationTest,TestIconMappingMigration)408 TEST_F(IconMappingMigrationTest, TestIconMappingMigration) {
409 HistoryDatabase history_db;
410 ASSERT_TRUE(history_db.db_.Open(history_db_name_));
411 history_db.BeginTransaction();
412
413 const GURL icon1 = GURL("http://www.google.com/favicon.ico");
414 const GURL icon2 = GURL("http://www.yahoo.com/favicon.ico");
415
416 ThumbnailDatabase db;
417 ASSERT_EQ(sql::INIT_OK, db.Init(thumbnail_db_name_, NULL, &history_db));
418 db.BeginTransaction();
419
420 // Migration should be done.
421 // Test one icon_mapping.
422 GURL page_url1 = GURL("http://google.com/");
423 std::vector<IconMapping> icon_mappings;
424 EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url1, &icon_mappings));
425 ASSERT_EQ(1u, icon_mappings.size());
426 EXPECT_EQ(FAVICON, icon_mappings[0].icon_type);
427 EXPECT_EQ(page_url1, icon_mappings[0].page_url);
428 EXPECT_EQ(1, icon_mappings[0].icon_id);
429 base::Time time;
430 std::vector<unsigned char> out_data;
431 GURL out_icon_url;
432 ASSERT_TRUE(db.GetFavicon(
433 icon_mappings[0].icon_id, &time, &out_data, &out_icon_url));
434 EXPECT_EQ(icon1, out_icon_url);
435
436 // Test a page which has the same icon.
437 GURL page_url3 = GURL("http://www.google.com/");
438 icon_mappings.clear();
439 EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url3, &icon_mappings));
440 ASSERT_EQ(1u, icon_mappings.size());
441 EXPECT_EQ(FAVICON, icon_mappings[0].icon_type);
442 EXPECT_EQ(page_url3, icon_mappings[0].page_url);
443 EXPECT_EQ(1, icon_mappings[0].icon_id);
444
445 // Test a icon_mapping with different IconID.
446 GURL page_url2 = GURL("http://yahoo.com/");
447 icon_mappings.clear();
448 EXPECT_TRUE(db.GetIconMappingsForPageURL(page_url2, &icon_mappings));
449 ASSERT_EQ(1u, icon_mappings.size());
450 EXPECT_EQ(FAVICON, icon_mappings[0].icon_type);
451 EXPECT_EQ(page_url2, icon_mappings[0].page_url);
452 EXPECT_EQ(2, icon_mappings[0].icon_id);
453 ASSERT_TRUE(db.GetFavicon(
454 icon_mappings[0].icon_id, &time, &out_data, &out_icon_url));
455 EXPECT_EQ(icon2, out_icon_url);
456
457 // Test a page without icon
458 GURL page_url4 = GURL("http://www.google.com/blank.html");
459 EXPECT_FALSE(db.GetIconMappingsForPageURL(page_url4, NULL));
460 }
461
462 } // namespace history
463