| 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 #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 Loading... |
| 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 ASSERT_EQ("ok", sql::test::IntegrityCheck(&raw_db)); | 793 { |
| 794 sql::Statement statement( |
| 795 raw_db.GetUniqueStatement("PRAGMA integrity_check")); |
| 796 EXPECT_TRUE(statement.Step()); |
| 797 ASSERT_EQ("ok", statement.ColumnString(0)); |
| 798 } |
| 794 | 799 |
| 795 const char kIndexName[] = "icon_mapping_page_url_idx"; | 800 const char kIndexName[] = "icon_mapping_page_url_idx"; |
| 796 const int idx_root_page = GetRootPage(&raw_db, kIndexName); | 801 const int idx_root_page = GetRootPage(&raw_db, kIndexName); |
| 797 const int page_size = GetPageSize(&raw_db); | 802 const int page_size = GetPageSize(&raw_db); |
| 798 scoped_ptr<char[]> buf(new char[page_size]); | 803 scoped_ptr<char[]> buf(new char[page_size]); |
| 799 EXPECT_TRUE(ReadPage(file_name_, idx_root_page, buf.get(), page_size)); | 804 EXPECT_TRUE(ReadPage(file_name_, idx_root_page, buf.get(), page_size)); |
| 800 | 805 |
| 801 { | 806 { |
| 802 const char kDeleteSql[] = "DELETE FROM icon_mapping WHERE page_url = ?"; | 807 const char kDeleteSql[] = "DELETE FROM icon_mapping WHERE page_url = ?"; |
| 803 sql::Statement statement(raw_db.GetUniqueStatement(kDeleteSql)); | 808 sql::Statement statement(raw_db.GetUniqueStatement(kDeleteSql)); |
| 804 statement.BindString(0, URLDatabase::GURLToDatabaseURL(kPageUrl2)); | 809 statement.BindString(0, URLDatabase::GURLToDatabaseURL(kPageUrl2)); |
| 805 EXPECT_TRUE(statement.Run()); | 810 EXPECT_TRUE(statement.Run()); |
| 806 } | 811 } |
| 807 raw_db.Close(); | 812 raw_db.Close(); |
| 808 | 813 |
| 809 EXPECT_TRUE(WritePage(file_name_, idx_root_page, buf.get(), page_size)); | 814 EXPECT_TRUE(WritePage(file_name_, idx_root_page, buf.get(), page_size)); |
| 810 } | 815 } |
| 811 | 816 |
| 812 // Database should be corrupt at the SQLite level. | 817 // Database should be corrupt at the SQLite level. |
| 813 { | 818 { |
| 814 sql::Connection raw_db; | 819 sql::Connection raw_db; |
| 815 EXPECT_TRUE(raw_db.Open(file_name_)); | 820 EXPECT_TRUE(raw_db.Open(file_name_)); |
| 816 ASSERT_NE("ok", sql::test::IntegrityCheck(&raw_db)); | 821 sql::Statement statement( |
| 822 raw_db.GetUniqueStatement("PRAGMA integrity_check")); |
| 823 EXPECT_TRUE(statement.Step()); |
| 824 ASSERT_NE("ok", statement.ColumnString(0)); |
| 817 } | 825 } |
| 818 | 826 |
| 819 // Open the database and access the corrupt index. | 827 // Open the database and access the corrupt index. |
| 820 { | 828 { |
| 821 sql::ScopedErrorIgnorer ignore_errors; | 829 sql::ScopedErrorIgnorer ignore_errors; |
| 822 ignore_errors.IgnoreError(SQLITE_CORRUPT); | 830 ignore_errors.IgnoreError(SQLITE_CORRUPT); |
| 823 ThumbnailDatabase db; | 831 ThumbnailDatabase db; |
| 824 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_)); | 832 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_)); |
| 825 | 833 |
| 826 // Data for kPageUrl2 was deleted, but the index entry remains, | 834 // Data for kPageUrl2 was deleted, but the index entry remains, |
| 827 // this will throw SQLITE_CORRUPT. The corruption handler will | 835 // this will throw SQLITE_CORRUPT. The corruption handler will |
| 828 // recover the database and poison the handle, so the outer call | 836 // recover the database and poison the handle, so the outer call |
| 829 // fails. | 837 // fails. |
| 830 EXPECT_FALSE(db.GetIconMappingsForPageURL(kPageUrl2, NULL)); | 838 EXPECT_FALSE(db.GetIconMappingsForPageURL(kPageUrl2, NULL)); |
| 831 | 839 |
| 832 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | 840 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
| 833 } | 841 } |
| 834 | 842 |
| 835 // Check that the database is recovered at the SQLite level. | 843 // Check that the database is recovered at the SQLite level. |
| 836 { | 844 { |
| 837 sql::Connection raw_db; | 845 sql::Connection raw_db; |
| 838 EXPECT_TRUE(raw_db.Open(file_name_)); | 846 EXPECT_TRUE(raw_db.Open(file_name_)); |
| 839 ASSERT_EQ("ok", sql::test::IntegrityCheck(&raw_db)); | 847 sql::Statement statement( |
| 848 raw_db.GetUniqueStatement("PRAGMA integrity_check")); |
| 849 EXPECT_TRUE(statement.Step()); |
| 850 EXPECT_EQ("ok", statement.ColumnString(0)); |
| 840 | 851 |
| 841 // Check that the expected tables exist. | 852 // Check that the expected tables exist. |
| 842 VerifyTablesAndColumns(&raw_db); | 853 VerifyTablesAndColumns(&raw_db); |
| 843 } | 854 } |
| 844 | 855 |
| 845 // Database should also be recovered at higher levels. | 856 // Database should also be recovered at higher levels. |
| 846 { | 857 { |
| 847 ThumbnailDatabase db; | 858 ThumbnailDatabase db; |
| 848 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_)); | 859 ASSERT_EQ(sql::INIT_OK, db.Init(file_name_)); |
| 849 | 860 |
| 850 // Now this fails because there is no mapping. | 861 // Now this fails because there is no mapping. |
| 851 EXPECT_FALSE(db.GetIconMappingsForPageURL(kPageUrl2, NULL)); | 862 EXPECT_FALSE(db.GetIconMappingsForPageURL(kPageUrl2, NULL)); |
| 852 | 863 |
| 853 // Other data was retained by recovery. | 864 // Other data was retained by recovery. |
| 854 EXPECT_TRUE( | 865 EXPECT_TRUE( |
| 855 CheckPageHasIcon(&db, kPageUrl1, chrome::FAVICON, | 866 CheckPageHasIcon(&db, kPageUrl1, chrome::FAVICON, |
| 856 kIconUrl1, kLargeSize, sizeof(kBlob1), kBlob1)); | 867 kIconUrl1, kLargeSize, sizeof(kBlob1), kBlob1)); |
| 857 } | 868 } |
| 858 | 869 |
| 859 // Corrupt the database again by adjusting the header. | 870 // Corrupt the database again by making the actual file shorter than |
| 860 EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_)); | 871 // the header expects. |
| 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 } |
| 861 | 885 |
| 862 // Database is unusable at the SQLite level. | 886 // Database is unusable at the SQLite level. |
| 863 { | 887 { |
| 864 sql::ScopedErrorIgnorer ignore_errors; | 888 sql::ScopedErrorIgnorer ignore_errors; |
| 865 ignore_errors.IgnoreError(SQLITE_CORRUPT); | 889 ignore_errors.IgnoreError(SQLITE_CORRUPT); |
| 866 sql::Connection raw_db; | 890 sql::Connection raw_db; |
| 867 EXPECT_TRUE(raw_db.Open(file_name_)); | 891 EXPECT_TRUE(raw_db.Open(file_name_)); |
| 868 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); | 892 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); |
| 869 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | 893 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
| 870 } | 894 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 887 | 911 |
| 888 TEST_F(ThumbnailDatabaseTest, Recovery6) { | 912 TEST_F(ThumbnailDatabaseTest, Recovery6) { |
| 889 // TODO(shess): See comment at top of Recovery test. | 913 // TODO(shess): See comment at top of Recovery test. |
| 890 if (!sql::Recovery::FullRecoverySupported()) | 914 if (!sql::Recovery::FullRecoverySupported()) |
| 891 return; | 915 return; |
| 892 | 916 |
| 893 // Create an example database without loading into ThumbnailDatabase | 917 // Create an example database without loading into ThumbnailDatabase |
| 894 // (which would upgrade it). | 918 // (which would upgrade it). |
| 895 EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "Favicons.v6.sql")); | 919 EXPECT_TRUE(CreateDatabaseFromSQL(file_name_, "Favicons.v6.sql")); |
| 896 | 920 |
| 897 // Corrupt the database again by adjusting the header. This form of | 921 // Corrupt the database by making the actual file shorter than the |
| 898 // corruption will cause immediate failures during Open(), before | 922 // SQLite header expects. This form of corruption will cause |
| 899 // the migration code runs, so the version-6 recovery will occur. | 923 // immediate failures during Open(), before the migration code runs, |
| 900 EXPECT_TRUE(sql::test::CorruptSizeInHeader(file_name_)); | 924 // so the version-6 recovery will occur. |
| 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 } |
| 901 | 938 |
| 902 // Database is unusable at the SQLite level. | 939 // Database is unusable at the SQLite level. |
| 903 { | 940 { |
| 904 sql::ScopedErrorIgnorer ignore_errors; | 941 sql::ScopedErrorIgnorer ignore_errors; |
| 905 ignore_errors.IgnoreError(SQLITE_CORRUPT); | 942 ignore_errors.IgnoreError(SQLITE_CORRUPT); |
| 906 sql::Connection raw_db; | 943 sql::Connection raw_db; |
| 907 EXPECT_TRUE(raw_db.Open(file_name_)); | 944 EXPECT_TRUE(raw_db.Open(file_name_)); |
| 908 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); | 945 EXPECT_FALSE(raw_db.IsSQLValid("PRAGMA integrity_check")); |
| 909 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | 946 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
| 910 } | 947 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 926 kIconUrl3, kLargeSize, sizeof(kBlob2), kBlob2)); | 963 kIconUrl3, kLargeSize, sizeof(kBlob2), kBlob2)); |
| 927 | 964 |
| 928 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | 965 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
| 929 } | 966 } |
| 930 | 967 |
| 931 // Check that the database is recovered at a SQLite level, and that | 968 // Check that the database is recovered at a SQLite level, and that |
| 932 // the current schema is in place. | 969 // the current schema is in place. |
| 933 { | 970 { |
| 934 sql::Connection raw_db; | 971 sql::Connection raw_db; |
| 935 EXPECT_TRUE(raw_db.Open(file_name_)); | 972 EXPECT_TRUE(raw_db.Open(file_name_)); |
| 936 ASSERT_EQ("ok", sql::test::IntegrityCheck(&raw_db)); | 973 sql::Statement statement( |
| 937 | 974 raw_db.GetUniqueStatement("PRAGMA integrity_check")); |
| 938 // Check that the expected tables exist. | 975 EXPECT_TRUE(statement.Step()); |
| 939 VerifyTablesAndColumns(&raw_db); | 976 EXPECT_EQ("ok", statement.ColumnString(0)); |
| 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 | 977 |
| 989 // Check that the expected tables exist. | 978 // Check that the expected tables exist. |
| 990 VerifyTablesAndColumns(&raw_db); | 979 VerifyTablesAndColumns(&raw_db); |
| 991 } | 980 } |
| 992 } | 981 } |
| 993 | 982 |
| 994 // Test that various broken schema found in the wild can be opened | 983 // Test that various broken schema found in the wild can be opened |
| 995 // successfully, and result in the correct schema. | 984 // successfully, and result in the correct schema. |
| 996 TEST_F(ThumbnailDatabaseTest, WildSchema) { | 985 TEST_F(ThumbnailDatabaseTest, WildSchema) { |
| 997 base::FilePath sql_path; | 986 base::FilePath sql_path; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1014 ThumbnailDatabase db; | 1003 ThumbnailDatabase db; |
| 1015 ASSERT_EQ(sql::INIT_OK, db.Init(db_path)); | 1004 ASSERT_EQ(sql::INIT_OK, db.Init(db_path)); |
| 1016 | 1005 |
| 1017 // Verify that the resulting schema is correct, whether it | 1006 // Verify that the resulting schema is correct, whether it |
| 1018 // involved razing the file or fixing things in place. | 1007 // involved razing the file or fixing things in place. |
| 1019 VerifyTablesAndColumns(&db.db_); | 1008 VerifyTablesAndColumns(&db.db_); |
| 1020 } | 1009 } |
| 1021 } | 1010 } |
| 1022 | 1011 |
| 1023 } // namespace history | 1012 } // namespace history |
| OLD | NEW |