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 |