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")); | |
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 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 |