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 std::shared_ptr<RdbStore> store_;
45 };
46
47 class CorruptTestOpenCallback : public RdbOpenCallback {
48 public:
49 int OnCreate(RdbStore &store) override;
50 int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override;
51 static constexpr const char *CREATE_TABLE_TEST = "CREATE TABLE IF NOT EXISTS test "
52 "(id INTEGER PRIMARY KEY AUTOINCREMENT, "
53 "name TEXT NOT NULL, age INTEGER, salary "
54 "REAL, blobType BLOB)";
55 };
56
OnCreate(RdbStore & store)57 int CorruptTestOpenCallback::OnCreate(RdbStore &store)
58 {
59 return store.ExecuteSql(CREATE_TABLE_TEST);
60 }
61
OnUpgrade(RdbStore & store,int oldVersion,int newVersion)62 int CorruptTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
63 {
64 return E_OK;
65 }
66
SetUp(void)67 void RdbCorruptTest::SetUp(void)
68 {
69 RdbHelper::ClearCache();
70 RdbHelper::DeleteRdbStore(RDB_TEST_PATH + DATABASE_NAME);
71 RdbStoreConfig sqliteSharedRstConfig(RDB_TEST_PATH + DATABASE_NAME);
72 CorruptTestOpenCallback openCallback;
73 int errCode = E_OK;
74 store_ = RdbHelper::GetRdbStore(sqliteSharedRstConfig, 1, openCallback, errCode);
75 EXPECT_NE(store_, nullptr);
76 EXPECT_EQ(errCode, E_OK);
77 // Preset 1000 entries into database file
78 GenerateData(1000);
79 store_ = nullptr;
80 RdbHelper::ClearCache();
81 }
82
TearDown(void)83 void RdbCorruptTest::TearDown(void)
84 {
85 RdbHelper::ClearCache();
86 RdbHelper::DeleteRdbStore(RDB_TEST_PATH + DATABASE_NAME);
87 }
88
GenerateData(int count)89 void RdbCorruptTest::GenerateData(int count)
90 {
91 for (int64_t i = 0; i < count; i++) {
92 // Preset data into database
93 RowData rowData = {1, "test", 18, 100.5, std::vector<uint8_t>{ 1, 2, 3 }};
94 rowData.id += i;
95 rowData.name += std::to_string(i + 1);
96 rowData.salary += i;
97 int64_t rowId = 0;
98 auto ret = store_->Insert(rowId, "test", UTUtils::SetRowData(rowData));
99 EXPECT_EQ(E_OK, ret);
100 EXPECT_EQ(i + 1, rowId);
101 }
102 }
103
DestroyDbFile(const std::string & filePath,size_t offset,size_t len,unsigned char ch)104 void RdbCorruptTest::DestroyDbFile(const std::string &filePath, size_t offset, size_t len, unsigned char ch)
105 {
106 std::fstream f;
107 f.open(filePath.c_str());
108
109 f.seekp(offset, std::ios::beg);
110 std::vector<char> buf(len, ch);
111 f.write(buf.data(), len);
112 f.close();
113 }
114
115 /**
116 * @tc.name: RdbCorruptTest001
117 * @tc.desc: test Rdb corruption
118 * @tc.type: FUNC
119 */
120 HWTEST_F(RdbCorruptTest, RdbCorruptTest001, TestSize.Level2)
121 {
122 // Destroy database file, set 1st byte of 3rd page into undefined flag, which indicate the btree page type
123 RdbCorruptTest::DestroyDbFile(RDB_TEST_PATH + DATABASE_NAME, 8192, 1, 0xFF);
124
125 // Get RDB store failed as database corrupted
126 CorruptTestOpenCallback sqliteCallback;
127 RdbStoreConfig sqliteConfig(RDB_TEST_PATH + DATABASE_NAME);
128 int errCode = E_OK;
129 store_ = RdbHelper::GetRdbStore(sqliteConfig, 1, sqliteCallback, errCode);
130 EXPECT_NE(store_, nullptr);
131 EXPECT_EQ(errCode, E_OK);
132
133 std::shared_ptr<ResultSet> resultSet = store_->QueryByStep("SELECT * FROM test");
134 EXPECT_NE(resultSet, nullptr);
135
136 while ((errCode = resultSet->GoToNextRow()) == E_OK) {
137 }
138 EXPECT_EQ(errCode, E_SQLITE_CORRUPT);
139 }
140 } // namespace Test