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