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

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

Issue 10823203: Fix downloads db state=3 corruption using version=23 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 24 matching lines...) Expand all
35 #include "base/scoped_temp_dir.h" 35 #include "base/scoped_temp_dir.h"
36 #include "base/string_util.h" 36 #include "base/string_util.h"
37 #include "base/utf_string_conversions.h" 37 #include "base/utf_string_conversions.h"
38 #include "chrome/browser/history/history.h" 38 #include "chrome/browser/history/history.h"
39 #include "chrome/browser/history/history_backend.h" 39 #include "chrome/browser/history/history_backend.h"
40 #include "chrome/browser/history/history_database.h" 40 #include "chrome/browser/history/history_database.h"
41 #include "chrome/browser/history/history_notifications.h" 41 #include "chrome/browser/history/history_notifications.h"
42 #include "chrome/browser/history/in_memory_database.h" 42 #include "chrome/browser/history/in_memory_database.h"
43 #include "chrome/browser/history/in_memory_history_backend.h" 43 #include "chrome/browser/history/in_memory_history_backend.h"
44 #include "chrome/browser/history/page_usage_data.h" 44 #include "chrome/browser/history/page_usage_data.h"
45 #include "chrome/common/chrome_constants.h"
45 #include "chrome/common/chrome_paths.h" 46 #include "chrome/common/chrome_paths.h"
46 #include "chrome/common/thumbnail_score.h" 47 #include "chrome/common/thumbnail_score.h"
47 #include "chrome/tools/profiles/thumbnail-inl.h" 48 #include "chrome/tools/profiles/thumbnail-inl.h"
48 #include "content/public/browser/download_item.h" 49 #include "content/public/browser/download_item.h"
49 #include "content/public/browser/download_persistent_store_info.h" 50 #include "content/public/browser/download_persistent_store_info.h"
50 #include "content/public/browser/notification_details.h" 51 #include "content/public/browser/notification_details.h"
51 #include "content/public/browser/notification_source.h" 52 #include "content/public/browser/notification_source.h"
52 #include "sql/connection.h" 53 #include "sql/connection.h"
53 #include "sql/statement.h" 54 #include "sql/statement.h"
54 #include "testing/gtest/include/gtest/gtest.h" 55 #include "testing/gtest/include/gtest/gtest.h"
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 history_service_->Cleanup(); 179 history_service_->Cleanup();
179 history_service_ = NULL; 180 history_service_ = NULL;
180 181
181 // Wait for the backend class to terminate before deleting the files and 182 // Wait for the backend class to terminate before deleting the files and
182 // moving to the next test. Note: if this never terminates, somebody is 183 // moving to the next test. Note: if this never terminates, somebody is
183 // probably leaking a reference to the history backend, so it never calls 184 // probably leaking a reference to the history backend, so it never calls
184 // our destroy task. 185 // our destroy task.
185 MessageLoop::current()->Run(); 186 MessageLoop::current()->Run();
186 } 187 }
187 188
188 int64 AddDownload(int32 state, const Time& time) { 189 int64 AddDownload(DownloadItem::DownloadState state, const Time& time) {
189 DownloadPersistentStoreInfo download( 190 DownloadPersistentStoreInfo download(
190 FilePath(FILE_PATH_LITERAL("foo-path")), 191 FilePath(FILE_PATH_LITERAL("foo-path")),
191 GURL("foo-url"), 192 GURL("foo-url"),
192 GURL(""), 193 GURL(""),
193 time, 194 time,
194 time, 195 time,
195 0, 196 0,
196 512, 197 512,
197 state, 198 state,
198 0, 199 0,
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 Time now = Time::Now(); 317 Time now = Time::Now();
317 TimeDelta one_day = TimeDelta::FromDays(1); 318 TimeDelta one_day = TimeDelta::FromDays(1);
318 Time month_ago = now - TimeDelta::FromDays(30); 319 Time month_ago = now - TimeDelta::FromDays(30);
319 320
320 // Initially there should be nothing in the downloads database. 321 // Initially there should be nothing in the downloads database.
321 std::vector<DownloadPersistentStoreInfo> downloads; 322 std::vector<DownloadPersistentStoreInfo> downloads;
322 db_->QueryDownloads(&downloads); 323 db_->QueryDownloads(&downloads);
323 EXPECT_EQ(0U, downloads.size()); 324 EXPECT_EQ(0U, downloads.size());
324 325
325 // Keep track of these as we need to update them later during the test. 326 // Keep track of these as we need to update them later during the test.
326 DownloadID in_progress, removing; 327 DownloadID in_progress;
327 328
328 // Create one with a 0 time. 329 // Create one with a 0 time.
329 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, Time())); 330 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, Time()));
330 // Create one for now and +/- 1 day. 331 // Create one for now and +/- 1 day.
331 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, now - one_day)); 332 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, now - one_day));
332 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, now)); 333 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, now));
333 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, now + one_day)); 334 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, now + one_day));
334 // Try the other four states. 335 // Try the other four states.
335 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, month_ago)); 336 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, month_ago));
336 EXPECT_NE(0, in_progress = AddDownload(DownloadItem::IN_PROGRESS, month_ago)); 337 EXPECT_NE(0, in_progress = AddDownload(DownloadItem::IN_PROGRESS, month_ago));
337 EXPECT_NE(0, AddDownload(DownloadItem::CANCELLED, month_ago)); 338 EXPECT_NE(0, AddDownload(DownloadItem::CANCELLED, month_ago));
338 EXPECT_NE(0, AddDownload(DownloadItem::INTERRUPTED, month_ago)); 339 EXPECT_NE(0, AddDownload(DownloadItem::INTERRUPTED, month_ago));
339 EXPECT_NE(0, removing = AddDownload(DownloadItem::REMOVING, month_ago)); 340 EXPECT_EQ(0, AddDownload(DownloadItem::REMOVING, month_ago));
340 341
341 // Test to see if inserts worked. 342 // Test to see if inserts worked.
342 db_->QueryDownloads(&downloads); 343 db_->QueryDownloads(&downloads);
343 EXPECT_EQ(9U, downloads.size()); 344 EXPECT_EQ(8U, downloads.size());
344 345
345 // Try removing from current timestamp. This should delete the one in the 346 // Try removing from current timestamp. This should delete the one in the
346 // future and one very recent one. 347 // future and one very recent one.
347 db_->RemoveDownloadsBetween(now, Time()); 348 db_->RemoveDownloadsBetween(now, Time());
348 db_->QueryDownloads(&downloads); 349 db_->QueryDownloads(&downloads);
349 EXPECT_EQ(7U, downloads.size()); 350 EXPECT_EQ(6U, downloads.size());
350 351
351 // Try removing from two months ago. This should not delete items that are 352 // Try removing from two months ago. This should not delete items that are
352 // 'in progress' or in 'removing' state. 353 // 'in progress' or in 'removing' state.
353 db_->RemoveDownloadsBetween(now - TimeDelta::FromDays(60), Time()); 354 db_->RemoveDownloadsBetween(now - TimeDelta::FromDays(60), Time());
354 db_->QueryDownloads(&downloads); 355 db_->QueryDownloads(&downloads);
355 EXPECT_EQ(3U, downloads.size()); 356 EXPECT_EQ(2U, downloads.size());
356 357
357 // Download manager converts to TimeT, which is lossy, so we do the same 358 // Download manager converts to TimeT, which is lossy, so we do the same
358 // for comparison. 359 // for comparison.
359 Time month_ago_lossy = Time::FromTimeT(month_ago.ToTimeT()); 360 Time month_ago_lossy = Time::FromTimeT(month_ago.ToTimeT());
360 361
361 // Make sure the right values remain. 362 // Make sure the right values remain.
362 EXPECT_EQ(DownloadItem::COMPLETE, downloads[0].state); 363 EXPECT_EQ(DownloadItem::COMPLETE, downloads[0].state);
363 EXPECT_EQ(0, downloads[0].start_time.ToInternalValue()); 364 EXPECT_EQ(0, downloads[0].start_time.ToInternalValue());
364 EXPECT_EQ(DownloadItem::IN_PROGRESS, downloads[1].state); 365 EXPECT_EQ(DownloadItem::IN_PROGRESS, downloads[1].state);
365 EXPECT_EQ(month_ago_lossy.ToInternalValue(), 366 EXPECT_EQ(month_ago_lossy.ToInternalValue(),
366 downloads[1].start_time.ToInternalValue()); 367 downloads[1].start_time.ToInternalValue());
367 EXPECT_EQ(DownloadItem::REMOVING, downloads[2].state);
368 EXPECT_EQ(month_ago_lossy.ToInternalValue(),
369 downloads[2].start_time.ToInternalValue());
370 368
371 // Change state so we can delete the downloads. 369 // Change state so we can delete the downloads.
372 DownloadPersistentStoreInfo data; 370 DownloadPersistentStoreInfo data;
373 data.received_bytes = 512; 371 data.received_bytes = 512;
374 data.state = DownloadItem::COMPLETE; 372 data.state = DownloadItem::COMPLETE;
375 data.end_time = base::Time::Now(); 373 data.end_time = base::Time::Now();
376 data.opened = false; 374 data.opened = false;
377 data.db_handle = in_progress; 375 data.db_handle = in_progress;
378 EXPECT_TRUE(db_->UpdateDownload(data)); 376 EXPECT_TRUE(db_->UpdateDownload(data));
379 data.state = DownloadItem::CANCELLED;
380 data.db_handle = removing;
381 EXPECT_TRUE(db_->UpdateDownload(data));
382 377
383 // Try removing from Time=0. This should delete all. 378 // Try removing from Time=0. This should delete all.
384 db_->RemoveDownloadsBetween(Time(), Time()); 379 db_->RemoveDownloadsBetween(Time(), Time());
385 db_->QueryDownloads(&downloads); 380 db_->QueryDownloads(&downloads);
386 EXPECT_EQ(0U, downloads.size()); 381 EXPECT_EQ(0U, downloads.size());
387 382
388 // Check removal of downloads stuck in IN_PROGRESS state. 383 // Check removal of downloads stuck in IN_PROGRESS state.
389 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, month_ago)); 384 EXPECT_NE(0, AddDownload(DownloadItem::COMPLETE, month_ago));
390 EXPECT_NE(0, AddDownload(DownloadItem::IN_PROGRESS, month_ago)); 385 EXPECT_NE(0, AddDownload(DownloadItem::IN_PROGRESS, month_ago));
391 db_->QueryDownloads(&downloads); 386 db_->QueryDownloads(&downloads);
392 EXPECT_EQ(2U, downloads.size()); 387 EXPECT_EQ(2U, downloads.size());
393 db_->RemoveDownloadsBetween(Time(), Time()); 388 db_->RemoveDownloadsBetween(Time(), Time());
394 db_->QueryDownloads(&downloads); 389 db_->QueryDownloads(&downloads);
395 // IN_PROGRESS download should remain. It it indicated as "Canceled" 390 // IN_PROGRESS download should remain. It it indicated as "Canceled"
396 EXPECT_EQ(1U, downloads.size()); 391 EXPECT_EQ(1U, downloads.size());
397 db_->CleanUpInProgressEntries(); 392 db_->CleanUpInProgressEntries();
398 db_->QueryDownloads(&downloads); 393 db_->QueryDownloads(&downloads);
399 EXPECT_EQ(1U, downloads.size()); 394 EXPECT_EQ(1U, downloads.size());
400 db_->RemoveDownloadsBetween(Time(), Time()); 395 db_->RemoveDownloadsBetween(Time(), Time());
401 db_->QueryDownloads(&downloads); 396 db_->QueryDownloads(&downloads);
402 EXPECT_EQ(0U, downloads.size()); 397 EXPECT_EQ(0U, downloads.size());
403 } 398 }
404 399
400 TEST_F(HistoryTest, MigrateDownloadsState) {
401 // Create the db and close it so that we can reopen it directly.
402 CreateBackendAndDatabase();
403 DeleteBackend();
404 {
405 // Re-open the db for manual manipulation.
406 sql::Connection db;
407 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
408 {
409 // Manually force the version to 22.
410 sql::Statement version22(db.GetUniqueStatement(
411 "UPDATE meta SET value=22 WHERE key='version'"));
412 ASSERT_TRUE(version22.Run());
413 }
414 // Manually insert corrupted rows; there's infrastructure in place now to
415 // make this impossible, at least according to the test above.
416 for (int state = 0; state < 5; ++state) {
417 sql::Statement s(db.GetUniqueStatement(
418 "INSERT INTO downloads (id, full_path, url, start_time, "
419 "received_bytes, total_bytes, state, end_time, opened) VALUES "
420 "(?, ?, ?, ?, ?, ?, ?, ?, ?)"));
421 s.BindInt64(0, 1 + state);
422 s.BindString(1, "path");
423 s.BindString(2, "url");
424 s.BindInt64(3, base::Time::Now().ToTimeT());
425 s.BindInt64(4, 100);
426 s.BindInt64(5, 100);
427 s.BindInt(6, state);
428 s.BindInt64(7, base::Time::Now().ToTimeT());
429 s.BindInt(8, state % 2);
430 ASSERT_TRUE(s.Run());
431 }
432 }
433
434 // Re-open the db using the HistoryDatabase, which should migrate from version
435 // 22 to 23, fixing just the row whose state was 3. Then close the db so that
436 // we can re-open it directly.
437 CreateBackendAndDatabase();
438 DeleteBackend();
439 {
440 // Re-open the db for manual manipulation.
441 sql::Connection db;
442 ASSERT_TRUE(db.Open(history_dir_.Append(chrome::kHistoryFilename)));
443 {
444 // The version should have been updated.
445 int cur_version = HistoryDatabase::GetCurrentVersion();
446 ASSERT_LT(22, cur_version);
447 sql::Statement s(db.GetUniqueStatement(
448 "SELECT value FROM meta WHERE key = 'version'"));
449 EXPECT_TRUE(s.Step());
450 EXPECT_EQ(cur_version, s.ColumnInt(0));
451 }
452 {
453 sql::Statement statement(db.GetUniqueStatement(
454 "SELECT id, state, opened "
455 "FROM downloads "
456 "ORDER BY id"));
457 int counter = 0;
458 while (statement.Step()) {
459 EXPECT_EQ(1 + counter, statement.ColumnInt64(0));
460 // The only thing that migration should have changed was state from 3 to
461 // 4.
462 EXPECT_EQ(((counter == 3) ? 4 : counter), statement.ColumnInt(1));
463 EXPECT_EQ(counter % 2, statement.ColumnInt(2));
464 ++counter;
465 }
466 EXPECT_EQ(5, counter);
467 }
468 }
469 }
470
405 TEST_F(HistoryTest, AddPage) { 471 TEST_F(HistoryTest, AddPage) {
406 scoped_refptr<HistoryService> history(new HistoryService); 472 scoped_refptr<HistoryService> history(new HistoryService);
407 history_service_ = history; 473 history_service_ = history;
408 ASSERT_TRUE(history->Init(history_dir_, NULL)); 474 ASSERT_TRUE(history->Init(history_dir_, NULL));
409 475
410 // Add the page once from a child frame. 476 // Add the page once from a child frame.
411 const GURL test_url("http://www.google.com/"); 477 const GURL test_url("http://www.google.com/");
412 history->AddPage(test_url, NULL, 0, GURL(), 478 history->AddPage(test_url, NULL, 0, GURL(),
413 content::PAGE_TRANSITION_MANUAL_SUBFRAME, 479 content::PAGE_TRANSITION_MANUAL_SUBFRAME,
414 history::RedirectList(), 480 history::RedirectList(),
(...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 history_service_ = history; 1022 history_service_ = history;
957 history->ScheduleDBTask(task.get(), &request_consumer); 1023 history->ScheduleDBTask(task.get(), &request_consumer);
958 request_consumer.CancelAllRequests(); 1024 request_consumer.CancelAllRequests();
959 CleanupHistoryService(); 1025 CleanupHistoryService();
960 // WARNING: history has now been deleted. 1026 // WARNING: history has now been deleted.
961 history = NULL; 1027 history = NULL;
962 ASSERT_FALSE(task->done_invoked); 1028 ASSERT_FALSE(task->done_invoked);
963 } 1029 }
964 1030
965 } // namespace history 1031 } // namespace history
OLDNEW
« no previous file with comments | « chrome/browser/history/history_database.cc ('k') | chrome/test/data/profiles/typical_history/Default/History » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698