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

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

Issue 50493012: [sql] Recover Favicons v5 databases, with more recovery automation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase, merge rows-recovered support. Created 7 years, 1 month 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
« no previous file with comments | « chrome/browser/history/thumbnail_database.cc ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #include <algorithm> 5 #include <algorithm>
6 #include <vector> 6 #include <vector>
7 7
8 #include "base/basictypes.h" 8 #include "base/basictypes.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/files/file_enumerator.h" 10 #include "base/files/file_enumerator.h"
(...skipping 772 matching lines...) Expand 10 before | Expand all | Expand 10 after
783 EXPECT_TRUE( 783 EXPECT_TRUE(
784 CheckPageHasIcon(&db, kPageUrl2, chrome::FAVICON, 784 CheckPageHasIcon(&db, kPageUrl2, chrome::FAVICON,
785 kIconUrl2, kLargeSize, sizeof(kBlob2), kBlob2)); 785 kIconUrl2, kLargeSize, sizeof(kBlob2), kBlob2));
786 } 786 }
787 787
788 // Corrupt the |icon_mapping.page_url| index by deleting an element 788 // Corrupt the |icon_mapping.page_url| index by deleting an element
789 // from the backing table but not the index. 789 // from the backing table but not the index.
790 { 790 {
791 sql::Connection raw_db; 791 sql::Connection raw_db;
792 EXPECT_TRUE(raw_db.Open(file_name_)); 792 EXPECT_TRUE(raw_db.Open(file_name_));
793 { 793 ASSERT_EQ("ok", sql::test::IntegrityCheck(&raw_db));
794 sql::Statement statement(
795 raw_db.GetUniqueStatement("PRAGMA integrity_check"));
796 EXPECT_TRUE(statement.Step());
797 ASSERT_EQ("ok", statement.ColumnString(0));
798 }
799 794
800 const char kIndexName[] = "icon_mapping_page_url_idx"; 795 const char kIndexName[] = "icon_mapping_page_url_idx";
801 const int idx_root_page = GetRootPage(&raw_db, kIndexName); 796 const int idx_root_page = GetRootPage(&raw_db, kIndexName);
802 const int page_size = GetPageSize(&raw_db); 797 const int page_size = GetPageSize(&raw_db);
803 scoped_ptr<char[]> buf(new char[page_size]); 798 scoped_ptr<char[]> buf(new char[page_size]);
804 EXPECT_TRUE(ReadPage(file_name_, idx_root_page, buf.get(), page_size)); 799 EXPECT_TRUE(ReadPage(file_name_, idx_root_page, buf.get(), page_size));
805 800
806 { 801 {
807 const char kDeleteSql[] = "DELETE FROM icon_mapping WHERE page_url = ?"; 802 const char kDeleteSql[] = "DELETE FROM icon_mapping WHERE page_url = ?";
808 sql::Statement statement(raw_db.GetUniqueStatement(kDeleteSql)); 803 sql::Statement statement(raw_db.GetUniqueStatement(kDeleteSql));
809 statement.BindString(0, URLDatabase::GURLToDatabaseURL(kPageUrl2)); 804 statement.BindString(0, URLDatabase::GURLToDatabaseURL(kPageUrl2));
810 EXPECT_TRUE(statement.Run()); 805 EXPECT_TRUE(statement.Run());
811 } 806 }
812 raw_db.Close(); 807 raw_db.Close();
813 808
814 EXPECT_TRUE(WritePage(file_name_, idx_root_page, buf.get(), page_size)); 809 EXPECT_TRUE(WritePage(file_name_, idx_root_page, buf.get(), page_size));
815 } 810 }
816 811
817 // Database should be corrupt at the SQLite level. 812 // Database should be corrupt at the SQLite level.
818 { 813 {
819 sql::Connection raw_db; 814 sql::Connection raw_db;
820 EXPECT_TRUE(raw_db.Open(file_name_)); 815 EXPECT_TRUE(raw_db.Open(file_name_));
821 sql::Statement statement( 816 ASSERT_NE("ok", sql::test::IntegrityCheck(&raw_db));
822 raw_db.GetUniqueStatement("PRAGMA integrity_check"));
823 EXPECT_TRUE(statement.Step());
824 ASSERT_NE("ok", statement.ColumnString(0));
825 } 817 }
826 818
827 // Open the database and access the corrupt index. 819 // Open the database and access the corrupt index.
828 { 820 {
829 sql::ScopedErrorIgnorer ignore_errors; 821 sql::ScopedErrorIgnorer ignore_errors;
830 ignore_errors.IgnoreError(SQLITE_CORRUPT); 822 ignore_errors.IgnoreError(SQLITE_CORRUPT);
831 ThumbnailDatabase db; 823 ThumbnailDatabase db;
832 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_)); 824 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
833 825
834 // Data for kPageUrl2 was deleted, but the index entry remains, 826 // Data for kPageUrl2 was deleted, but the index entry remains,
835 // this will throw SQLITE_CORRUPT. The corruption handler will 827 // this will throw SQLITE_CORRUPT. The corruption handler will
836 // recover the database and poison the handle, so the outer call 828 // recover the database and poison the handle, so the outer call
837 // fails. 829 // fails.
838 EXPECT_FALSE(db.GetIconMappingsForPageURL(kPageUrl2, NULL)); 830 EXPECT_FALSE(db.GetIconMappingsForPageURL(kPageUrl2, NULL));
839 831
840 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 832 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
841 } 833 }
842 834
843 // Check that the database is recovered at the SQLite level. 835 // Check that the database is recovered at the SQLite level.
844 { 836 {
845 sql::Connection raw_db; 837 sql::Connection raw_db;
846 EXPECT_TRUE(raw_db.Open(file_name_)); 838 EXPECT_TRUE(raw_db.Open(file_name_));
847 sql::Statement statement( 839 ASSERT_EQ("ok", sql::test::IntegrityCheck(&raw_db));
848 raw_db.GetUniqueStatement("PRAGMA integrity_check"));
849 EXPECT_TRUE(statement.Step());
850 EXPECT_EQ("ok", statement.ColumnString(0));
851 840
852 // Check that the expected tables exist. 841 // Check that the expected tables exist.
853 VerifyTablesAndColumns(&raw_db); 842 VerifyTablesAndColumns(&raw_db);
854 } 843 }
855 844
856 // Database should also be recovered at higher levels. 845 // Database should also be recovered at higher levels.
857 { 846 {
858 ThumbnailDatabase db; 847 ThumbnailDatabase db;
859 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_)); 848 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
860 849
861 // Now this fails because there is no mapping. 850 // Now this fails because there is no mapping.
862 EXPECT_FALSE(db.GetIconMappingsForPageURL(kPageUrl2, NULL)); 851 EXPECT_FALSE(db.GetIconMappingsForPageURL(kPageUrl2, NULL));
863 852
864 // Other data was retained by recovery. 853 // Other data was retained by recovery.
865 EXPECT_TRUE( 854 EXPECT_TRUE(
866 CheckPageHasIcon(&db, kPageUrl1, chrome::FAVICON, 855 CheckPageHasIcon(&db, kPageUrl1, chrome::FAVICON,
867 kIconUrl1, kLargeSize, sizeof(kBlob1), kBlob1)); 856 kIconUrl1, kLargeSize, sizeof(kBlob1), kBlob1));
868 } 857 }
869 858
870 // Corrupt the database again by making the actual file shorter than 859 // Corrupt the database again by adjusting the header.
871 // the header expects. 860 EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_));
872 {
873 int64 db_size = 0;
874 EXPECT_TRUE(file_util::GetFileSize(file_name_, &db_size));
875 {
876 sql::Connection raw_db;
877 EXPECT_TRUE(raw_db.Open(file_name_));
878 EXPECT_TRUE(raw_db.Execute("CREATE TABLE t(x)"));
879 }
880 file_util::ScopedFILE file(file_util::OpenFile(file_name_, "rb+"));
881 ASSERT_TRUE(file.get() != NULL);
882 EXPECT_EQ(0, fseek(file.get(), static_cast<long>(db_size), SEEK_SET));
883 EXPECT_TRUE(file_util::TruncateFile(file.get()));
884 }
885 861
886 // Database is unusable at the SQLite level. 862 // Database is unusable at the SQLite level.
887 { 863 {
888 sql::ScopedErrorIgnorer ignore_errors; 864 sql::ScopedErrorIgnorer ignore_errors;
889 ignore_errors.IgnoreError(SQLITE_CORRUPT); 865 ignore_errors.IgnoreError(SQLITE_CORRUPT);
890 sql::Connection raw_db; 866 sql::Connection raw_db;
891 EXPECT_TRUE(raw_db.Open(file_name_)); 867 EXPECT_TRUE(raw_db.Open(file_name_));
892 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); 868 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check"));
893 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 869 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
894 } 870 }
(...skipping 16 matching lines...) Expand all
911 887
912 TEST_F(ThumbnailDatabaseTest, Recovery6) { 888 TEST_F(ThumbnailDatabaseTest, Recovery6) {
913 // TODO(shess): See comment at top of Recovery test. 889 // TODO(shess): See comment at top of Recovery test.
914 if (!sql::Recovery::FullRecoverySupported()) 890 if (!sql::Recovery::FullRecoverySupported())
915 return; 891 return;
916 892
917 // Create an example database without loading into ThumbnailDatabase 893 // Create an example database without loading into ThumbnailDatabase
918 // (which would upgrade it). 894 // (which would upgrade it).
919 EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "Favicons.v6.sql")); 895 EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "Favicons.v6.sql"));
920 896
921 // Corrupt the database by making the actual file shorter than the 897 // Corrupt the database again by adjusting the header. This form of
922 // SQLite header expects. This form of corruption will cause 898 // corruption will cause immediate failures during Open(), before
923 // immediate failures during Open(), before the migration code runs, 899 // the migration code runs, so the version-6 recovery will occur.
924 // so the version-6 recovery will occur. 900 EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_));
925 {
926 int64 db_size = 0;
927 EXPECT_TRUE(file_util::GetFileSize(file_name_, &db_size));
928 {
929 sql::Connection raw_db;
930 EXPECT_TRUE(raw_db.Open(file_name_));
931 EXPECT_TRUE(raw_db.Execute("CREATE TABLE t(x)"));
932 }
933 file_util::ScopedFILE file(file_util::OpenFile(file_name_, "rb+"));
934 ASSERT_TRUE(file.get() != NULL);
935 EXPECT_EQ(0, fseek(file.get(), static_cast<long>(db_size), SEEK_SET));
936 EXPECT_TRUE(file_util::TruncateFile(file.get()));
937 }
938 901
939 // Database is unusable at the SQLite level. 902 // Database is unusable at the SQLite level.
940 { 903 {
941 sql::ScopedErrorIgnorer ignore_errors; 904 sql::ScopedErrorIgnorer ignore_errors;
942 ignore_errors.IgnoreError(SQLITE_CORRUPT); 905 ignore_errors.IgnoreError(SQLITE_CORRUPT);
943 sql::Connection raw_db; 906 sql::Connection raw_db;
944 EXPECT_TRUE(raw_db.Open(file_name_)); 907 EXPECT_TRUE(raw_db.Open(file_name_));
945 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); 908 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check"));
946 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 909 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
947 } 910 }
(...skipping 15 matching lines...) Expand all
963 kIconUrl3, kLargeSize, sizeof(kBlob2), kBlob2)); 926 kIconUrl3, kLargeSize, sizeof(kBlob2), kBlob2));
964 927
965 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 928 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
966 } 929 }
967 930
968 // Check that the database is recovered at a SQLite level, and that 931 // Check that the database is recovered at a SQLite level, and that
969 // the current schema is in place. 932 // the current schema is in place.
970 { 933 {
971 sql::Connection raw_db; 934 sql::Connection raw_db;
972 EXPECT_TRUE(raw_db.Open(file_name_)); 935 EXPECT_TRUE(raw_db.Open(file_name_));
973 sql::Statement statement( 936 ASSERT_EQ("ok", sql::test::IntegrityCheck(&raw_db));
974 raw_db.GetUniqueStatement("PRAGMA integrity_check"));
975 EXPECT_TRUE(statement.Step());
976 EXPECT_EQ("ok", statement.ColumnString(0));
977 937
978 // Check that the expected tables exist. 938 // Check that the expected tables exist.
979 VerifyTablesAndColumns(&raw_db); 939 VerifyTablesAndColumns(&raw_db);
940 }
941 }
942
943 TEST_F(ThumbnailDatabaseTest, Recovery5) {
944 // Create an example database without loading into ThumbnailDatabase
945 // (which would upgrade it).
946 EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "Favicons.v5.sql"));
947
948 // Corrupt the database again by adjusting the header. This form of
949 // corruption will cause immediate failures during Open(), before
950 // the migration code runs, so the version-5 recovery will occur.
951 EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_));
952
953 // Database is unusable at the SQLite level.
954 {
955 sql::ScopedErrorIgnorer ignore_errors;
956 ignore_errors.IgnoreError(SQLITE_CORRUPT);
957 sql::Connection raw_db;
958 EXPECT_TRUE(raw_db.Open(file_name_));
959 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check"));
960 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
961 }
962
963 // Database should be recovered during open.
964 {
965 sql::ScopedErrorIgnorer ignore_errors;
966 ignore_errors.IgnoreError(SQLITE_CORRUPT);
967 ThumbnailDatabase db;
968 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_));
969
970 // Test that some data is present, copied from
971 // ThumbnailDatabaseTest.Version5 .
972 EXPECT_TRUE(
973 CheckPageHasIcon(&db, kPageUrl3, chrome::FAVICON,
974 kIconUrl1, gfx::Size(), sizeof(kBlob1), kBlob1));
975 EXPECT_TRUE(
976 CheckPageHasIcon(&db, kPageUrl3, chrome::TOUCH_ICON,
977 kIconUrl3, gfx::Size(), sizeof(kBlob2), kBlob2));
978
979 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
980 }
981
982 // Check that the database is recovered at a SQLite level, and that
983 // the current schema is in place.
984 {
985 sql::Connection raw_db;
986 EXPECT_TRUE(raw_db.Open(file_name_));
987 ASSERT_EQ("ok", sql::test::IntegrityCheck(&raw_db));
988
989 // Check that the expected tables exist.
990 VerifyTablesAndColumns(&raw_db);
980 } 991 }
981 } 992 }
982 993
983 // Test that various broken schema found in the wild can be opened 994 // Test that various broken schema found in the wild can be opened
984 // successfully, and result in the correct schema. 995 // successfully, and result in the correct schema.
985 TEST_F(ThumbnailDatabaseTest, WildSchema) { 996 TEST_F(ThumbnailDatabaseTest, WildSchema) {
986 base::FilePath sql_path; 997 base::FilePath sql_path;
987 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &sql_path)); 998 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &sql_path));
988 sql_path = sql_path.AppendASCII("History").AppendASCII("thumbnail_wild"); 999 sql_path = sql_path.AppendASCII("History").AppendASCII("thumbnail_wild");
989 1000
(...skipping 13 matching lines...) Expand all
1003 ThumbnailDatabase db; 1014 ThumbnailDatabase db;
1004 ASSERT_EQ(sql::INIT_OK, db.Init(db_path)); 1015 ASSERT_EQ(sql::INIT_OK, db.Init(db_path));
1005 1016
1006 // Verify that the resulting schema is correct, whether it 1017 // Verify that the resulting schema is correct, whether it
1007 // involved razing the file or fixing things in place. 1018 // involved razing the file or fixing things in place.
1008 VerifyTablesAndColumns(&db.db_); 1019 VerifyTablesAndColumns(&db.db_);
1009 } 1020 }
1010 } 1021 }
1011 1022
1012 } // namespace history 1023 } // namespace history
OLDNEW
« no previous file with comments | « chrome/browser/history/thumbnail_database.cc ('k') | sql/connection_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698