Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(329)

Side by Side Diff: chrome/browser/history/history_unittest.cc

Issue 1100763002: Inject CanAddURLToHistory into TopSitesImpl (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@prefs
Patch Set: Fix error introduced during rebase Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 // History unit tests come in two flavors:
6 //
7 // 1. The more complicated style is that the unit test creates a full history
8 // service. This spawns a background thread for the history backend, and
9 // all communication is asynchronous. This is useful for testing more
10 // complicated things or end-to-end behavior.
11 //
12 // 2. The simpler style is to create a history backend on this thread and
13 // access it directly without a HistoryService object. This is much simpler
14 // because communication is synchronous. Generally, sets should go through
15 // the history backend (since there is a lot of logic) but gets can come
16 // directly from the HistoryDatabase. This is because the backend generally
17 // has no logic in the getter except threading stuff, which we don't want
18 // to run.
19
20 #include <time.h>
21
22 #include <algorithm>
23 #include <string>
24
25 #include "base/basictypes.h"
26 #include "base/bind.h"
27 #include "base/bind_helpers.h"
28 #include "base/callback.h"
29 #include "base/command_line.h"
30 #include "base/compiler_specific.h"
31 #include "base/files/file_path.h"
32 #include "base/files/file_util.h"
33 #include "base/files/scoped_temp_dir.h"
34 #include "base/logging.h"
35 #include "base/memory/scoped_ptr.h"
36 #include "base/memory/scoped_vector.h"
37 #include "base/message_loop/message_loop.h"
38 #include "base/path_service.h"
39 #include "base/strings/string_util.h"
40 #include "base/strings/stringprintf.h"
41 #include "base/strings/utf_string_conversions.h"
42 #include "base/task/cancelable_task_tracker.h"
43 #include "base/threading/platform_thread.h"
44 #include "base/time/time.h"
45 #include "chrome/common/chrome_constants.h"
46 #include "chrome/common/chrome_paths.h"
47 #include "components/history/content/browser/download_constants_utils.h"
48 #include "components/history/content/browser/history_database_helper.h"
49 #include "components/history/core/browser/download_constants.h"
50 #include "components/history/core/browser/download_row.h"
51 #include "components/history/core/browser/history_backend.h"
52 #include "components/history/core/browser/history_constants.h"
53 #include "components/history/core/browser/history_database.h"
54 #include "components/history/core/browser/history_database_params.h"
55 #include "components/history/core/browser/history_db_task.h"
56 #include "components/history/core/browser/history_service.h"
57 #include "components/history/core/browser/in_memory_database.h"
58 #include "components/history/core/browser/in_memory_history_backend.h"
59 #include "components/history/core/browser/page_usage_data.h"
60 #include "components/history/core/common/thumbnail_score.h"
61 #include "components/history/core/test/history_unittest_base.h"
62 #include "components/history/core/test/test_history_database.h"
63 #include "components/history/core/test/thumbnail-inl.h"
64 #include "content/public/browser/download_item.h"
65 #include "content/public/browser/notification_details.h"
66 #include "content/public/browser/notification_source.h"
67 #include "sql/connection.h"
68 #include "sql/statement.h"
69 #include "sync/api/attachments/attachment_id.h"
70 #include "sync/api/fake_sync_change_processor.h"
71 #include "sync/api/sync_change.h"
72 #include "sync/api/sync_change_processor.h"
73 #include "sync/api/sync_change_processor_wrapper_for_test.h"
74 #include "sync/api/sync_error.h"
75 #include "sync/api/sync_error_factory.h"
76 #include "sync/api/sync_merge_result.h"
77 #include "sync/internal_api/public/attachments/attachment_service_proxy_for_test .h"
78 #include "sync/protocol/history_delete_directive_specifics.pb.h"
79 #include "sync/protocol/sync.pb.h"
80 #include "testing/gtest/include/gtest/gtest.h"
81 #include "third_party/skia/include/core/SkBitmap.h"
82 #include "ui/gfx/codec/jpeg_codec.h"
83
84 using base::Time;
85 using base::TimeDelta;
86 using content::DownloadItem;
87
88 namespace history {
89 class HistoryBackendDBTest;
90
91 // Delegate class for when we create a backend without a HistoryService.
92 //
93 // This must be outside the anonymous namespace for the friend statement in
94 // HistoryBackendDBTest to work.
95 class BackendDelegate : public HistoryBackend::Delegate {
96 public:
97 explicit BackendDelegate(HistoryBackendDBTest* history_test)
98 : history_test_(history_test) {
99 }
100
101 void NotifyProfileError(sql::InitStatus init_status) override {}
102 void SetInMemoryBackend(scoped_ptr<InMemoryHistoryBackend> backend) override;
103 void NotifyFaviconChanged(const std::set<GURL>& url) override {}
104 void NotifyURLVisited(ui::PageTransition transition,
105 const URLRow& row,
106 const RedirectList& redirects,
107 base::Time visit_time) override {}
108 void NotifyURLsModified(const URLRows& changed_urls) override {}
109 void NotifyURLsDeleted(bool all_history,
110 bool expired,
111 const URLRows& deleted_rows,
112 const std::set<GURL>& favicon_urls) override {}
113 void NotifyKeywordSearchTermUpdated(const URLRow& row,
114 KeywordID keyword_id,
115 const base::string16& term) override {}
116 void NotifyKeywordSearchTermDeleted(URLID url_id) override {}
117 void DBLoaded() override {}
118
119 private:
120 HistoryBackendDBTest* history_test_;
121 };
122
123 // This must be outside the anonymous namespace for the friend statement in
124 // HistoryBackend to work.
125 class HistoryBackendDBTest : public HistoryUnitTestBase {
126 public:
127 HistoryBackendDBTest() : db_(NULL) {
128 }
129
130 ~HistoryBackendDBTest() override {}
131
132 protected:
133 friend class BackendDelegate;
134
135 // Creates the HistoryBackend and HistoryDatabase on the current thread,
136 // assigning the values to backend_ and db_.
137 void CreateBackendAndDatabase() {
138 backend_ = new HistoryBackend(new BackendDelegate(this), nullptr);
139 backend_->Init(std::string(), false,
140 HistoryDatabaseParamsForPath(history_dir_));
141 db_ = backend_->db_.get();
142 DCHECK(in_mem_backend_) << "Mem backend should have been set by "
143 "HistoryBackend::Init";
144 }
145
146 void CreateDBVersion(int version) {
147 base::FilePath data_path;
148 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
149 data_path = data_path.AppendASCII("History");
150 data_path =
151 data_path.AppendASCII(base::StringPrintf("history.%d.sql", version));
152 ASSERT_NO_FATAL_FAILURE(
153 ExecuteSQLScript(data_path, history_dir_.Append(kHistoryFilename)));
154 }
155
156 void CreateArchivedDB() {
157 base::FilePath data_path;
158 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
159 data_path = data_path.AppendASCII("History");
160 data_path = data_path.AppendASCII("archived_history.4.sql");
161 ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
162 data_path, history_dir_.Append(kArchivedHistoryFilename)));
163 }
164
165 // testing::Test
166 void SetUp() override {
167 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
168 history_dir_ = temp_dir_.path().AppendASCII("HistoryBackendDBTest");
169 ASSERT_TRUE(base::CreateDirectory(history_dir_));
170 }
171
172 void DeleteBackend() {
173 if (backend_.get()) {
174 backend_->Closing();
175 backend_ = NULL;
176 }
177 }
178
179 void TearDown() override {
180 DeleteBackend();
181
182 // Make sure we don't have any event pending that could disrupt the next
183 // test.
184 base::MessageLoop::current()->PostTask(FROM_HERE,
185 base::MessageLoop::QuitClosure());
186 base::MessageLoop::current()->Run();
187 }
188
189 bool AddDownload(uint32 id, DownloadState state, const Time& time) {
190 std::vector<GURL> url_chain;
191 url_chain.push_back(GURL("foo-url"));
192
193 DownloadRow download(base::FilePath(FILE_PATH_LITERAL("current-path")),
194 base::FilePath(FILE_PATH_LITERAL("target-path")),
195 url_chain,
196 GURL("http://referrer.com/"),
197 "application/vnd.oasis.opendocument.text",
198 "application/octet-stream",
199 time,
200 time,
201 std::string(),
202 std::string(),
203 0,
204 512,
205 state,
206 DownloadDangerType::NOT_DANGEROUS,
207 ToHistoryDownloadInterruptReason(
208 content::DOWNLOAD_INTERRUPT_REASON_NONE),
209 id,
210 false,
211 "by_ext_id",
212 "by_ext_name");
213 return db_->CreateDownload(download);
214 }
215
216 base::ScopedTempDir temp_dir_;
217
218 base::MessageLoopForUI message_loop_;
219
220 // names of the database files
221 base::FilePath history_dir_;
222
223 // Created via CreateBackendAndDatabase.
224 scoped_refptr<HistoryBackend> backend_;
225 scoped_ptr<InMemoryHistoryBackend> in_mem_backend_;
226 HistoryDatabase* db_; // Cached reference to the backend's database.
227 };
228
229 void BackendDelegate::SetInMemoryBackend(
230 scoped_ptr<InMemoryHistoryBackend> backend) {
231 // Save the in-memory backend to the history test object, this happens
232 // synchronously, so we don't have to do anything fancy.
233 history_test_->in_mem_backend_.swap(backend);
234 }
235
236 TEST_F(HistoryBackendDBTest, ClearBrowsingData_Downloads) {
237 CreateBackendAndDatabase();
238
239 // Initially there should be nothing in the downloads database.
240 std::vector<DownloadRow> downloads;
241 db_->QueryDownloads(&downloads);
242 EXPECT_EQ(0U, downloads.size());
243
244 // Add a download, test that it was added correctly, remove it, test that it
245 // was removed.
246 Time now = Time();
247 uint32 id = 1;
248 EXPECT_TRUE(AddDownload(id, DownloadState::COMPLETE, Time()));
249 db_->QueryDownloads(&downloads);
250 EXPECT_EQ(1U, downloads.size());
251
252 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("current-path")),
253 downloads[0].current_path);
254 EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("target-path")),
255 downloads[0].target_path);
256 EXPECT_EQ(1UL, downloads[0].url_chain.size());
257 EXPECT_EQ(GURL("foo-url"), downloads[0].url_chain[0]);
258 EXPECT_EQ(std::string("http://referrer.com/"),
259 std::string(downloads[0].referrer_url.spec()));
260 EXPECT_EQ(now, downloads[0].start_time);
261 EXPECT_EQ(now, downloads[0].end_time);
262 EXPECT_EQ(0, downloads[0].received_bytes);
263 EXPECT_EQ(512, downloads[0].total_bytes);
264 EXPECT_EQ(DownloadState::COMPLETE, downloads[0].state);
265 EXPECT_EQ(DownloadDangerType::NOT_DANGEROUS, downloads[0].danger_type);
266 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
267 downloads[0].interrupt_reason);
268 EXPECT_FALSE(downloads[0].opened);
269 EXPECT_EQ("by_ext_id", downloads[0].by_ext_id);
270 EXPECT_EQ("by_ext_name", downloads[0].by_ext_name);
271 EXPECT_EQ("application/vnd.oasis.opendocument.text", downloads[0].mime_type);
272 EXPECT_EQ("application/octet-stream", downloads[0].original_mime_type);
273
274 db_->QueryDownloads(&downloads);
275 EXPECT_EQ(1U, downloads.size());
276 db_->RemoveDownload(id);
277 db_->QueryDownloads(&downloads);
278 EXPECT_EQ(0U, downloads.size());
279 }
280
281 TEST_F(HistoryBackendDBTest, MigrateDownloadsState) {
282 // Create the db we want.
283 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
284 {
285 // Open the db for manual manipulation.
286 sql::Connection db;
287 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
288
289 // Manually insert corrupted rows; there's infrastructure in place now to
290 // make this impossible, at least according to the test above.
291 for (int state = 0; state < 5; ++state) {
292 sql::Statement s(db.GetUniqueStatement(
293 "INSERT INTO downloads (id, full_path, url, start_time, "
294 "received_bytes, total_bytes, state, end_time, opened) VALUES "
295 "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
296 s.BindInt64(0, 1 + state);
297 s.BindString(1, "path");
298 s.BindString(2, "url");
299 s.BindInt64(3, base::Time::Now().ToTimeT());
300 s.BindInt64(4, 100);
301 s.BindInt64(5, 100);
302 s.BindInt(6, state);
303 s.BindInt64(7, base::Time::Now().ToTimeT());
304 s.BindInt(8, state % 2);
305 ASSERT_TRUE(s.Run());
306 }
307 }
308
309 // Re-open the db using the HistoryDatabase, which should migrate from version
310 // 22 to the current version, fixing just the row whose state was 3.
311 // Then close the db so that we can re-open it directly.
312 CreateBackendAndDatabase();
313 DeleteBackend();
314 {
315 // Re-open the db for manual manipulation.
316 sql::Connection db;
317 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
318 {
319 // The version should have been updated.
320 int cur_version = HistoryDatabase::GetCurrentVersion();
321 ASSERT_LT(22, cur_version);
322 sql::Statement s(db.GetUniqueStatement(
323 "SELECT value FROM meta WHERE key = 'version'"));
324 EXPECT_TRUE(s.Step());
325 EXPECT_EQ(cur_version, s.ColumnInt(0));
326 }
327 {
328 sql::Statement statement(db.GetUniqueStatement(
329 "SELECT id, state, opened "
330 "FROM downloads "
331 "ORDER BY id"));
332 int counter = 0;
333 while (statement.Step()) {
334 EXPECT_EQ(1 + counter, statement.ColumnInt64(0));
335 // The only thing that migration should have changed was state from 3 to
336 // 4.
337 EXPECT_EQ(((counter == 3) ? 4 : counter), statement.ColumnInt(1));
338 EXPECT_EQ(counter % 2, statement.ColumnInt(2));
339 ++counter;
340 }
341 EXPECT_EQ(5, counter);
342 }
343 }
344 }
345
346 TEST_F(HistoryBackendDBTest, MigrateDownloadsReasonPathsAndDangerType) {
347 Time now(base::Time::Now());
348
349 // Create the db we want. The schema didn't change from 22->23, so just
350 // re-use the v22 file.
351 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
352 {
353 // Re-open the db for manual manipulation.
354 sql::Connection db;
355 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
356
357 // Manually insert some rows.
358 sql::Statement s(db.GetUniqueStatement(
359 "INSERT INTO downloads (id, full_path, url, start_time, "
360 "received_bytes, total_bytes, state, end_time, opened) VALUES "
361 "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
362
363 int64 id = 0;
364 // Null path.
365 s.BindInt64(0, ++id);
366 s.BindString(1, std::string());
367 s.BindString(2, "http://whatever.com/index.html");
368 s.BindInt64(3, now.ToTimeT());
369 s.BindInt64(4, 100);
370 s.BindInt64(5, 100);
371 s.BindInt(6, 1);
372 s.BindInt64(7, now.ToTimeT());
373 s.BindInt(8, 1);
374 ASSERT_TRUE(s.Run());
375 s.Reset(true);
376
377 // Non-null path.
378 s.BindInt64(0, ++id);
379 s.BindString(1, "/path/to/some/file");
380 s.BindString(2, "http://whatever.com/index1.html");
381 s.BindInt64(3, now.ToTimeT());
382 s.BindInt64(4, 100);
383 s.BindInt64(5, 100);
384 s.BindInt(6, 1);
385 s.BindInt64(7, now.ToTimeT());
386 s.BindInt(8, 1);
387 ASSERT_TRUE(s.Run());
388 }
389
390 // Re-open the db using the HistoryDatabase, which should migrate from version
391 // 23 to 24, creating the new tables and creating the new path, reason,
392 // and danger columns.
393 CreateBackendAndDatabase();
394 DeleteBackend();
395 {
396 // Re-open the db for manual manipulation.
397 sql::Connection db;
398 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
399 {
400 // The version should have been updated.
401 int cur_version = HistoryDatabase::GetCurrentVersion();
402 ASSERT_LT(23, cur_version);
403 sql::Statement s(db.GetUniqueStatement(
404 "SELECT value FROM meta WHERE key = 'version'"));
405 EXPECT_TRUE(s.Step());
406 EXPECT_EQ(cur_version, s.ColumnInt(0));
407 }
408 {
409 base::Time nowish(base::Time::FromTimeT(now.ToTimeT()));
410
411 // Confirm downloads table is valid.
412 sql::Statement statement(db.GetUniqueStatement(
413 "SELECT id, interrupt_reason, current_path, target_path, "
414 " danger_type, start_time, end_time "
415 "FROM downloads ORDER BY id"));
416 EXPECT_TRUE(statement.Step());
417 EXPECT_EQ(1, statement.ColumnInt64(0));
418 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
419 statement.ColumnInt(1));
420 EXPECT_EQ("", statement.ColumnString(2));
421 EXPECT_EQ("", statement.ColumnString(3));
422 // Implicit dependence on value of kDangerTypeNotDangerous from
423 // download_database.cc.
424 EXPECT_EQ(0, statement.ColumnInt(4));
425 EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(5));
426 EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(6));
427
428 EXPECT_TRUE(statement.Step());
429 EXPECT_EQ(2, statement.ColumnInt64(0));
430 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE,
431 statement.ColumnInt(1));
432 EXPECT_EQ("/path/to/some/file", statement.ColumnString(2));
433 EXPECT_EQ("/path/to/some/file", statement.ColumnString(3));
434 EXPECT_EQ(0, statement.ColumnInt(4));
435 EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(5));
436 EXPECT_EQ(nowish.ToInternalValue(), statement.ColumnInt64(6));
437
438 EXPECT_FALSE(statement.Step());
439 }
440 {
441 // Confirm downloads_url_chains table is valid.
442 sql::Statement statement(db.GetUniqueStatement(
443 "SELECT id, chain_index, url FROM downloads_url_chains "
444 " ORDER BY id, chain_index"));
445 EXPECT_TRUE(statement.Step());
446 EXPECT_EQ(1, statement.ColumnInt64(0));
447 EXPECT_EQ(0, statement.ColumnInt(1));
448 EXPECT_EQ("http://whatever.com/index.html", statement.ColumnString(2));
449
450 EXPECT_TRUE(statement.Step());
451 EXPECT_EQ(2, statement.ColumnInt64(0));
452 EXPECT_EQ(0, statement.ColumnInt(1));
453 EXPECT_EQ("http://whatever.com/index1.html", statement.ColumnString(2));
454
455 EXPECT_FALSE(statement.Step());
456 }
457 }
458 }
459
460 TEST_F(HistoryBackendDBTest, MigrateReferrer) {
461 Time now(base::Time::Now());
462 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
463 {
464 sql::Connection db;
465 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
466 sql::Statement s(db.GetUniqueStatement(
467 "INSERT INTO downloads (id, full_path, url, start_time, "
468 "received_bytes, total_bytes, state, end_time, opened) VALUES "
469 "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
470 int64 db_handle = 0;
471 s.BindInt64(0, ++db_handle);
472 s.BindString(1, "full_path");
473 s.BindString(2, "http://whatever.com/index.html");
474 s.BindInt64(3, now.ToTimeT());
475 s.BindInt64(4, 100);
476 s.BindInt64(5, 100);
477 s.BindInt(6, 1);
478 s.BindInt64(7, now.ToTimeT());
479 s.BindInt(8, 1);
480 ASSERT_TRUE(s.Run());
481 }
482 // Re-open the db using the HistoryDatabase, which should migrate to version
483 // 26, creating the referrer column.
484 CreateBackendAndDatabase();
485 DeleteBackend();
486 {
487 // Re-open the db for manual manipulation.
488 sql::Connection db;
489 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
490 // The version should have been updated.
491 int cur_version = HistoryDatabase::GetCurrentVersion();
492 ASSERT_LE(26, cur_version);
493 {
494 sql::Statement s(db.GetUniqueStatement(
495 "SELECT value FROM meta WHERE key = 'version'"));
496 EXPECT_TRUE(s.Step());
497 EXPECT_EQ(cur_version, s.ColumnInt(0));
498 }
499 {
500 sql::Statement s(db.GetUniqueStatement(
501 "SELECT referrer from downloads"));
502 EXPECT_TRUE(s.Step());
503 EXPECT_EQ(std::string(), s.ColumnString(0));
504 }
505 }
506 }
507
508 TEST_F(HistoryBackendDBTest, MigrateDownloadedByExtension) {
509 Time now(base::Time::Now());
510 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(26));
511 {
512 sql::Connection db;
513 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
514 {
515 sql::Statement s(db.GetUniqueStatement(
516 "INSERT INTO downloads (id, current_path, target_path, start_time, "
517 "received_bytes, total_bytes, state, danger_type, interrupt_reason, "
518 "end_time, opened, referrer) VALUES "
519 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
520 s.BindInt64(0, 1);
521 s.BindString(1, "current_path");
522 s.BindString(2, "target_path");
523 s.BindInt64(3, now.ToTimeT());
524 s.BindInt64(4, 100);
525 s.BindInt64(5, 100);
526 s.BindInt(6, 1);
527 s.BindInt(7, 0);
528 s.BindInt(8, 0);
529 s.BindInt64(9, now.ToTimeT());
530 s.BindInt(10, 1);
531 s.BindString(11, "referrer");
532 ASSERT_TRUE(s.Run());
533 }
534 {
535 sql::Statement s(db.GetUniqueStatement(
536 "INSERT INTO downloads_url_chains (id, chain_index, url) VALUES "
537 "(?, ?, ?)"));
538 s.BindInt64(0, 4);
539 s.BindInt64(1, 0);
540 s.BindString(2, "url");
541 ASSERT_TRUE(s.Run());
542 }
543 }
544 // Re-open the db using the HistoryDatabase, which should migrate to version
545 // 27, creating the by_ext_id and by_ext_name columns.
546 CreateBackendAndDatabase();
547 DeleteBackend();
548 {
549 // Re-open the db for manual manipulation.
550 sql::Connection db;
551 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
552 // The version should have been updated.
553 int cur_version = HistoryDatabase::GetCurrentVersion();
554 ASSERT_LE(27, cur_version);
555 {
556 sql::Statement s(db.GetUniqueStatement(
557 "SELECT value FROM meta WHERE key = 'version'"));
558 EXPECT_TRUE(s.Step());
559 EXPECT_EQ(cur_version, s.ColumnInt(0));
560 }
561 {
562 sql::Statement s(db.GetUniqueStatement(
563 "SELECT by_ext_id, by_ext_name from downloads"));
564 EXPECT_TRUE(s.Step());
565 EXPECT_EQ(std::string(), s.ColumnString(0));
566 EXPECT_EQ(std::string(), s.ColumnString(1));
567 }
568 }
569 }
570
571 TEST_F(HistoryBackendDBTest, MigrateDownloadValidators) {
572 Time now(base::Time::Now());
573 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(27));
574 {
575 sql::Connection db;
576 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
577 {
578 sql::Statement s(db.GetUniqueStatement(
579 "INSERT INTO downloads (id, current_path, target_path, start_time, "
580 "received_bytes, total_bytes, state, danger_type, interrupt_reason, "
581 "end_time, opened, referrer, by_ext_id, by_ext_name) VALUES "
582 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
583 s.BindInt64(0, 1);
584 s.BindString(1, "current_path");
585 s.BindString(2, "target_path");
586 s.BindInt64(3, now.ToTimeT());
587 s.BindInt64(4, 100);
588 s.BindInt64(5, 100);
589 s.BindInt(6, 1);
590 s.BindInt(7, 0);
591 s.BindInt(8, 0);
592 s.BindInt64(9, now.ToTimeT());
593 s.BindInt(10, 1);
594 s.BindString(11, "referrer");
595 s.BindString(12, "by extension ID");
596 s.BindString(13, "by extension name");
597 ASSERT_TRUE(s.Run());
598 }
599 {
600 sql::Statement s(db.GetUniqueStatement(
601 "INSERT INTO downloads_url_chains (id, chain_index, url) VALUES "
602 "(?, ?, ?)"));
603 s.BindInt64(0, 4);
604 s.BindInt64(1, 0);
605 s.BindString(2, "url");
606 ASSERT_TRUE(s.Run());
607 }
608 }
609 // Re-open the db using the HistoryDatabase, which should migrate to the
610 // current version, creating the etag and last_modified columns.
611 CreateBackendAndDatabase();
612 DeleteBackend();
613 {
614 // Re-open the db for manual manipulation.
615 sql::Connection db;
616 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
617 // The version should have been updated.
618 int cur_version = HistoryDatabase::GetCurrentVersion();
619 ASSERT_LE(28, cur_version);
620 {
621 sql::Statement s(db.GetUniqueStatement(
622 "SELECT value FROM meta WHERE key = 'version'"));
623 EXPECT_TRUE(s.Step());
624 EXPECT_EQ(cur_version, s.ColumnInt(0));
625 }
626 {
627 sql::Statement s(db.GetUniqueStatement(
628 "SELECT etag, last_modified from downloads"));
629 EXPECT_TRUE(s.Step());
630 EXPECT_EQ(std::string(), s.ColumnString(0));
631 EXPECT_EQ(std::string(), s.ColumnString(1));
632 }
633 }
634 }
635
636 TEST_F(HistoryBackendDBTest, PurgeArchivedDatabase) {
637 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(27));
638 ASSERT_NO_FATAL_FAILURE(CreateArchivedDB());
639
640 ASSERT_TRUE(base::PathExists(history_dir_.Append(kArchivedHistoryFilename)));
641
642 CreateBackendAndDatabase();
643 DeleteBackend();
644
645 // We do not retain expired history entries in an archived database as of M37.
646 // Verify that any legacy archived database is deleted on start-up.
647 ASSERT_FALSE(base::PathExists(history_dir_.Append(kArchivedHistoryFilename)));
648 }
649
650 TEST_F(HistoryBackendDBTest, MigrateDownloadMimeType) {
651 Time now(base::Time::Now());
652 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(28));
653 {
654 sql::Connection db;
655 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
656 {
657 sql::Statement s(db.GetUniqueStatement(
658 "INSERT INTO downloads (id, current_path, target_path, start_time, "
659 "received_bytes, total_bytes, state, danger_type, interrupt_reason, "
660 "end_time, opened, referrer, by_ext_id, by_ext_name, etag, "
661 "last_modified) VALUES "
662 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
663 s.BindInt64(0, 1);
664 s.BindString(1, "current_path");
665 s.BindString(2, "target_path");
666 s.BindInt64(3, now.ToTimeT());
667 s.BindInt64(4, 100);
668 s.BindInt64(5, 100);
669 s.BindInt(6, 1);
670 s.BindInt(7, 0);
671 s.BindInt(8, 0);
672 s.BindInt64(9, now.ToTimeT());
673 s.BindInt(10, 1);
674 s.BindString(11, "referrer");
675 s.BindString(12, "by extension ID");
676 s.BindString(13, "by extension name");
677 s.BindString(14, "etag");
678 s.BindInt64(15, now.ToTimeT());
679 ASSERT_TRUE(s.Run());
680 }
681 {
682 sql::Statement s(db.GetUniqueStatement(
683 "INSERT INTO downloads_url_chains (id, chain_index, url) VALUES "
684 "(?, ?, ?)"));
685 s.BindInt64(0, 4);
686 s.BindInt64(1, 0);
687 s.BindString(2, "url");
688 ASSERT_TRUE(s.Run());
689 }
690 }
691 // Re-open the db using the HistoryDatabase, which should migrate to the
692 // current version, creating themime_type abd original_mime_type columns.
693 CreateBackendAndDatabase();
694 DeleteBackend();
695 {
696 // Re-open the db for manual manipulation.
697 sql::Connection db;
698 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
699 // The version should have been updated.
700 int cur_version = HistoryDatabase::GetCurrentVersion();
701 ASSERT_LE(29, cur_version);
702 {
703 sql::Statement s(db.GetUniqueStatement(
704 "SELECT value FROM meta WHERE key = 'version'"));
705 EXPECT_TRUE(s.Step());
706 EXPECT_EQ(cur_version, s.ColumnInt(0));
707 }
708 {
709 sql::Statement s(db.GetUniqueStatement(
710 "SELECT mime_type, original_mime_type from downloads"));
711 EXPECT_TRUE(s.Step());
712 EXPECT_EQ(std::string(), s.ColumnString(0));
713 EXPECT_EQ(std::string(), s.ColumnString(1));
714 }
715 }
716 }
717
718 TEST_F(HistoryBackendDBTest, ConfirmDownloadRowCreateAndDelete) {
719 // Create the DB.
720 CreateBackendAndDatabase();
721
722 base::Time now(base::Time::Now());
723
724 // Add some downloads.
725 uint32 id1 = 1, id2 = 2, id3 = 3;
726 AddDownload(id1, DownloadState::COMPLETE, now);
727 AddDownload(id2, DownloadState::COMPLETE, now + base::TimeDelta::FromDays(2));
728 AddDownload(id3, DownloadState::COMPLETE, now - base::TimeDelta::FromDays(2));
729
730 // Confirm that resulted in the correct number of rows in the DB.
731 DeleteBackend();
732 {
733 sql::Connection db;
734 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
735 sql::Statement statement(db.GetUniqueStatement(
736 "Select Count(*) from downloads"));
737 EXPECT_TRUE(statement.Step());
738 EXPECT_EQ(3, statement.ColumnInt(0));
739
740 sql::Statement statement1(db.GetUniqueStatement(
741 "Select Count(*) from downloads_url_chains"));
742 EXPECT_TRUE(statement1.Step());
743 EXPECT_EQ(3, statement1.ColumnInt(0));
744 }
745
746 // Delete some rows and make sure the results are still correct.
747 CreateBackendAndDatabase();
748 db_->RemoveDownload(id2);
749 db_->RemoveDownload(id3);
750 DeleteBackend();
751 {
752 sql::Connection db;
753 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
754 sql::Statement statement(db.GetUniqueStatement(
755 "Select Count(*) from downloads"));
756 EXPECT_TRUE(statement.Step());
757 EXPECT_EQ(1, statement.ColumnInt(0));
758
759 sql::Statement statement1(db.GetUniqueStatement(
760 "Select Count(*) from downloads_url_chains"));
761 EXPECT_TRUE(statement1.Step());
762 EXPECT_EQ(1, statement1.ColumnInt(0));
763 }
764 }
765
766 TEST_F(HistoryBackendDBTest, DownloadNukeRecordsMissingURLs) {
767 CreateBackendAndDatabase();
768 base::Time now(base::Time::Now());
769 std::vector<GURL> url_chain;
770 DownloadRow download(base::FilePath(FILE_PATH_LITERAL("foo-path")),
771 base::FilePath(FILE_PATH_LITERAL("foo-path")),
772 url_chain,
773 GURL(std::string()),
774 "application/octet-stream",
775 "application/octet-stream",
776 now,
777 now,
778 std::string(),
779 std::string(),
780 0,
781 512,
782 DownloadState::COMPLETE,
783 DownloadDangerType::NOT_DANGEROUS,
784 ToHistoryDownloadInterruptReason(
785 content::DOWNLOAD_INTERRUPT_REASON_NONE),
786 1,
787 0,
788 "by_ext_id",
789 "by_ext_name");
790
791 // Creating records without any urls should fail.
792 EXPECT_FALSE(db_->CreateDownload(download));
793
794 download.url_chain.push_back(GURL("foo-url"));
795 EXPECT_TRUE(db_->CreateDownload(download));
796
797 // Pretend that the URLs were dropped.
798 DeleteBackend();
799 {
800 sql::Connection db;
801 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
802 sql::Statement statement(db.GetUniqueStatement(
803 "DELETE FROM downloads_url_chains WHERE id=1"));
804 ASSERT_TRUE(statement.Run());
805 }
806 CreateBackendAndDatabase();
807 std::vector<DownloadRow> downloads;
808 db_->QueryDownloads(&downloads);
809 EXPECT_EQ(0U, downloads.size());
810
811 // QueryDownloads should have nuked the corrupt record.
812 DeleteBackend();
813 {
814 sql::Connection db;
815 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
816 {
817 sql::Statement statement(db.GetUniqueStatement(
818 "SELECT count(*) from downloads"));
819 ASSERT_TRUE(statement.Step());
820 EXPECT_EQ(0, statement.ColumnInt(0));
821 }
822 }
823 }
824
825 TEST_F(HistoryBackendDBTest, ConfirmDownloadInProgressCleanup) {
826 // Create the DB.
827 CreateBackendAndDatabase();
828
829 base::Time now(base::Time::Now());
830
831 // Put an IN_PROGRESS download in the DB.
832 AddDownload(1, DownloadState::IN_PROGRESS, now);
833
834 // Confirm that they made it into the DB unchanged.
835 DeleteBackend();
836 {
837 sql::Connection db;
838 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
839 sql::Statement statement(db.GetUniqueStatement(
840 "Select Count(*) from downloads"));
841 EXPECT_TRUE(statement.Step());
842 EXPECT_EQ(1, statement.ColumnInt(0));
843
844 sql::Statement statement1(db.GetUniqueStatement(
845 "Select state, interrupt_reason from downloads"));
846 EXPECT_TRUE(statement1.Step());
847 EXPECT_EQ(DownloadStateToInt(DownloadState::IN_PROGRESS),
848 statement1.ColumnInt(0));
849 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE, statement1.ColumnInt(1));
850 EXPECT_FALSE(statement1.Step());
851 }
852
853 // Read in the DB through query downloads, then test that the
854 // right transformation was returned.
855 CreateBackendAndDatabase();
856 std::vector<DownloadRow> results;
857 db_->QueryDownloads(&results);
858 ASSERT_EQ(1u, results.size());
859 EXPECT_EQ(DownloadState::INTERRUPTED, results[0].state);
860 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH,
861 results[0].interrupt_reason);
862
863 // Allow the update to propagate, shut down the DB, and confirm that
864 // the query updated the on disk database as well.
865 base::MessageLoop::current()->RunUntilIdle();
866 DeleteBackend();
867 {
868 sql::Connection db;
869 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
870 sql::Statement statement(db.GetUniqueStatement(
871 "Select Count(*) from downloads"));
872 EXPECT_TRUE(statement.Step());
873 EXPECT_EQ(1, statement.ColumnInt(0));
874
875 sql::Statement statement1(db.GetUniqueStatement(
876 "Select state, interrupt_reason from downloads"));
877 EXPECT_TRUE(statement1.Step());
878 EXPECT_EQ(DownloadStateToInt(DownloadState::INTERRUPTED),
879 statement1.ColumnInt(0));
880 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH,
881 statement1.ColumnInt(1));
882 EXPECT_FALSE(statement1.Step());
883 }
884 }
885
886 struct InterruptReasonAssociation {
887 std::string name;
888 int value;
889 };
890
891 // Test is dependent on interrupt reasons being listed in header file
892 // in order.
893 const InterruptReasonAssociation current_reasons[] = {
894 #define INTERRUPT_REASON(a, b) { #a, b },
895 #include "content/public/browser/download_interrupt_reason_values.h"
896 #undef INTERRUPT_REASON
897 };
898
899 // This represents a list of all reasons we've previously used;
900 // Do Not Remove Any Entries From This List.
901 const InterruptReasonAssociation historical_reasons[] = {
902 {"FILE_FAILED", 1},
903 {"FILE_ACCESS_DENIED", 2},
904 {"FILE_NO_SPACE", 3},
905 {"FILE_NAME_TOO_LONG", 5},
906 {"FILE_TOO_LARGE", 6},
907 {"FILE_VIRUS_INFECTED", 7},
908 {"FILE_TRANSIENT_ERROR", 10},
909 {"FILE_BLOCKED", 11},
910 {"FILE_SECURITY_CHECK_FAILED", 12},
911 {"FILE_TOO_SHORT", 13},
912 {"NETWORK_FAILED", 20},
913 {"NETWORK_TIMEOUT", 21},
914 {"NETWORK_DISCONNECTED", 22},
915 {"NETWORK_SERVER_DOWN", 23},
916 {"NETWORK_INVALID_REQUEST", 24},
917 {"SERVER_FAILED", 30},
918 {"SERVER_NO_RANGE", 31},
919 {"SERVER_PRECONDITION", 32},
920 {"SERVER_BAD_CONTENT", 33},
921 {"SERVER_UNAUTHORIZED", 34},
922 {"SERVER_CERT_PROBLEM", 35},
923 {"USER_CANCELED", 40},
924 {"USER_SHUTDOWN", 41},
925 {"CRASH", 50},
926 };
927
928 // Make sure no one has changed a DownloadInterruptReason we've previously
929 // persisted.
930 TEST_F(HistoryBackendDBTest,
931 ConfirmDownloadInterruptReasonBackwardsCompatible) {
932 // Are there any cases in which a historical number has been repurposed
933 // for an error other than it's original?
934 for (size_t i = 0; i < arraysize(current_reasons); i++) {
935 const InterruptReasonAssociation& cur_reason(current_reasons[i]);
936 bool found = false;
937
938 for (size_t j = 0; j < arraysize(historical_reasons); ++j) {
939 const InterruptReasonAssociation& hist_reason(historical_reasons[j]);
940
941 if (hist_reason.value == cur_reason.value) {
942 EXPECT_EQ(cur_reason.name, hist_reason.name)
943 << "Same integer value used for old error \""
944 << hist_reason.name
945 << "\" as for new error \""
946 << cur_reason.name
947 << "\"." << std::endl
948 << "**This will cause database conflicts with persisted values**"
949 << std::endl
950 << "Please assign a new, non-conflicting value for the new error.";
951 }
952
953 if (hist_reason.name == cur_reason.name) {
954 EXPECT_EQ(cur_reason.value, hist_reason.value)
955 << "Same name (\"" << hist_reason.name
956 << "\") maps to a different value historically ("
957 << hist_reason.value << ") and currently ("
958 << cur_reason.value << ")" << std::endl
959 << "This may cause database conflicts with persisted values"
960 << std::endl
961 << "If this error is the same as the old one, you should"
962 << std::endl
963 << "use the old value, and if it is different, you should"
964 << std::endl
965 << "use a new name.";
966
967 found = true;
968 }
969 }
970
971 EXPECT_TRUE(found)
972 << "Error \"" << cur_reason.name << "\" not found in historical list."
973 << std::endl
974 << "Please add it.";
975 }
976 }
977
978 class HistoryTest : public testing::Test {
979 public:
980 HistoryTest() : query_url_success_(false) {
981 }
982
983 ~HistoryTest() override {}
984
985 void OnMostVisitedURLsAvailable(const MostVisitedURLList* url_list) {
986 most_visited_urls_ = *url_list;
987 base::MessageLoop::current()->Quit();
988 }
989
990 protected:
991 friend class BackendDelegate;
992
993 // testing::Test
994 void SetUp() override {
995 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
996 history_dir_ = temp_dir_.path().AppendASCII("HistoryTest");
997 ASSERT_TRUE(base::CreateDirectory(history_dir_));
998 history_service_.reset(new history::HistoryService);
999 if (!history_service_->Init(std::string(),
1000 HistoryDatabaseParamsForPath(history_dir_))) {
1001 history_service_.reset();
1002 ADD_FAILURE();
1003 }
1004 }
1005
1006 void TearDown() override {
1007 if (history_service_)
1008 CleanupHistoryService();
1009
1010 // Make sure we don't have any event pending that could disrupt the next
1011 // test.
1012 base::MessageLoop::current()->PostTask(FROM_HERE,
1013 base::MessageLoop::QuitClosure());
1014 base::MessageLoop::current()->Run();
1015 }
1016
1017 void CleanupHistoryService() {
1018 DCHECK(history_service_);
1019
1020 history_service_->ClearCachedDataForContextID(0);
1021 history_service_->SetOnBackendDestroyTask(base::MessageLoop::QuitClosure());
1022 history_service_->Cleanup();
1023 history_service_.reset();
1024
1025 // Wait for the backend class to terminate before deleting the files and
1026 // moving to the next test. Note: if this never terminates, somebody is
1027 // probably leaking a reference to the history backend, so it never calls
1028 // our destroy task.
1029 base::MessageLoop::current()->Run();
1030 }
1031
1032 // Fills the query_url_row_ and query_url_visits_ structures with the
1033 // information about the given URL and returns true. If the URL was not
1034 // found, this will return false and those structures will not be changed.
1035 bool QueryURL(history::HistoryService* history, const GURL& url) {
1036 history_service_->QueryURL(
1037 url,
1038 true,
1039 base::Bind(&HistoryTest::SaveURLAndQuit, base::Unretained(this)),
1040 &tracker_);
1041 base::MessageLoop::current()->Run(); // Will be exited in SaveURLAndQuit.
1042 return query_url_success_;
1043 }
1044
1045 // Callback for HistoryService::QueryURL.
1046 void SaveURLAndQuit(bool success,
1047 const URLRow& url_row,
1048 const VisitVector& visits) {
1049 query_url_success_ = success;
1050 if (query_url_success_) {
1051 query_url_row_ = url_row;
1052 query_url_visits_ = visits;
1053 } else {
1054 query_url_row_ = URLRow();
1055 query_url_visits_.clear();
1056 }
1057 base::MessageLoop::current()->Quit();
1058 }
1059
1060 // Fills in saved_redirects_ with the redirect information for the given URL,
1061 // returning true on success. False means the URL was not found.
1062 void QueryRedirectsFrom(history::HistoryService* history, const GURL& url) {
1063 history_service_->QueryRedirectsFrom(
1064 url,
1065 base::Bind(&HistoryTest::OnRedirectQueryComplete,
1066 base::Unretained(this)),
1067 &tracker_);
1068 base::MessageLoop::current()->Run(); // Will be exited in *QueryComplete.
1069 }
1070
1071 // Callback for QueryRedirects.
1072 void OnRedirectQueryComplete(const history::RedirectList* redirects) {
1073 saved_redirects_.clear();
1074 if (!redirects->empty()) {
1075 saved_redirects_.insert(
1076 saved_redirects_.end(), redirects->begin(), redirects->end());
1077 }
1078 base::MessageLoop::current()->Quit();
1079 }
1080
1081 base::ScopedTempDir temp_dir_;
1082
1083 base::MessageLoopForUI message_loop_;
1084
1085 MostVisitedURLList most_visited_urls_;
1086
1087 // When non-NULL, this will be deleted on tear down and we will block until
1088 // the backend thread has completed. This allows tests for the history
1089 // service to use this feature, but other tests to ignore this.
1090 scoped_ptr<history::HistoryService> history_service_;
1091
1092 // names of the database files
1093 base::FilePath history_dir_;
1094
1095 // Set by the redirect callback when we get data. You should be sure to
1096 // clear this before issuing a redirect request.
1097 history::RedirectList saved_redirects_;
1098
1099 // For history requests.
1100 base::CancelableTaskTracker tracker_;
1101
1102 // For saving URL info after a call to QueryURL
1103 bool query_url_success_;
1104 URLRow query_url_row_;
1105 VisitVector query_url_visits_;
1106 };
1107
1108 TEST_F(HistoryTest, AddPage) {
1109 ASSERT_TRUE(history_service_.get());
1110 // Add the page once from a child frame.
1111 const GURL test_url("http://www.google.com/");
1112 history_service_->AddPage(test_url, base::Time::Now(), NULL, 0, GURL(),
1113 history::RedirectList(),
1114 ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
1115 history::SOURCE_BROWSED, false);
1116 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1117 EXPECT_EQ(1, query_url_row_.visit_count());
1118 EXPECT_EQ(0, query_url_row_.typed_count());
1119 EXPECT_TRUE(query_url_row_.hidden()); // Hidden because of child frame.
1120
1121 // Add the page once from the main frame (should unhide it).
1122 history_service_->AddPage(test_url, base::Time::Now(), NULL, 0, GURL(),
1123 history::RedirectList(), ui::PAGE_TRANSITION_LINK,
1124 history::SOURCE_BROWSED, false);
1125 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1126 EXPECT_EQ(2, query_url_row_.visit_count()); // Added twice.
1127 EXPECT_EQ(0, query_url_row_.typed_count()); // Never typed.
1128 EXPECT_FALSE(query_url_row_.hidden()); // Because loaded in main frame.
1129 }
1130
1131 TEST_F(HistoryTest, AddRedirect) {
1132 ASSERT_TRUE(history_service_.get());
1133 const char* first_sequence[] = {
1134 "http://first.page.com/",
1135 "http://second.page.com/"};
1136 int first_count = arraysize(first_sequence);
1137 history::RedirectList first_redirects;
1138 for (int i = 0; i < first_count; i++)
1139 first_redirects.push_back(GURL(first_sequence[i]));
1140
1141 // Add the sequence of pages as a server with no referrer. Note that we need
1142 // to have a non-NULL page ID scope.
1143 history_service_->AddPage(
1144 first_redirects.back(), base::Time::Now(),
1145 reinterpret_cast<ContextID>(1), 0, GURL(), first_redirects,
1146 ui::PAGE_TRANSITION_LINK, history::SOURCE_BROWSED, true);
1147
1148 // The first page should be added once with a link visit type (because we set
1149 // LINK when we added the original URL, and a referrer of nowhere (0).
1150 EXPECT_TRUE(QueryURL(history_service_.get(), first_redirects[0]));
1151 EXPECT_EQ(1, query_url_row_.visit_count());
1152 ASSERT_EQ(1U, query_url_visits_.size());
1153 int64 first_visit = query_url_visits_[0].visit_id;
1154 EXPECT_EQ(ui::PAGE_TRANSITION_LINK |
1155 ui::PAGE_TRANSITION_CHAIN_START,
1156 query_url_visits_[0].transition);
1157 EXPECT_EQ(0, query_url_visits_[0].referring_visit); // No referrer.
1158
1159 // The second page should be a server redirect type with a referrer of the
1160 // first page.
1161 EXPECT_TRUE(QueryURL(history_service_.get(), first_redirects[1]));
1162 EXPECT_EQ(1, query_url_row_.visit_count());
1163 ASSERT_EQ(1U, query_url_visits_.size());
1164 int64 second_visit = query_url_visits_[0].visit_id;
1165 EXPECT_EQ(ui::PAGE_TRANSITION_SERVER_REDIRECT |
1166 ui::PAGE_TRANSITION_CHAIN_END,
1167 query_url_visits_[0].transition);
1168 EXPECT_EQ(first_visit, query_url_visits_[0].referring_visit);
1169
1170 // Check that the redirect finding function successfully reports it.
1171 saved_redirects_.clear();
1172 QueryRedirectsFrom(history_service_.get(), first_redirects[0]);
1173 ASSERT_EQ(1U, saved_redirects_.size());
1174 EXPECT_EQ(first_redirects[1], saved_redirects_[0]);
1175
1176 // Now add a client redirect from that second visit to a third, client
1177 // redirects are tracked by the RenderView prior to updating history,
1178 // so we pass in a CLIENT_REDIRECT qualifier to mock that behavior.
1179 history::RedirectList second_redirects;
1180 second_redirects.push_back(first_redirects[1]);
1181 second_redirects.push_back(GURL("http://last.page.com/"));
1182 history_service_->AddPage(second_redirects[1], base::Time::Now(),
1183 reinterpret_cast<ContextID>(1), 1,
1184 second_redirects[0], second_redirects,
1185 ui::PageTransitionFromInt(
1186 ui::PAGE_TRANSITION_LINK |
1187 ui::PAGE_TRANSITION_CLIENT_REDIRECT),
1188 history::SOURCE_BROWSED, true);
1189
1190 // The last page (source of the client redirect) should NOT have an
1191 // additional visit added, because it was a client redirect (normally it
1192 // would). We should only have 1 left over from the first sequence.
1193 EXPECT_TRUE(QueryURL(history_service_.get(), second_redirects[0]));
1194 EXPECT_EQ(1, query_url_row_.visit_count());
1195
1196 // The final page should be set as a client redirect from the previous visit.
1197 EXPECT_TRUE(QueryURL(history_service_.get(), second_redirects[1]));
1198 EXPECT_EQ(1, query_url_row_.visit_count());
1199 ASSERT_EQ(1U, query_url_visits_.size());
1200 EXPECT_EQ(ui::PAGE_TRANSITION_CLIENT_REDIRECT |
1201 ui::PAGE_TRANSITION_CHAIN_END,
1202 query_url_visits_[0].transition);
1203 EXPECT_EQ(second_visit, query_url_visits_[0].referring_visit);
1204 }
1205
1206 TEST_F(HistoryTest, MakeIntranetURLsTyped) {
1207 ASSERT_TRUE(history_service_.get());
1208
1209 // Add a non-typed visit to an intranet URL on an unvisited host. This should
1210 // get promoted to a typed visit.
1211 const GURL test_url("http://intranet_host/path");
1212 history_service_->AddPage(
1213 test_url, base::Time::Now(), NULL, 0, GURL(),
1214 history::RedirectList(), ui::PAGE_TRANSITION_LINK,
1215 history::SOURCE_BROWSED, false);
1216 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1217 EXPECT_EQ(1, query_url_row_.visit_count());
1218 EXPECT_EQ(1, query_url_row_.typed_count());
1219 ASSERT_EQ(1U, query_url_visits_.size());
1220 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED,
1221 ui::PageTransitionStripQualifier(query_url_visits_[0].transition));
1222
1223 // Add more visits on the same host. None of these should be promoted since
1224 // there is already a typed visit.
1225
1226 // Different path.
1227 const GURL test_url2("http://intranet_host/different_path");
1228 history_service_->AddPage(
1229 test_url2, base::Time::Now(), NULL, 0, GURL(),
1230 history::RedirectList(), ui::PAGE_TRANSITION_LINK,
1231 history::SOURCE_BROWSED, false);
1232 EXPECT_TRUE(QueryURL(history_service_.get(), test_url2));
1233 EXPECT_EQ(1, query_url_row_.visit_count());
1234 EXPECT_EQ(0, query_url_row_.typed_count());
1235 ASSERT_EQ(1U, query_url_visits_.size());
1236 EXPECT_EQ(ui::PAGE_TRANSITION_LINK,
1237 ui::PageTransitionStripQualifier(query_url_visits_[0].transition));
1238
1239 // No path.
1240 const GURL test_url3("http://intranet_host/");
1241 history_service_->AddPage(
1242 test_url3, base::Time::Now(), NULL, 0, GURL(),
1243 history::RedirectList(), ui::PAGE_TRANSITION_LINK,
1244 history::SOURCE_BROWSED, false);
1245 EXPECT_TRUE(QueryURL(history_service_.get(), test_url3));
1246 EXPECT_EQ(1, query_url_row_.visit_count());
1247 EXPECT_EQ(0, query_url_row_.typed_count());
1248 ASSERT_EQ(1U, query_url_visits_.size());
1249 EXPECT_EQ(ui::PAGE_TRANSITION_LINK,
1250 ui::PageTransitionStripQualifier(query_url_visits_[0].transition));
1251
1252 // Different scheme.
1253 const GURL test_url4("https://intranet_host/");
1254 history_service_->AddPage(
1255 test_url4, base::Time::Now(), NULL, 0, GURL(),
1256 history::RedirectList(), ui::PAGE_TRANSITION_LINK,
1257 history::SOURCE_BROWSED, false);
1258 EXPECT_TRUE(QueryURL(history_service_.get(), test_url4));
1259 EXPECT_EQ(1, query_url_row_.visit_count());
1260 EXPECT_EQ(0, query_url_row_.typed_count());
1261 ASSERT_EQ(1U, query_url_visits_.size());
1262 EXPECT_EQ(ui::PAGE_TRANSITION_LINK,
1263 ui::PageTransitionStripQualifier(query_url_visits_[0].transition));
1264
1265 // Different transition.
1266 const GURL test_url5("http://intranet_host/another_path");
1267 history_service_->AddPage(
1268 test_url5, base::Time::Now(), NULL, 0, GURL(),
1269 history::RedirectList(),
1270 ui::PAGE_TRANSITION_AUTO_BOOKMARK,
1271 history::SOURCE_BROWSED, false);
1272 EXPECT_TRUE(QueryURL(history_service_.get(), test_url5));
1273 EXPECT_EQ(1, query_url_row_.visit_count());
1274 EXPECT_EQ(0, query_url_row_.typed_count());
1275 ASSERT_EQ(1U, query_url_visits_.size());
1276 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_BOOKMARK,
1277 ui::PageTransitionStripQualifier(query_url_visits_[0].transition));
1278
1279 // Original URL.
1280 history_service_->AddPage(
1281 test_url, base::Time::Now(), NULL, 0, GURL(),
1282 history::RedirectList(), ui::PAGE_TRANSITION_LINK,
1283 history::SOURCE_BROWSED, false);
1284 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1285 EXPECT_EQ(2, query_url_row_.visit_count());
1286 EXPECT_EQ(1, query_url_row_.typed_count());
1287 ASSERT_EQ(2U, query_url_visits_.size());
1288 EXPECT_EQ(ui::PAGE_TRANSITION_LINK,
1289 ui::PageTransitionStripQualifier(query_url_visits_[1].transition));
1290 }
1291
1292 TEST_F(HistoryTest, Typed) {
1293 const ContextID context_id = reinterpret_cast<ContextID>(1);
1294
1295 ASSERT_TRUE(history_service_.get());
1296
1297 // Add the page once as typed.
1298 const GURL test_url("http://www.google.com/");
1299 history_service_->AddPage(
1300 test_url, base::Time::Now(), context_id, 0, GURL(),
1301 history::RedirectList(), ui::PAGE_TRANSITION_TYPED,
1302 history::SOURCE_BROWSED, false);
1303 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1304
1305 // We should have the same typed & visit count.
1306 EXPECT_EQ(1, query_url_row_.visit_count());
1307 EXPECT_EQ(1, query_url_row_.typed_count());
1308
1309 // Add the page again not typed.
1310 history_service_->AddPage(
1311 test_url, base::Time::Now(), context_id, 0, GURL(),
1312 history::RedirectList(), ui::PAGE_TRANSITION_LINK,
1313 history::SOURCE_BROWSED, false);
1314 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1315
1316 // The second time should not have updated the typed count.
1317 EXPECT_EQ(2, query_url_row_.visit_count());
1318 EXPECT_EQ(1, query_url_row_.typed_count());
1319
1320 // Add the page again as a generated URL.
1321 history_service_->AddPage(
1322 test_url, base::Time::Now(), context_id, 0, GURL(),
1323 history::RedirectList(), ui::PAGE_TRANSITION_GENERATED,
1324 history::SOURCE_BROWSED, false);
1325 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1326
1327 // This should have worked like a link click.
1328 EXPECT_EQ(3, query_url_row_.visit_count());
1329 EXPECT_EQ(1, query_url_row_.typed_count());
1330
1331 // Add the page again as a reload.
1332 history_service_->AddPage(
1333 test_url, base::Time::Now(), context_id, 0, GURL(),
1334 history::RedirectList(), ui::PAGE_TRANSITION_RELOAD,
1335 history::SOURCE_BROWSED, false);
1336 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1337
1338 // This should not have incremented any visit counts.
1339 EXPECT_EQ(3, query_url_row_.visit_count());
1340 EXPECT_EQ(1, query_url_row_.typed_count());
1341 }
1342
1343 TEST_F(HistoryTest, SetTitle) {
1344 ASSERT_TRUE(history_service_.get());
1345
1346 // Add a URL.
1347 const GURL existing_url("http://www.google.com/");
1348 history_service_->AddPage(
1349 existing_url, base::Time::Now(), history::SOURCE_BROWSED);
1350
1351 // Set some title.
1352 const base::string16 existing_title = base::UTF8ToUTF16("Google");
1353 history_service_->SetPageTitle(existing_url, existing_title);
1354
1355 // Make sure the title got set.
1356 EXPECT_TRUE(QueryURL(history_service_.get(), existing_url));
1357 EXPECT_EQ(existing_title, query_url_row_.title());
1358
1359 // set a title on a nonexistent page
1360 const GURL nonexistent_url("http://news.google.com/");
1361 const base::string16 nonexistent_title = base::UTF8ToUTF16("Google News");
1362 history_service_->SetPageTitle(nonexistent_url, nonexistent_title);
1363
1364 // Make sure nothing got written.
1365 EXPECT_FALSE(QueryURL(history_service_.get(), nonexistent_url));
1366 EXPECT_EQ(base::string16(), query_url_row_.title());
1367
1368 // TODO(brettw) this should also test redirects, which get the title of the
1369 // destination page.
1370 }
1371
1372 TEST_F(HistoryTest, MostVisitedURLs) {
1373 ASSERT_TRUE(history_service_.get());
1374
1375 const GURL url0("http://www.google.com/url0/");
1376 const GURL url1("http://www.google.com/url1/");
1377 const GURL url2("http://www.google.com/url2/");
1378 const GURL url3("http://www.google.com/url3/");
1379 const GURL url4("http://www.google.com/url4/");
1380
1381 const ContextID context_id = reinterpret_cast<ContextID>(1);
1382
1383 // Add two pages.
1384 history_service_->AddPage(
1385 url0, base::Time::Now(), context_id, 0, GURL(),
1386 history::RedirectList(), ui::PAGE_TRANSITION_TYPED,
1387 history::SOURCE_BROWSED, false);
1388 history_service_->AddPage(
1389 url1, base::Time::Now(), context_id, 0, GURL(),
1390 history::RedirectList(), ui::PAGE_TRANSITION_TYPED,
1391 history::SOURCE_BROWSED, false);
1392 history_service_->QueryMostVisitedURLs(
1393 20,
1394 90,
1395 base::Bind(&HistoryTest::OnMostVisitedURLsAvailable,
1396 base::Unretained(this)),
1397 &tracker_);
1398 base::MessageLoop::current()->Run();
1399
1400 EXPECT_EQ(2U, most_visited_urls_.size());
1401 EXPECT_EQ(url0, most_visited_urls_[0].url);
1402 EXPECT_EQ(url1, most_visited_urls_[1].url);
1403
1404 // Add another page.
1405 history_service_->AddPage(
1406 url2, base::Time::Now(), context_id, 0, GURL(),
1407 history::RedirectList(), ui::PAGE_TRANSITION_TYPED,
1408 history::SOURCE_BROWSED, false);
1409 history_service_->QueryMostVisitedURLs(
1410 20,
1411 90,
1412 base::Bind(&HistoryTest::OnMostVisitedURLsAvailable,
1413 base::Unretained(this)),
1414 &tracker_);
1415 base::MessageLoop::current()->Run();
1416
1417 EXPECT_EQ(3U, most_visited_urls_.size());
1418 EXPECT_EQ(url0, most_visited_urls_[0].url);
1419 EXPECT_EQ(url1, most_visited_urls_[1].url);
1420 EXPECT_EQ(url2, most_visited_urls_[2].url);
1421
1422 // Revisit url2, making it the top URL.
1423 history_service_->AddPage(
1424 url2, base::Time::Now(), context_id, 0, GURL(),
1425 history::RedirectList(), ui::PAGE_TRANSITION_TYPED,
1426 history::SOURCE_BROWSED, false);
1427 history_service_->QueryMostVisitedURLs(
1428 20,
1429 90,
1430 base::Bind(&HistoryTest::OnMostVisitedURLsAvailable,
1431 base::Unretained(this)),
1432 &tracker_);
1433 base::MessageLoop::current()->Run();
1434
1435 EXPECT_EQ(3U, most_visited_urls_.size());
1436 EXPECT_EQ(url2, most_visited_urls_[0].url);
1437 EXPECT_EQ(url0, most_visited_urls_[1].url);
1438 EXPECT_EQ(url1, most_visited_urls_[2].url);
1439
1440 // Revisit url1, making it the top URL.
1441 history_service_->AddPage(
1442 url1, base::Time::Now(), context_id, 0, GURL(),
1443 history::RedirectList(), ui::PAGE_TRANSITION_TYPED,
1444 history::SOURCE_BROWSED, false);
1445 history_service_->QueryMostVisitedURLs(
1446 20,
1447 90,
1448 base::Bind(&HistoryTest::OnMostVisitedURLsAvailable,
1449 base::Unretained(this)),
1450 &tracker_);
1451 base::MessageLoop::current()->Run();
1452
1453 EXPECT_EQ(3U, most_visited_urls_.size());
1454 EXPECT_EQ(url1, most_visited_urls_[0].url);
1455 EXPECT_EQ(url2, most_visited_urls_[1].url);
1456 EXPECT_EQ(url0, most_visited_urls_[2].url);
1457
1458 // Redirects
1459 history::RedirectList redirects;
1460 redirects.push_back(url3);
1461 redirects.push_back(url4);
1462
1463 // Visit url4 using redirects.
1464 history_service_->AddPage(
1465 url4, base::Time::Now(), context_id, 0, GURL(),
1466 redirects, ui::PAGE_TRANSITION_TYPED,
1467 history::SOURCE_BROWSED, false);
1468 history_service_->QueryMostVisitedURLs(
1469 20,
1470 90,
1471 base::Bind(&HistoryTest::OnMostVisitedURLsAvailable,
1472 base::Unretained(this)),
1473 &tracker_);
1474 base::MessageLoop::current()->Run();
1475
1476 EXPECT_EQ(4U, most_visited_urls_.size());
1477 EXPECT_EQ(url1, most_visited_urls_[0].url);
1478 EXPECT_EQ(url2, most_visited_urls_[1].url);
1479 EXPECT_EQ(url0, most_visited_urls_[2].url);
1480 EXPECT_EQ(url3, most_visited_urls_[3].url);
1481 EXPECT_EQ(2U, most_visited_urls_[3].redirects.size());
1482 }
1483
1484 namespace {
1485
1486 // A HistoryDBTask implementation. Each time RunOnDBThread is invoked
1487 // invoke_count is increment. When invoked kWantInvokeCount times, true is
1488 // returned from RunOnDBThread which should stop RunOnDBThread from being
1489 // invoked again. When DoneRunOnMainThread is invoked, done_invoked is set to
1490 // true.
1491 class HistoryDBTaskImpl : public HistoryDBTask {
1492 public:
1493 static const int kWantInvokeCount;
1494
1495 HistoryDBTaskImpl(int* invoke_count, bool* done_invoked)
1496 : invoke_count_(invoke_count), done_invoked_(done_invoked) {}
1497
1498 bool RunOnDBThread(HistoryBackend* backend, HistoryDatabase* db) override {
1499 return (++*invoke_count_ == kWantInvokeCount);
1500 }
1501
1502 void DoneRunOnMainThread() override {
1503 *done_invoked_ = true;
1504 base::MessageLoop::current()->Quit();
1505 }
1506
1507 int* invoke_count_;
1508 bool* done_invoked_;
1509
1510 private:
1511 ~HistoryDBTaskImpl() override {}
1512
1513 DISALLOW_COPY_AND_ASSIGN(HistoryDBTaskImpl);
1514 };
1515
1516 // static
1517 const int HistoryDBTaskImpl::kWantInvokeCount = 2;
1518
1519 } // namespace
1520
1521 TEST_F(HistoryTest, HistoryDBTask) {
1522 ASSERT_TRUE(history_service_.get());
1523 base::CancelableTaskTracker task_tracker;
1524 int invoke_count = 0;
1525 bool done_invoked = false;
1526 history_service_->ScheduleDBTask(
1527 scoped_ptr<history::HistoryDBTask>(
1528 new HistoryDBTaskImpl(&invoke_count, &done_invoked)),
1529 &task_tracker);
1530 // Run the message loop. When HistoryDBTaskImpl::DoneRunOnMainThread runs,
1531 // it will stop the message loop. If the test hangs here, it means
1532 // DoneRunOnMainThread isn't being invoked correctly.
1533 base::MessageLoop::current()->Run();
1534 CleanupHistoryService();
1535 // WARNING: history has now been deleted.
1536 history_service_.reset();
1537 ASSERT_EQ(HistoryDBTaskImpl::kWantInvokeCount, invoke_count);
1538 ASSERT_TRUE(done_invoked);
1539 }
1540
1541 TEST_F(HistoryTest, HistoryDBTaskCanceled) {
1542 ASSERT_TRUE(history_service_.get());
1543 base::CancelableTaskTracker task_tracker;
1544 int invoke_count = 0;
1545 bool done_invoked = false;
1546 history_service_->ScheduleDBTask(
1547 scoped_ptr<history::HistoryDBTask>(
1548 new HistoryDBTaskImpl(&invoke_count, &done_invoked)),
1549 &task_tracker);
1550 task_tracker.TryCancelAll();
1551 CleanupHistoryService();
1552 // WARNING: history has now been deleted.
1553 history_service_.reset();
1554 ASSERT_FALSE(done_invoked);
1555 }
1556
1557 // Create a local delete directive and process it while sync is
1558 // online, and then when offline. The delete directive should be sent to sync,
1559 // no error should be returned for the first time, and an error should be
1560 // returned for the second time.
1561 TEST_F(HistoryTest, ProcessLocalDeleteDirectiveSyncOnline) {
1562 ASSERT_TRUE(history_service_.get());
1563
1564 const GURL test_url("http://www.google.com/");
1565 for (int64 i = 1; i <= 10; ++i) {
1566 base::Time t =
1567 base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(i);
1568 history_service_->AddPage(test_url, t, NULL, 0, GURL(),
1569 history::RedirectList(),
1570 ui::PAGE_TRANSITION_LINK,
1571 history::SOURCE_BROWSED, false);
1572 }
1573
1574 sync_pb::HistoryDeleteDirectiveSpecifics delete_directive;
1575 sync_pb::GlobalIdDirective* global_id_directive =
1576 delete_directive.mutable_global_id_directive();
1577 global_id_directive->add_global_id(
1578 (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1))
1579 .ToInternalValue());
1580
1581 syncer::FakeSyncChangeProcessor change_processor;
1582
1583 EXPECT_FALSE(
1584 history_service_->MergeDataAndStartSyncing(
1585 syncer::HISTORY_DELETE_DIRECTIVES,
1586 syncer::SyncDataList(),
1587 scoped_ptr<syncer::SyncChangeProcessor>(
1588 new syncer::SyncChangeProcessorWrapperForTest(
1589 &change_processor)),
1590 scoped_ptr<syncer::SyncErrorFactory>())
1591 .error()
1592 .IsSet());
1593
1594 syncer::SyncError err =
1595 history_service_->ProcessLocalDeleteDirective(delete_directive);
1596 EXPECT_FALSE(err.IsSet());
1597 EXPECT_EQ(1u, change_processor.changes().size());
1598
1599 history_service_->StopSyncing(syncer::HISTORY_DELETE_DIRECTIVES);
1600 err = history_service_->ProcessLocalDeleteDirective(delete_directive);
1601 EXPECT_TRUE(err.IsSet());
1602 EXPECT_EQ(1u, change_processor.changes().size());
1603 }
1604
1605 // Closure function that runs periodically to check result of delete directive
1606 // processing. Stop when timeout or processing ends indicated by the creation
1607 // of sync changes.
1608 void CheckDirectiveProcessingResult(
1609 Time timeout,
1610 const syncer::FakeSyncChangeProcessor* change_processor,
1611 uint32 num_changes) {
1612 if (base::Time::Now() > timeout ||
1613 change_processor->changes().size() >= num_changes) {
1614 return;
1615 }
1616
1617 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
1618 base::MessageLoop::current()->PostTask(
1619 FROM_HERE,
1620 base::Bind(&CheckDirectiveProcessingResult, timeout,
1621 change_processor, num_changes));
1622 }
1623
1624 // Create a delete directive for a few specific history entries,
1625 // including ones that don't exist. The expected entries should be
1626 // deleted.
1627 TEST_F(HistoryTest, ProcessGlobalIdDeleteDirective) {
1628 ASSERT_TRUE(history_service_.get());
1629 const GURL test_url("http://www.google.com/");
1630 for (int64 i = 1; i <= 20; i++) {
1631 base::Time t =
1632 base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(i);
1633 history_service_->AddPage(test_url, t, NULL, 0, GURL(),
1634 history::RedirectList(),
1635 ui::PAGE_TRANSITION_LINK,
1636 history::SOURCE_BROWSED, false);
1637 }
1638
1639 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1640 EXPECT_EQ(20, query_url_row_.visit_count());
1641
1642 syncer::SyncDataList directives;
1643 // 1st directive.
1644 sync_pb::EntitySpecifics entity_specs;
1645 sync_pb::GlobalIdDirective* global_id_directive =
1646 entity_specs.mutable_history_delete_directive()
1647 ->mutable_global_id_directive();
1648 global_id_directive->add_global_id(
1649 (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(6))
1650 .ToInternalValue());
1651 global_id_directive->set_start_time_usec(3);
1652 global_id_directive->set_end_time_usec(10);
1653 directives.push_back(syncer::SyncData::CreateRemoteData(
1654 1,
1655 entity_specs,
1656 base::Time(),
1657 syncer::AttachmentIdList(),
1658 syncer::AttachmentServiceProxyForTest::Create()));
1659
1660 // 2nd directive.
1661 global_id_directive->Clear();
1662 global_id_directive->add_global_id(
1663 (base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(17))
1664 .ToInternalValue());
1665 global_id_directive->set_start_time_usec(13);
1666 global_id_directive->set_end_time_usec(19);
1667 directives.push_back(syncer::SyncData::CreateRemoteData(
1668 2,
1669 entity_specs,
1670 base::Time(),
1671 syncer::AttachmentIdList(),
1672 syncer::AttachmentServiceProxyForTest::Create()));
1673
1674 syncer::FakeSyncChangeProcessor change_processor;
1675 EXPECT_FALSE(
1676 history_service_->MergeDataAndStartSyncing(
1677 syncer::HISTORY_DELETE_DIRECTIVES,
1678 directives,
1679 scoped_ptr<syncer::SyncChangeProcessor>(
1680 new syncer::SyncChangeProcessorWrapperForTest(
1681 &change_processor)),
1682 scoped_ptr<syncer::SyncErrorFactory>())
1683 .error()
1684 .IsSet());
1685
1686 // Inject a task to check status and keep message loop filled before directive
1687 // processing finishes.
1688 base::MessageLoop::current()->PostTask(
1689 FROM_HERE,
1690 base::Bind(&CheckDirectiveProcessingResult,
1691 base::Time::Now() + base::TimeDelta::FromSeconds(10),
1692 &change_processor, 2));
1693 base::MessageLoop::current()->RunUntilIdle();
1694 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1695 ASSERT_EQ(5, query_url_row_.visit_count());
1696 EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1),
1697 query_url_visits_[0].visit_time);
1698 EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(2),
1699 query_url_visits_[1].visit_time);
1700 EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(11),
1701 query_url_visits_[2].visit_time);
1702 EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(12),
1703 query_url_visits_[3].visit_time);
1704 EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(20),
1705 query_url_visits_[4].visit_time);
1706
1707 // Expect two sync changes for deleting processed directives.
1708 const syncer::SyncChangeList& sync_changes = change_processor.changes();
1709 ASSERT_EQ(2u, sync_changes.size());
1710 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
1711 EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
1712 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
1713 EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
1714 }
1715
1716 // Create delete directives for time ranges. The expected entries should be
1717 // deleted.
1718 TEST_F(HistoryTest, ProcessTimeRangeDeleteDirective) {
1719 ASSERT_TRUE(history_service_.get());
1720 const GURL test_url("http://www.google.com/");
1721 for (int64 i = 1; i <= 10; ++i) {
1722 base::Time t =
1723 base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(i);
1724 history_service_->AddPage(test_url, t, NULL, 0, GURL(),
1725 history::RedirectList(),
1726 ui::PAGE_TRANSITION_LINK,
1727 history::SOURCE_BROWSED, false);
1728 }
1729
1730 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1731 EXPECT_EQ(10, query_url_row_.visit_count());
1732
1733 syncer::SyncDataList directives;
1734 // 1st directive.
1735 sync_pb::EntitySpecifics entity_specs;
1736 sync_pb::TimeRangeDirective* time_range_directive =
1737 entity_specs.mutable_history_delete_directive()
1738 ->mutable_time_range_directive();
1739 time_range_directive->set_start_time_usec(2);
1740 time_range_directive->set_end_time_usec(5);
1741 directives.push_back(syncer::SyncData::CreateRemoteData(
1742 1,
1743 entity_specs,
1744 base::Time(),
1745 syncer::AttachmentIdList(),
1746 syncer::AttachmentServiceProxyForTest::Create()));
1747
1748 // 2nd directive.
1749 time_range_directive->Clear();
1750 time_range_directive->set_start_time_usec(8);
1751 time_range_directive->set_end_time_usec(10);
1752 directives.push_back(syncer::SyncData::CreateRemoteData(
1753 2,
1754 entity_specs,
1755 base::Time(),
1756 syncer::AttachmentIdList(),
1757 syncer::AttachmentServiceProxyForTest::Create()));
1758
1759 syncer::FakeSyncChangeProcessor change_processor;
1760 EXPECT_FALSE(
1761 history_service_->MergeDataAndStartSyncing(
1762 syncer::HISTORY_DELETE_DIRECTIVES,
1763 directives,
1764 scoped_ptr<syncer::SyncChangeProcessor>(
1765 new syncer::SyncChangeProcessorWrapperForTest(
1766 &change_processor)),
1767 scoped_ptr<syncer::SyncErrorFactory>())
1768 .error()
1769 .IsSet());
1770
1771 // Inject a task to check status and keep message loop filled before
1772 // directive processing finishes.
1773 base::MessageLoop::current()->PostTask(
1774 FROM_HERE,
1775 base::Bind(&CheckDirectiveProcessingResult,
1776 base::Time::Now() + base::TimeDelta::FromSeconds(10),
1777 &change_processor, 2));
1778 base::MessageLoop::current()->RunUntilIdle();
1779 EXPECT_TRUE(QueryURL(history_service_.get(), test_url));
1780 ASSERT_EQ(3, query_url_row_.visit_count());
1781 EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(1),
1782 query_url_visits_[0].visit_time);
1783 EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(6),
1784 query_url_visits_[1].visit_time);
1785 EXPECT_EQ(base::Time::UnixEpoch() + base::TimeDelta::FromMicroseconds(7),
1786 query_url_visits_[2].visit_time);
1787
1788 // Expect two sync changes for deleting processed directives.
1789 const syncer::SyncChangeList& sync_changes = change_processor.changes();
1790 ASSERT_EQ(2u, sync_changes.size());
1791 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[0].change_type());
1792 EXPECT_EQ(1, syncer::SyncDataRemote(sync_changes[0].sync_data()).GetId());
1793 EXPECT_EQ(syncer::SyncChange::ACTION_DELETE, sync_changes[1].change_type());
1794 EXPECT_EQ(2, syncer::SyncDataRemote(sync_changes[1].sync_data()).GetId());
1795 }
1796
1797 TEST_F(HistoryBackendDBTest, MigratePresentations) {
1798 // Create the db we want. Use 22 since segments didn't change in that time
1799 // frame.
1800 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22));
1801
1802 const SegmentID segment_id = 2;
1803 const URLID url_id = 3;
1804 const GURL url("http://www.foo.com");
1805 const std::string url_name(VisitSegmentDatabase::ComputeSegmentName(url));
1806 const base::string16 title(base::ASCIIToUTF16("Title1"));
1807 const Time segment_time(Time::Now());
1808
1809 {
1810 // Re-open the db for manual manipulation.
1811 sql::Connection db;
1812 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
1813
1814 // Add an entry to urls.
1815 {
1816 sql::Statement s(db.GetUniqueStatement(
1817 "INSERT INTO urls "
1818 "(id, url, title, last_visit_time) VALUES "
1819 "(?, ?, ?, ?)"));
1820 s.BindInt64(0, url_id);
1821 s.BindString(1, url.spec());
1822 s.BindString16(2, title);
1823 s.BindInt64(3, segment_time.ToInternalValue());
1824 ASSERT_TRUE(s.Run());
1825 }
1826
1827 // Add an entry to segments.
1828 {
1829 sql::Statement s(db.GetUniqueStatement(
1830 "INSERT INTO segments "
1831 "(id, name, url_id, pres_index) VALUES "
1832 "(?, ?, ?, ?)"));
1833 s.BindInt64(0, segment_id);
1834 s.BindString(1, url_name);
1835 s.BindInt64(2, url_id);
1836 s.BindInt(3, 4); // pres_index
1837 ASSERT_TRUE(s.Run());
1838 }
1839
1840 // And one to segment_usage.
1841 {
1842 sql::Statement s(db.GetUniqueStatement(
1843 "INSERT INTO segment_usage "
1844 "(id, segment_id, time_slot, visit_count) VALUES "
1845 "(?, ?, ?, ?)"));
1846 s.BindInt64(0, 4); // id.
1847 s.BindInt64(1, segment_id);
1848 s.BindInt64(2, segment_time.ToInternalValue());
1849 s.BindInt(3, 5); // visit count.
1850 ASSERT_TRUE(s.Run());
1851 }
1852 }
1853
1854 // Re-open the db, triggering migration.
1855 CreateBackendAndDatabase();
1856
1857 std::vector<PageUsageData*> results;
1858 db_->QuerySegmentUsage(segment_time, 10, &results);
1859 ASSERT_EQ(1u, results.size());
1860 EXPECT_EQ(url, results[0]->GetURL());
1861 EXPECT_EQ(segment_id, results[0]->GetID());
1862 EXPECT_EQ(title, results[0]->GetTitle());
1863 STLDeleteElements(&results);
1864 }
1865
1866 } // namespace history
OLDNEW
« no previous file with comments | « chrome/browser/history/history_backend_unittest.cc ('k') | chrome/browser/history/thumbnail_database_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698