• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <gtest/gtest.h>
17 
18 #include <fstream>
19 #include <string>
20 #include <unistd.h>
21 #include <vector>
22 
23 #include "common.h"
24 #include "logger.h"
25 #include "rdb_errno.h"
26 #include "rdb_helper.h"
27 #include "rdb_open_callback.h"
28 
29 using namespace testing::ext;
30 using namespace OHOS::Rdb;
31 using namespace OHOS::NativeRdb;
32 
33 namespace Test {
34 
35 class RdbCorruptTest : public testing::Test {
36 public:
SetUpTestCase(void)37     static void SetUpTestCase(void) {}
TearDownTestCase(void)38     static void TearDownTestCase(void) {}
39     void SetUp();
40     void TearDown();
41     void GenerateData(int count);
42     static void DestroyDbFile(const std::string &filePath, size_t offset, size_t len, unsigned char ch);
43     static constexpr const char *DATABASE_NAME = "corrupt_test.db";
44     static constexpr int DB_FILE_HEADER_LENGTH = 100;
45     std::shared_ptr<RdbStore> store_;
46 };
47 
48 class CorruptTestOpenCallback : public RdbOpenCallback {
49 public:
50     int OnCreate(RdbStore &store) override;
51     int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override;
52     static constexpr const char *CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test "
53                                                      "(id INTEGER PRIMARY KEY AUTOINCREMENT, "
54                                                      "name TEXT NOT NULL, age INTEGER, salary "
55                                                      "REAL, blobType BLOB)";
56 };
57 
OnCreate(RdbStore & store)58 int CorruptTestOpenCallback::OnCreate(RdbStore &store)
59 {
60     return store.ExecuteSql(CREATE_TABLE_TEST);
61 }
62 
OnUpgrade(RdbStore & store,int oldVersion,int newVersion)63 int CorruptTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
64 {
65     return E_OK;
66 }
67 
SetUp(void)68 void RdbCorruptTest::SetUp(void)
69 {
70     RdbHelper::ClearCache();
71     RdbHelper::DeleteRdbStore(RDB_TEST_PATH + DATABASE_NAME);
72     RdbStoreConfig sqliteSharedRstConfig(RDB_TEST_PATH + DATABASE_NAME);
73     CorruptTestOpenCallback openCallback;
74     int errCode = E_OK;
75     store_ = RdbHelper::GetRdbStore(sqliteSharedRstConfig, 1, openCallback, errCode);
76     EXPECT_NE(store_, nullptr);
77     EXPECT_EQ(errCode, E_OK);
78     // Preset 1000 entries into database file
79     GenerateData(1000);
80     store_ = nullptr;
81     RdbHelper::ClearCache();
82 }
83 
TearDown(void)84 void RdbCorruptTest::TearDown(void)
85 {
86     RdbHelper::ClearCache();
87     RdbHelper::DeleteRdbStore(RDB_TEST_PATH + DATABASE_NAME);
88 }
89 
GenerateData(int count)90 void RdbCorruptTest::GenerateData(int count)
91 {
92     for (int64_t i = 0; i < count; i++) {
93         // Preset data into database
94         RowData rowData = {1, "test", 18, 100.5, std::vector<uint8_t>{ 1, 2, 3 }};
95         rowData.id += i;
96         rowData.name += std::to_string(i + 1);
97         rowData.salary += i;
98         int64_t rowId = 0;
99         auto ret = store_->Insert(rowId, "test", UTUtils::SetRowData(rowData));
100         EXPECT_EQ(E_OK, ret);
101         EXPECT_EQ(i + 1, rowId);
102     }
103 }
104 
DestroyDbFile(const std::string & filePath,size_t offset,size_t len,unsigned char ch)105 void RdbCorruptTest::DestroyDbFile(const std::string &filePath, size_t offset, size_t len, unsigned char ch)
106 {
107     std::fstream f;
108     f.open(filePath.c_str());
109 
110     f.seekp(offset, std::ios::beg);
111     std::vector<char> buf(len, ch);
112     f.write(buf.data(), len);
113     f.close();
114 }
115 
116 /**
117  * @tc.name: RdbCorruptTest001
118  * @tc.desc: test Rdb corruption
119  * @tc.type: FUNC
120  */
121 HWTEST_F(RdbCorruptTest, RdbCorruptTest001, TestSize.Level2)
122 {
123     // Destroy database file, set 1st byte of 3rd page into undefined flag, which indicate the btree page type
124     RdbCorruptTest::DestroyDbFile(RDB_TEST_PATH + DATABASE_NAME, 8192, 1, 0xFF);
125 
126     // Get RDB store failed as database corrupted
127     CorruptTestOpenCallback sqliteCallback;
128     RdbStoreConfig sqliteConfig(RDB_TEST_PATH + DATABASE_NAME);
129     int errCode = E_OK;
130     store_ = RdbHelper::GetRdbStore(sqliteConfig, 1, sqliteCallback, errCode);
131     EXPECT_NE(store_, nullptr);
132     EXPECT_EQ(errCode, E_OK);
133 
134     std::shared_ptr<ResultSet> resultSet = store_->QueryByStep("SELECT * FROM test");
135     EXPECT_NE(resultSet, nullptr);
136 
137     while ((errCode = resultSet->GoToNextRow()) == E_OK) {
138     }
139     EXPECT_EQ(errCode, E_SQLITE_CORRUPT);
140 }
141 
142 /**
143  * @tc.name: RdbCorruptTest002
144  * @tc.desc: test Rdb verify db file header's reserved bytes
145  * @tc.type: FUNC
146  */
147 HWTEST_F(RdbCorruptTest, RdbCorruptTest002, TestSize.Level2)
148 {
149     std::fstream f;
150     f.open(RDB_TEST_PATH + DATABASE_NAME);
151     f.seekp(0, std::ios::beg);
152     char buf[DB_FILE_HEADER_LENGTH] = {0};
153     f.read(buf, sizeof(buf));
154     f.close();
155     // 20 is the offset of reserved bytes field
156     EXPECT_EQ((unsigned int)buf[20], 0);
157 }
158 } // namespace Test