OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // History unit tests come in two flavors: | 5 // History unit tests come in two flavors: |
6 // | 6 // |
7 // 1. The more complicated style is that the unit test creates a full history | 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 | 8 // service. This spawns a background thread for the history backend, and |
9 // all communication is asynchronous. This is useful for testing more | 9 // all communication is asynchronous. This is useful for testing more |
10 // complicated things or end-to-end behavior. | 10 // complicated things or end-to-end behavior. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 #include "chrome/browser/history/history_backend.h" | 46 #include "chrome/browser/history/history_backend.h" |
47 #include "chrome/browser/history/history_database.h" | 47 #include "chrome/browser/history/history_database.h" |
48 #include "chrome/browser/history/history_db_task.h" | 48 #include "chrome/browser/history/history_db_task.h" |
49 #include "chrome/browser/history/history_notifications.h" | 49 #include "chrome/browser/history/history_notifications.h" |
50 #include "chrome/browser/history/history_service.h" | 50 #include "chrome/browser/history/history_service.h" |
51 #include "chrome/browser/history/history_unittest_base.h" | 51 #include "chrome/browser/history/history_unittest_base.h" |
52 #include "chrome/browser/history/in_memory_history_backend.h" | 52 #include "chrome/browser/history/in_memory_history_backend.h" |
53 #include "chrome/common/chrome_constants.h" | 53 #include "chrome/common/chrome_constants.h" |
54 #include "chrome/common/chrome_paths.h" | 54 #include "chrome/common/chrome_paths.h" |
55 #include "chrome/tools/profiles/thumbnail-inl.h" | 55 #include "chrome/tools/profiles/thumbnail-inl.h" |
| 56 #include "components/history/core/browser/history_constants.h" |
56 #include "components/history/core/browser/in_memory_database.h" | 57 #include "components/history/core/browser/in_memory_database.h" |
57 #include "components/history/core/browser/page_usage_data.h" | 58 #include "components/history/core/browser/page_usage_data.h" |
58 #include "components/history/core/common/thumbnail_score.h" | 59 #include "components/history/core/common/thumbnail_score.h" |
59 #include "content/public/browser/download_item.h" | 60 #include "content/public/browser/download_item.h" |
60 #include "content/public/browser/notification_details.h" | 61 #include "content/public/browser/notification_details.h" |
61 #include "content/public/browser/notification_source.h" | 62 #include "content/public/browser/notification_source.h" |
62 #include "sql/connection.h" | 63 #include "sql/connection.h" |
63 #include "sql/statement.h" | 64 #include "sql/statement.h" |
64 #include "sync/api/attachments/attachment_id.h" | 65 #include "sync/api/attachments/attachment_id.h" |
65 #include "sync/api/fake_sync_change_processor.h" | 66 #include "sync/api/fake_sync_change_processor.h" |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 "HistoryBackend::Init"; | 134 "HistoryBackend::Init"; |
134 } | 135 } |
135 | 136 |
136 void CreateDBVersion(int version) { | 137 void CreateDBVersion(int version) { |
137 base::FilePath data_path; | 138 base::FilePath data_path; |
138 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); | 139 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); |
139 data_path = data_path.AppendASCII("History"); | 140 data_path = data_path.AppendASCII("History"); |
140 data_path = | 141 data_path = |
141 data_path.AppendASCII(base::StringPrintf("history.%d.sql", version)); | 142 data_path.AppendASCII(base::StringPrintf("history.%d.sql", version)); |
142 ASSERT_NO_FATAL_FAILURE( | 143 ASSERT_NO_FATAL_FAILURE( |
143 ExecuteSQLScript(data_path, history_dir_.Append( | 144 ExecuteSQLScript(data_path, history_dir_.Append(kHistoryFilename))); |
144 chrome::kHistoryFilename))); | |
145 } | 145 } |
146 | 146 |
147 void CreateArchivedDB() { | 147 void CreateArchivedDB() { |
148 base::FilePath data_path; | 148 base::FilePath data_path; |
149 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); | 149 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path)); |
150 data_path = data_path.AppendASCII("History"); | 150 data_path = data_path.AppendASCII("History"); |
151 data_path = data_path.AppendASCII("archived_history.4.sql"); | 151 data_path = data_path.AppendASCII("archived_history.4.sql"); |
152 ASSERT_NO_FATAL_FAILURE( | 152 ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript( |
153 ExecuteSQLScript(data_path, history_dir_.Append( | 153 data_path, history_dir_.Append(kArchivedHistoryFilename))); |
154 chrome::kArchivedHistoryFilename))); | |
155 } | 154 } |
156 | 155 |
157 // testing::Test | 156 // testing::Test |
158 void SetUp() override { | 157 void SetUp() override { |
159 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 158 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
160 history_dir_ = temp_dir_.path().AppendASCII("HistoryBackendDBTest"); | 159 history_dir_ = temp_dir_.path().AppendASCII("HistoryBackendDBTest"); |
161 ASSERT_TRUE(base::CreateDirectory(history_dir_)); | 160 ASSERT_TRUE(base::CreateDirectory(history_dir_)); |
162 } | 161 } |
163 | 162 |
164 void DeleteBackend() { | 163 void DeleteBackend() { |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 db_->QueryDownloads(&downloads); | 280 db_->QueryDownloads(&downloads); |
282 EXPECT_EQ(0U, downloads.size()); | 281 EXPECT_EQ(0U, downloads.size()); |
283 } | 282 } |
284 | 283 |
285 TEST_F(HistoryBackendDBTest, MigrateDownloadsState) { | 284 TEST_F(HistoryBackendDBTest, MigrateDownloadsState) { |
286 // Create the db we want. | 285 // Create the db we want. |
287 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22)); | 286 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22)); |
288 { | 287 { |
289 // Open the db for manual manipulation. | 288 // Open the db for manual manipulation. |
290 sql::Connection db; | 289 sql::Connection db; |
291 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 290 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
292 | 291 |
293 // Manually insert corrupted rows; there's infrastructure in place now to | 292 // Manually insert corrupted rows; there's infrastructure in place now to |
294 // make this impossible, at least according to the test above. | 293 // make this impossible, at least according to the test above. |
295 for (int state = 0; state < 5; ++state) { | 294 for (int state = 0; state < 5; ++state) { |
296 sql::Statement s(db.GetUniqueStatement( | 295 sql::Statement s(db.GetUniqueStatement( |
297 "INSERT INTO downloads (id, full_path, url, start_time, " | 296 "INSERT INTO downloads (id, full_path, url, start_time, " |
298 "received_bytes, total_bytes, state, end_time, opened) VALUES " | 297 "received_bytes, total_bytes, state, end_time, opened) VALUES " |
299 "(?, ?, ?, ?, ?, ?, ?, ?, ?)")); | 298 "(?, ?, ?, ?, ?, ?, ?, ?, ?)")); |
300 s.BindInt64(0, 1 + state); | 299 s.BindInt64(0, 1 + state); |
301 s.BindString(1, "path"); | 300 s.BindString(1, "path"); |
302 s.BindString(2, "url"); | 301 s.BindString(2, "url"); |
303 s.BindInt64(3, base::Time::Now().ToTimeT()); | 302 s.BindInt64(3, base::Time::Now().ToTimeT()); |
304 s.BindInt64(4, 100); | 303 s.BindInt64(4, 100); |
305 s.BindInt64(5, 100); | 304 s.BindInt64(5, 100); |
306 s.BindInt(6, state); | 305 s.BindInt(6, state); |
307 s.BindInt64(7, base::Time::Now().ToTimeT()); | 306 s.BindInt64(7, base::Time::Now().ToTimeT()); |
308 s.BindInt(8, state % 2); | 307 s.BindInt(8, state % 2); |
309 ASSERT_TRUE(s.Run()); | 308 ASSERT_TRUE(s.Run()); |
310 } | 309 } |
311 } | 310 } |
312 | 311 |
313 // Re-open the db using the HistoryDatabase, which should migrate from version | 312 // Re-open the db using the HistoryDatabase, which should migrate from version |
314 // 22 to the current version, fixing just the row whose state was 3. | 313 // 22 to the current version, fixing just the row whose state was 3. |
315 // Then close the db so that we can re-open it directly. | 314 // Then close the db so that we can re-open it directly. |
316 CreateBackendAndDatabase(); | 315 CreateBackendAndDatabase(); |
317 DeleteBackend(); | 316 DeleteBackend(); |
318 { | 317 { |
319 // Re-open the db for manual manipulation. | 318 // Re-open the db for manual manipulation. |
320 sql::Connection db; | 319 sql::Connection db; |
321 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 320 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
322 { | 321 { |
323 // The version should have been updated. | 322 // The version should have been updated. |
324 int cur_version = HistoryDatabase::GetCurrentVersion(); | 323 int cur_version = HistoryDatabase::GetCurrentVersion(); |
325 ASSERT_LT(22, cur_version); | 324 ASSERT_LT(22, cur_version); |
326 sql::Statement s(db.GetUniqueStatement( | 325 sql::Statement s(db.GetUniqueStatement( |
327 "SELECT value FROM meta WHERE key = 'version'")); | 326 "SELECT value FROM meta WHERE key = 'version'")); |
328 EXPECT_TRUE(s.Step()); | 327 EXPECT_TRUE(s.Step()); |
329 EXPECT_EQ(cur_version, s.ColumnInt(0)); | 328 EXPECT_EQ(cur_version, s.ColumnInt(0)); |
330 } | 329 } |
331 { | 330 { |
(...skipping 17 matching lines...) Expand all Loading... |
349 | 348 |
350 TEST_F(HistoryBackendDBTest, MigrateDownloadsReasonPathsAndDangerType) { | 349 TEST_F(HistoryBackendDBTest, MigrateDownloadsReasonPathsAndDangerType) { |
351 Time now(base::Time::Now()); | 350 Time now(base::Time::Now()); |
352 | 351 |
353 // Create the db we want. The schema didn't change from 22->23, so just | 352 // Create the db we want. The schema didn't change from 22->23, so just |
354 // re-use the v22 file. | 353 // re-use the v22 file. |
355 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22)); | 354 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22)); |
356 { | 355 { |
357 // Re-open the db for manual manipulation. | 356 // Re-open the db for manual manipulation. |
358 sql::Connection db; | 357 sql::Connection db; |
359 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 358 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
360 | 359 |
361 // Manually insert some rows. | 360 // Manually insert some rows. |
362 sql::Statement s(db.GetUniqueStatement( | 361 sql::Statement s(db.GetUniqueStatement( |
363 "INSERT INTO downloads (id, full_path, url, start_time, " | 362 "INSERT INTO downloads (id, full_path, url, start_time, " |
364 "received_bytes, total_bytes, state, end_time, opened) VALUES " | 363 "received_bytes, total_bytes, state, end_time, opened) VALUES " |
365 "(?, ?, ?, ?, ?, ?, ?, ?, ?)")); | 364 "(?, ?, ?, ?, ?, ?, ?, ?, ?)")); |
366 | 365 |
367 int64 id = 0; | 366 int64 id = 0; |
368 // Null path. | 367 // Null path. |
369 s.BindInt64(0, ++id); | 368 s.BindInt64(0, ++id); |
(...skipping 22 matching lines...) Expand all Loading... |
392 } | 391 } |
393 | 392 |
394 // Re-open the db using the HistoryDatabase, which should migrate from version | 393 // Re-open the db using the HistoryDatabase, which should migrate from version |
395 // 23 to 24, creating the new tables and creating the new path, reason, | 394 // 23 to 24, creating the new tables and creating the new path, reason, |
396 // and danger columns. | 395 // and danger columns. |
397 CreateBackendAndDatabase(); | 396 CreateBackendAndDatabase(); |
398 DeleteBackend(); | 397 DeleteBackend(); |
399 { | 398 { |
400 // Re-open the db for manual manipulation. | 399 // Re-open the db for manual manipulation. |
401 sql::Connection db; | 400 sql::Connection db; |
402 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 401 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
403 { | 402 { |
404 // The version should have been updated. | 403 // The version should have been updated. |
405 int cur_version = HistoryDatabase::GetCurrentVersion(); | 404 int cur_version = HistoryDatabase::GetCurrentVersion(); |
406 ASSERT_LT(23, cur_version); | 405 ASSERT_LT(23, cur_version); |
407 sql::Statement s(db.GetUniqueStatement( | 406 sql::Statement s(db.GetUniqueStatement( |
408 "SELECT value FROM meta WHERE key = 'version'")); | 407 "SELECT value FROM meta WHERE key = 'version'")); |
409 EXPECT_TRUE(s.Step()); | 408 EXPECT_TRUE(s.Step()); |
410 EXPECT_EQ(cur_version, s.ColumnInt(0)); | 409 EXPECT_EQ(cur_version, s.ColumnInt(0)); |
411 } | 410 } |
412 { | 411 { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 EXPECT_FALSE(statement.Step()); | 458 EXPECT_FALSE(statement.Step()); |
460 } | 459 } |
461 } | 460 } |
462 } | 461 } |
463 | 462 |
464 TEST_F(HistoryBackendDBTest, MigrateReferrer) { | 463 TEST_F(HistoryBackendDBTest, MigrateReferrer) { |
465 Time now(base::Time::Now()); | 464 Time now(base::Time::Now()); |
466 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22)); | 465 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(22)); |
467 { | 466 { |
468 sql::Connection db; | 467 sql::Connection db; |
469 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 468 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
470 sql::Statement s(db.GetUniqueStatement( | 469 sql::Statement s(db.GetUniqueStatement( |
471 "INSERT INTO downloads (id, full_path, url, start_time, " | 470 "INSERT INTO downloads (id, full_path, url, start_time, " |
472 "received_bytes, total_bytes, state, end_time, opened) VALUES " | 471 "received_bytes, total_bytes, state, end_time, opened) VALUES " |
473 "(?, ?, ?, ?, ?, ?, ?, ?, ?)")); | 472 "(?, ?, ?, ?, ?, ?, ?, ?, ?)")); |
474 int64 db_handle = 0; | 473 int64 db_handle = 0; |
475 s.BindInt64(0, ++db_handle); | 474 s.BindInt64(0, ++db_handle); |
476 s.BindString(1, "full_path"); | 475 s.BindString(1, "full_path"); |
477 s.BindString(2, "http://whatever.com/index.html"); | 476 s.BindString(2, "http://whatever.com/index.html"); |
478 s.BindInt64(3, now.ToTimeT()); | 477 s.BindInt64(3, now.ToTimeT()); |
479 s.BindInt64(4, 100); | 478 s.BindInt64(4, 100); |
480 s.BindInt64(5, 100); | 479 s.BindInt64(5, 100); |
481 s.BindInt(6, 1); | 480 s.BindInt(6, 1); |
482 s.BindInt64(7, now.ToTimeT()); | 481 s.BindInt64(7, now.ToTimeT()); |
483 s.BindInt(8, 1); | 482 s.BindInt(8, 1); |
484 ASSERT_TRUE(s.Run()); | 483 ASSERT_TRUE(s.Run()); |
485 } | 484 } |
486 // Re-open the db using the HistoryDatabase, which should migrate to version | 485 // Re-open the db using the HistoryDatabase, which should migrate to version |
487 // 26, creating the referrer column. | 486 // 26, creating the referrer column. |
488 CreateBackendAndDatabase(); | 487 CreateBackendAndDatabase(); |
489 DeleteBackend(); | 488 DeleteBackend(); |
490 { | 489 { |
491 // Re-open the db for manual manipulation. | 490 // Re-open the db for manual manipulation. |
492 sql::Connection db; | 491 sql::Connection db; |
493 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 492 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
494 // The version should have been updated. | 493 // The version should have been updated. |
495 int cur_version = HistoryDatabase::GetCurrentVersion(); | 494 int cur_version = HistoryDatabase::GetCurrentVersion(); |
496 ASSERT_LE(26, cur_version); | 495 ASSERT_LE(26, cur_version); |
497 { | 496 { |
498 sql::Statement s(db.GetUniqueStatement( | 497 sql::Statement s(db.GetUniqueStatement( |
499 "SELECT value FROM meta WHERE key = 'version'")); | 498 "SELECT value FROM meta WHERE key = 'version'")); |
500 EXPECT_TRUE(s.Step()); | 499 EXPECT_TRUE(s.Step()); |
501 EXPECT_EQ(cur_version, s.ColumnInt(0)); | 500 EXPECT_EQ(cur_version, s.ColumnInt(0)); |
502 } | 501 } |
503 { | 502 { |
504 sql::Statement s(db.GetUniqueStatement( | 503 sql::Statement s(db.GetUniqueStatement( |
505 "SELECT referrer from downloads")); | 504 "SELECT referrer from downloads")); |
506 EXPECT_TRUE(s.Step()); | 505 EXPECT_TRUE(s.Step()); |
507 EXPECT_EQ(std::string(), s.ColumnString(0)); | 506 EXPECT_EQ(std::string(), s.ColumnString(0)); |
508 } | 507 } |
509 } | 508 } |
510 } | 509 } |
511 | 510 |
512 TEST_F(HistoryBackendDBTest, MigrateDownloadedByExtension) { | 511 TEST_F(HistoryBackendDBTest, MigrateDownloadedByExtension) { |
513 Time now(base::Time::Now()); | 512 Time now(base::Time::Now()); |
514 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(26)); | 513 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(26)); |
515 { | 514 { |
516 sql::Connection db; | 515 sql::Connection db; |
517 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 516 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
518 { | 517 { |
519 sql::Statement s(db.GetUniqueStatement( | 518 sql::Statement s(db.GetUniqueStatement( |
520 "INSERT INTO downloads (id, current_path, target_path, start_time, " | 519 "INSERT INTO downloads (id, current_path, target_path, start_time, " |
521 "received_bytes, total_bytes, state, danger_type, interrupt_reason, " | 520 "received_bytes, total_bytes, state, danger_type, interrupt_reason, " |
522 "end_time, opened, referrer) VALUES " | 521 "end_time, opened, referrer) VALUES " |
523 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); | 522 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); |
524 s.BindInt64(0, 1); | 523 s.BindInt64(0, 1); |
525 s.BindString(1, "current_path"); | 524 s.BindString(1, "current_path"); |
526 s.BindString(2, "target_path"); | 525 s.BindString(2, "target_path"); |
527 s.BindInt64(3, now.ToTimeT()); | 526 s.BindInt64(3, now.ToTimeT()); |
(...skipping 17 matching lines...) Expand all Loading... |
545 ASSERT_TRUE(s.Run()); | 544 ASSERT_TRUE(s.Run()); |
546 } | 545 } |
547 } | 546 } |
548 // Re-open the db using the HistoryDatabase, which should migrate to version | 547 // Re-open the db using the HistoryDatabase, which should migrate to version |
549 // 27, creating the by_ext_id and by_ext_name columns. | 548 // 27, creating the by_ext_id and by_ext_name columns. |
550 CreateBackendAndDatabase(); | 549 CreateBackendAndDatabase(); |
551 DeleteBackend(); | 550 DeleteBackend(); |
552 { | 551 { |
553 // Re-open the db for manual manipulation. | 552 // Re-open the db for manual manipulation. |
554 sql::Connection db; | 553 sql::Connection db; |
555 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 554 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
556 // The version should have been updated. | 555 // The version should have been updated. |
557 int cur_version = HistoryDatabase::GetCurrentVersion(); | 556 int cur_version = HistoryDatabase::GetCurrentVersion(); |
558 ASSERT_LE(27, cur_version); | 557 ASSERT_LE(27, cur_version); |
559 { | 558 { |
560 sql::Statement s(db.GetUniqueStatement( | 559 sql::Statement s(db.GetUniqueStatement( |
561 "SELECT value FROM meta WHERE key = 'version'")); | 560 "SELECT value FROM meta WHERE key = 'version'")); |
562 EXPECT_TRUE(s.Step()); | 561 EXPECT_TRUE(s.Step()); |
563 EXPECT_EQ(cur_version, s.ColumnInt(0)); | 562 EXPECT_EQ(cur_version, s.ColumnInt(0)); |
564 } | 563 } |
565 { | 564 { |
566 sql::Statement s(db.GetUniqueStatement( | 565 sql::Statement s(db.GetUniqueStatement( |
567 "SELECT by_ext_id, by_ext_name from downloads")); | 566 "SELECT by_ext_id, by_ext_name from downloads")); |
568 EXPECT_TRUE(s.Step()); | 567 EXPECT_TRUE(s.Step()); |
569 EXPECT_EQ(std::string(), s.ColumnString(0)); | 568 EXPECT_EQ(std::string(), s.ColumnString(0)); |
570 EXPECT_EQ(std::string(), s.ColumnString(1)); | 569 EXPECT_EQ(std::string(), s.ColumnString(1)); |
571 } | 570 } |
572 } | 571 } |
573 } | 572 } |
574 | 573 |
575 TEST_F(HistoryBackendDBTest, MigrateDownloadValidators) { | 574 TEST_F(HistoryBackendDBTest, MigrateDownloadValidators) { |
576 Time now(base::Time::Now()); | 575 Time now(base::Time::Now()); |
577 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(27)); | 576 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(27)); |
578 { | 577 { |
579 sql::Connection db; | 578 sql::Connection db; |
580 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 579 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
581 { | 580 { |
582 sql::Statement s(db.GetUniqueStatement( | 581 sql::Statement s(db.GetUniqueStatement( |
583 "INSERT INTO downloads (id, current_path, target_path, start_time, " | 582 "INSERT INTO downloads (id, current_path, target_path, start_time, " |
584 "received_bytes, total_bytes, state, danger_type, interrupt_reason, " | 583 "received_bytes, total_bytes, state, danger_type, interrupt_reason, " |
585 "end_time, opened, referrer, by_ext_id, by_ext_name) VALUES " | 584 "end_time, opened, referrer, by_ext_id, by_ext_name) VALUES " |
586 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); | 585 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); |
587 s.BindInt64(0, 1); | 586 s.BindInt64(0, 1); |
588 s.BindString(1, "current_path"); | 587 s.BindString(1, "current_path"); |
589 s.BindString(2, "target_path"); | 588 s.BindString(2, "target_path"); |
590 s.BindInt64(3, now.ToTimeT()); | 589 s.BindInt64(3, now.ToTimeT()); |
(...skipping 19 matching lines...) Expand all Loading... |
610 ASSERT_TRUE(s.Run()); | 609 ASSERT_TRUE(s.Run()); |
611 } | 610 } |
612 } | 611 } |
613 // Re-open the db using the HistoryDatabase, which should migrate to the | 612 // Re-open the db using the HistoryDatabase, which should migrate to the |
614 // current version, creating the etag and last_modified columns. | 613 // current version, creating the etag and last_modified columns. |
615 CreateBackendAndDatabase(); | 614 CreateBackendAndDatabase(); |
616 DeleteBackend(); | 615 DeleteBackend(); |
617 { | 616 { |
618 // Re-open the db for manual manipulation. | 617 // Re-open the db for manual manipulation. |
619 sql::Connection db; | 618 sql::Connection db; |
620 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 619 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
621 // The version should have been updated. | 620 // The version should have been updated. |
622 int cur_version = HistoryDatabase::GetCurrentVersion(); | 621 int cur_version = HistoryDatabase::GetCurrentVersion(); |
623 ASSERT_LE(28, cur_version); | 622 ASSERT_LE(28, cur_version); |
624 { | 623 { |
625 sql::Statement s(db.GetUniqueStatement( | 624 sql::Statement s(db.GetUniqueStatement( |
626 "SELECT value FROM meta WHERE key = 'version'")); | 625 "SELECT value FROM meta WHERE key = 'version'")); |
627 EXPECT_TRUE(s.Step()); | 626 EXPECT_TRUE(s.Step()); |
628 EXPECT_EQ(cur_version, s.ColumnInt(0)); | 627 EXPECT_EQ(cur_version, s.ColumnInt(0)); |
629 } | 628 } |
630 { | 629 { |
631 sql::Statement s(db.GetUniqueStatement( | 630 sql::Statement s(db.GetUniqueStatement( |
632 "SELECT etag, last_modified from downloads")); | 631 "SELECT etag, last_modified from downloads")); |
633 EXPECT_TRUE(s.Step()); | 632 EXPECT_TRUE(s.Step()); |
634 EXPECT_EQ(std::string(), s.ColumnString(0)); | 633 EXPECT_EQ(std::string(), s.ColumnString(0)); |
635 EXPECT_EQ(std::string(), s.ColumnString(1)); | 634 EXPECT_EQ(std::string(), s.ColumnString(1)); |
636 } | 635 } |
637 } | 636 } |
638 } | 637 } |
639 | 638 |
640 TEST_F(HistoryBackendDBTest, PurgeArchivedDatabase) { | 639 TEST_F(HistoryBackendDBTest, PurgeArchivedDatabase) { |
641 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(27)); | 640 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(27)); |
642 ASSERT_NO_FATAL_FAILURE(CreateArchivedDB()); | 641 ASSERT_NO_FATAL_FAILURE(CreateArchivedDB()); |
643 | 642 |
644 ASSERT_TRUE(base::PathExists( | 643 ASSERT_TRUE(base::PathExists(history_dir_.Append(kArchivedHistoryFilename))); |
645 history_dir_.Append(chrome::kArchivedHistoryFilename))); | |
646 | 644 |
647 CreateBackendAndDatabase(); | 645 CreateBackendAndDatabase(); |
648 DeleteBackend(); | 646 DeleteBackend(); |
649 | 647 |
650 // We do not retain expired history entries in an archived database as of M37. | 648 // We do not retain expired history entries in an archived database as of M37. |
651 // Verify that any legacy archived database is deleted on start-up. | 649 // Verify that any legacy archived database is deleted on start-up. |
652 ASSERT_FALSE(base::PathExists( | 650 ASSERT_FALSE(base::PathExists(history_dir_.Append(kArchivedHistoryFilename))); |
653 history_dir_.Append(chrome::kArchivedHistoryFilename))); | |
654 } | 651 } |
655 | 652 |
656 TEST_F(HistoryBackendDBTest, MigrateDownloadMimeType) { | 653 TEST_F(HistoryBackendDBTest, MigrateDownloadMimeType) { |
657 Time now(base::Time::Now()); | 654 Time now(base::Time::Now()); |
658 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(28)); | 655 ASSERT_NO_FATAL_FAILURE(CreateDBVersion(28)); |
659 { | 656 { |
660 sql::Connection db; | 657 sql::Connection db; |
661 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 658 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
662 { | 659 { |
663 sql::Statement s(db.GetUniqueStatement( | 660 sql::Statement s(db.GetUniqueStatement( |
664 "INSERT INTO downloads (id, current_path, target_path, start_time, " | 661 "INSERT INTO downloads (id, current_path, target_path, start_time, " |
665 "received_bytes, total_bytes, state, danger_type, interrupt_reason, " | 662 "received_bytes, total_bytes, state, danger_type, interrupt_reason, " |
666 "end_time, opened, referrer, by_ext_id, by_ext_name, etag, " | 663 "end_time, opened, referrer, by_ext_id, by_ext_name, etag, " |
667 "last_modified) VALUES " | 664 "last_modified) VALUES " |
668 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); | 665 "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")); |
669 s.BindInt64(0, 1); | 666 s.BindInt64(0, 1); |
670 s.BindString(1, "current_path"); | 667 s.BindString(1, "current_path"); |
671 s.BindString(2, "target_path"); | 668 s.BindString(2, "target_path"); |
(...skipping 22 matching lines...) Expand all Loading... |
694 ASSERT_TRUE(s.Run()); | 691 ASSERT_TRUE(s.Run()); |
695 } | 692 } |
696 } | 693 } |
697 // Re-open the db using the HistoryDatabase, which should migrate to the | 694 // Re-open the db using the HistoryDatabase, which should migrate to the |
698 // current version, creating themime_type abd original_mime_type columns. | 695 // current version, creating themime_type abd original_mime_type columns. |
699 CreateBackendAndDatabase(); | 696 CreateBackendAndDatabase(); |
700 DeleteBackend(); | 697 DeleteBackend(); |
701 { | 698 { |
702 // Re-open the db for manual manipulation. | 699 // Re-open the db for manual manipulation. |
703 sql::Connection db; | 700 sql::Connection db; |
704 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 701 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
705 // The version should have been updated. | 702 // The version should have been updated. |
706 int cur_version = HistoryDatabase::GetCurrentVersion(); | 703 int cur_version = HistoryDatabase::GetCurrentVersion(); |
707 ASSERT_LE(29, cur_version); | 704 ASSERT_LE(29, cur_version); |
708 { | 705 { |
709 sql::Statement s(db.GetUniqueStatement( | 706 sql::Statement s(db.GetUniqueStatement( |
710 "SELECT value FROM meta WHERE key = 'version'")); | 707 "SELECT value FROM meta WHERE key = 'version'")); |
711 EXPECT_TRUE(s.Step()); | 708 EXPECT_TRUE(s.Step()); |
712 EXPECT_EQ(cur_version, s.ColumnInt(0)); | 709 EXPECT_EQ(cur_version, s.ColumnInt(0)); |
713 } | 710 } |
714 { | 711 { |
(...skipping 15 matching lines...) Expand all Loading... |
730 // Add some downloads. | 727 // Add some downloads. |
731 uint32 id1 = 1, id2 = 2, id3 = 3; | 728 uint32 id1 = 1, id2 = 2, id3 = 3; |
732 AddDownload(id1, DownloadItem::COMPLETE, now); | 729 AddDownload(id1, DownloadItem::COMPLETE, now); |
733 AddDownload(id2, DownloadItem::COMPLETE, now + base::TimeDelta::FromDays(2)); | 730 AddDownload(id2, DownloadItem::COMPLETE, now + base::TimeDelta::FromDays(2)); |
734 AddDownload(id3, DownloadItem::COMPLETE, now - base::TimeDelta::FromDays(2)); | 731 AddDownload(id3, DownloadItem::COMPLETE, now - base::TimeDelta::FromDays(2)); |
735 | 732 |
736 // Confirm that resulted in the correct number of rows in the DB. | 733 // Confirm that resulted in the correct number of rows in the DB. |
737 DeleteBackend(); | 734 DeleteBackend(); |
738 { | 735 { |
739 sql::Connection db; | 736 sql::Connection db; |
740 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 737 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
741 sql::Statement statement(db.GetUniqueStatement( | 738 sql::Statement statement(db.GetUniqueStatement( |
742 "Select Count(*) from downloads")); | 739 "Select Count(*) from downloads")); |
743 EXPECT_TRUE(statement.Step()); | 740 EXPECT_TRUE(statement.Step()); |
744 EXPECT_EQ(3, statement.ColumnInt(0)); | 741 EXPECT_EQ(3, statement.ColumnInt(0)); |
745 | 742 |
746 sql::Statement statement1(db.GetUniqueStatement( | 743 sql::Statement statement1(db.GetUniqueStatement( |
747 "Select Count(*) from downloads_url_chains")); | 744 "Select Count(*) from downloads_url_chains")); |
748 EXPECT_TRUE(statement1.Step()); | 745 EXPECT_TRUE(statement1.Step()); |
749 EXPECT_EQ(3, statement1.ColumnInt(0)); | 746 EXPECT_EQ(3, statement1.ColumnInt(0)); |
750 } | 747 } |
751 | 748 |
752 // Delete some rows and make sure the results are still correct. | 749 // Delete some rows and make sure the results are still correct. |
753 CreateBackendAndDatabase(); | 750 CreateBackendAndDatabase(); |
754 db_->RemoveDownload(id2); | 751 db_->RemoveDownload(id2); |
755 db_->RemoveDownload(id3); | 752 db_->RemoveDownload(id3); |
756 DeleteBackend(); | 753 DeleteBackend(); |
757 { | 754 { |
758 sql::Connection db; | 755 sql::Connection db; |
759 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 756 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
760 sql::Statement statement(db.GetUniqueStatement( | 757 sql::Statement statement(db.GetUniqueStatement( |
761 "Select Count(*) from downloads")); | 758 "Select Count(*) from downloads")); |
762 EXPECT_TRUE(statement.Step()); | 759 EXPECT_TRUE(statement.Step()); |
763 EXPECT_EQ(1, statement.ColumnInt(0)); | 760 EXPECT_EQ(1, statement.ColumnInt(0)); |
764 | 761 |
765 sql::Statement statement1(db.GetUniqueStatement( | 762 sql::Statement statement1(db.GetUniqueStatement( |
766 "Select Count(*) from downloads_url_chains")); | 763 "Select Count(*) from downloads_url_chains")); |
767 EXPECT_TRUE(statement1.Step()); | 764 EXPECT_TRUE(statement1.Step()); |
768 EXPECT_EQ(1, statement1.ColumnInt(0)); | 765 EXPECT_EQ(1, statement1.ColumnInt(0)); |
769 } | 766 } |
(...skipping 26 matching lines...) Expand all Loading... |
796 // Creating records without any urls should fail. | 793 // Creating records without any urls should fail. |
797 EXPECT_FALSE(db_->CreateDownload(download)); | 794 EXPECT_FALSE(db_->CreateDownload(download)); |
798 | 795 |
799 download.url_chain.push_back(GURL("foo-url")); | 796 download.url_chain.push_back(GURL("foo-url")); |
800 EXPECT_TRUE(db_->CreateDownload(download)); | 797 EXPECT_TRUE(db_->CreateDownload(download)); |
801 | 798 |
802 // Pretend that the URLs were dropped. | 799 // Pretend that the URLs were dropped. |
803 DeleteBackend(); | 800 DeleteBackend(); |
804 { | 801 { |
805 sql::Connection db; | 802 sql::Connection db; |
806 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 803 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
807 sql::Statement statement(db.GetUniqueStatement( | 804 sql::Statement statement(db.GetUniqueStatement( |
808 "DELETE FROM downloads_url_chains WHERE id=1")); | 805 "DELETE FROM downloads_url_chains WHERE id=1")); |
809 ASSERT_TRUE(statement.Run()); | 806 ASSERT_TRUE(statement.Run()); |
810 } | 807 } |
811 CreateBackendAndDatabase(); | 808 CreateBackendAndDatabase(); |
812 std::vector<DownloadRow> downloads; | 809 std::vector<DownloadRow> downloads; |
813 db_->QueryDownloads(&downloads); | 810 db_->QueryDownloads(&downloads); |
814 EXPECT_EQ(0U, downloads.size()); | 811 EXPECT_EQ(0U, downloads.size()); |
815 | 812 |
816 // QueryDownloads should have nuked the corrupt record. | 813 // QueryDownloads should have nuked the corrupt record. |
817 DeleteBackend(); | 814 DeleteBackend(); |
818 { | 815 { |
819 sql::Connection db; | 816 sql::Connection db; |
820 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 817 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
821 { | 818 { |
822 sql::Statement statement(db.GetUniqueStatement( | 819 sql::Statement statement(db.GetUniqueStatement( |
823 "SELECT count(*) from downloads")); | 820 "SELECT count(*) from downloads")); |
824 ASSERT_TRUE(statement.Step()); | 821 ASSERT_TRUE(statement.Step()); |
825 EXPECT_EQ(0, statement.ColumnInt(0)); | 822 EXPECT_EQ(0, statement.ColumnInt(0)); |
826 } | 823 } |
827 } | 824 } |
828 } | 825 } |
829 | 826 |
830 TEST_F(HistoryBackendDBTest, ConfirmDownloadInProgressCleanup) { | 827 TEST_F(HistoryBackendDBTest, ConfirmDownloadInProgressCleanup) { |
831 // Create the DB. | 828 // Create the DB. |
832 CreateBackendAndDatabase(); | 829 CreateBackendAndDatabase(); |
833 | 830 |
834 base::Time now(base::Time::Now()); | 831 base::Time now(base::Time::Now()); |
835 | 832 |
836 // Put an IN_PROGRESS download in the DB. | 833 // Put an IN_PROGRESS download in the DB. |
837 AddDownload(1, DownloadItem::IN_PROGRESS, now); | 834 AddDownload(1, DownloadItem::IN_PROGRESS, now); |
838 | 835 |
839 // Confirm that they made it into the DB unchanged. | 836 // Confirm that they made it into the DB unchanged. |
840 DeleteBackend(); | 837 DeleteBackend(); |
841 { | 838 { |
842 sql::Connection db; | 839 sql::Connection db; |
843 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 840 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
844 sql::Statement statement(db.GetUniqueStatement( | 841 sql::Statement statement(db.GetUniqueStatement( |
845 "Select Count(*) from downloads")); | 842 "Select Count(*) from downloads")); |
846 EXPECT_TRUE(statement.Step()); | 843 EXPECT_TRUE(statement.Step()); |
847 EXPECT_EQ(1, statement.ColumnInt(0)); | 844 EXPECT_EQ(1, statement.ColumnInt(0)); |
848 | 845 |
849 sql::Statement statement1(db.GetUniqueStatement( | 846 sql::Statement statement1(db.GetUniqueStatement( |
850 "Select state, interrupt_reason from downloads")); | 847 "Select state, interrupt_reason from downloads")); |
851 EXPECT_TRUE(statement1.Step()); | 848 EXPECT_TRUE(statement1.Step()); |
852 EXPECT_EQ(DownloadDatabase::kStateInProgress, statement1.ColumnInt(0)); | 849 EXPECT_EQ(DownloadDatabase::kStateInProgress, statement1.ColumnInt(0)); |
853 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE, statement1.ColumnInt(1)); | 850 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_NONE, statement1.ColumnInt(1)); |
854 EXPECT_FALSE(statement1.Step()); | 851 EXPECT_FALSE(statement1.Step()); |
855 } | 852 } |
856 | 853 |
857 // Read in the DB through query downloads, then test that the | 854 // Read in the DB through query downloads, then test that the |
858 // right transformation was returned. | 855 // right transformation was returned. |
859 CreateBackendAndDatabase(); | 856 CreateBackendAndDatabase(); |
860 std::vector<DownloadRow> results; | 857 std::vector<DownloadRow> results; |
861 db_->QueryDownloads(&results); | 858 db_->QueryDownloads(&results); |
862 ASSERT_EQ(1u, results.size()); | 859 ASSERT_EQ(1u, results.size()); |
863 EXPECT_EQ(content::DownloadItem::INTERRUPTED, results[0].state); | 860 EXPECT_EQ(content::DownloadItem::INTERRUPTED, results[0].state); |
864 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH, | 861 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH, |
865 results[0].interrupt_reason); | 862 results[0].interrupt_reason); |
866 | 863 |
867 // Allow the update to propagate, shut down the DB, and confirm that | 864 // Allow the update to propagate, shut down the DB, and confirm that |
868 // the query updated the on disk database as well. | 865 // the query updated the on disk database as well. |
869 base::MessageLoop::current()->RunUntilIdle(); | 866 base::MessageLoop::current()->RunUntilIdle(); |
870 DeleteBackend(); | 867 DeleteBackend(); |
871 { | 868 { |
872 sql::Connection db; | 869 sql::Connection db; |
873 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 870 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
874 sql::Statement statement(db.GetUniqueStatement( | 871 sql::Statement statement(db.GetUniqueStatement( |
875 "Select Count(*) from downloads")); | 872 "Select Count(*) from downloads")); |
876 EXPECT_TRUE(statement.Step()); | 873 EXPECT_TRUE(statement.Step()); |
877 EXPECT_EQ(1, statement.ColumnInt(0)); | 874 EXPECT_EQ(1, statement.ColumnInt(0)); |
878 | 875 |
879 sql::Statement statement1(db.GetUniqueStatement( | 876 sql::Statement statement1(db.GetUniqueStatement( |
880 "Select state, interrupt_reason from downloads")); | 877 "Select state, interrupt_reason from downloads")); |
881 EXPECT_TRUE(statement1.Step()); | 878 EXPECT_TRUE(statement1.Step()); |
882 EXPECT_EQ(DownloadDatabase::kStateInterrupted, statement1.ColumnInt(0)); | 879 EXPECT_EQ(DownloadDatabase::kStateInterrupted, statement1.ColumnInt(0)); |
883 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH, | 880 EXPECT_EQ(content::DOWNLOAD_INTERRUPT_REASON_CRASH, |
(...skipping 927 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1811 const SegmentID segment_id = 2; | 1808 const SegmentID segment_id = 2; |
1812 const URLID url_id = 3; | 1809 const URLID url_id = 3; |
1813 const GURL url("http://www.foo.com"); | 1810 const GURL url("http://www.foo.com"); |
1814 const std::string url_name(VisitSegmentDatabase::ComputeSegmentName(url)); | 1811 const std::string url_name(VisitSegmentDatabase::ComputeSegmentName(url)); |
1815 const base::string16 title(base::ASCIIToUTF16("Title1")); | 1812 const base::string16 title(base::ASCIIToUTF16("Title1")); |
1816 const Time segment_time(Time::Now()); | 1813 const Time segment_time(Time::Now()); |
1817 | 1814 |
1818 { | 1815 { |
1819 // Re-open the db for manual manipulation. | 1816 // Re-open the db for manual manipulation. |
1820 sql::Connection db; | 1817 sql::Connection db; |
1821 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename))); | 1818 ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename))); |
1822 | 1819 |
1823 // Add an entry to urls. | 1820 // Add an entry to urls. |
1824 { | 1821 { |
1825 sql::Statement s(db.GetUniqueStatement( | 1822 sql::Statement s(db.GetUniqueStatement( |
1826 "INSERT INTO urls " | 1823 "INSERT INTO urls " |
1827 "(id, url, title, last_visit_time) VALUES " | 1824 "(id, url, title, last_visit_time) VALUES " |
1828 "(?, ?, ?, ?)")); | 1825 "(?, ?, ?, ?)")); |
1829 s.BindInt64(0, url_id); | 1826 s.BindInt64(0, url_id); |
1830 s.BindString(1, url.spec()); | 1827 s.BindString(1, url.spec()); |
1831 s.BindString16(2, title); | 1828 s.BindString16(2, title); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1866 std::vector<PageUsageData*> results; | 1863 std::vector<PageUsageData*> results; |
1867 db_->QuerySegmentUsage(segment_time, 10, &results); | 1864 db_->QuerySegmentUsage(segment_time, 10, &results); |
1868 ASSERT_EQ(1u, results.size()); | 1865 ASSERT_EQ(1u, results.size()); |
1869 EXPECT_EQ(url, results[0]->GetURL()); | 1866 EXPECT_EQ(url, results[0]->GetURL()); |
1870 EXPECT_EQ(segment_id, results[0]->GetID()); | 1867 EXPECT_EQ(segment_id, results[0]->GetID()); |
1871 EXPECT_EQ(title, results[0]->GetTitle()); | 1868 EXPECT_EQ(title, results[0]->GetTitle()); |
1872 STLDeleteElements(&results); | 1869 STLDeleteElements(&results); |
1873 } | 1870 } |
1874 | 1871 |
1875 } // namespace history | 1872 } // namespace history |
OLD | NEW |