| 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 { | 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 Loading... |
| 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 Loading... |
| 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")); | 937 |
| 975 EXPECT_TRUE(statement.Step()); | 938 // Check that the expected tables exist. |
| 976 EXPECT_EQ("ok", statement.ColumnString(0)); | 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)); |
| 977 | 988 |
| 978 // Check that the expected tables exist. | 989 // Check that the expected tables exist. |
| 979 VerifyTablesAndColumns(&raw_db); | 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; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 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 |
| OLD | NEW |