1 /*
2 * Copyright (c) 2021 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 <fstream>
17 #include <gtest/gtest.h>
18
19 #include "db_errno.h"
20 #include "distributeddb_tools_unit_test.h"
21 #include "package_file.h"
22 #include "platform_specific.h"
23 #include "securec.h"
24 #include "value_hash_calc.h"
25
26 using namespace testing::ext;
27 using namespace DistributedDB;
28 using namespace DistributedDBUnitTest;
29 using namespace std;
30
31 namespace {
32 string g_testPath;
33 string g_sourcePath = "/source/";
34 string g_packageResultPath = "/package_result/";
35 string g_unpackResultPath = "/unpack_result/";
36 FileInfo g_fileInfo;
37 const string PACKAGE_RESULT_FILE_NAME = "package_result.dat";
38 const string NON_EXIST_PATH = "/nonexist/";
39 const string FILE_NAME_1 = "file1.txt";
40 const string FILE_NAME_2 = "file2.dat";
41 const string FILE_CONTENT_1 = "Hello world.";
42 const string NON_EXIST_FILE = "nonexist.dat";
43 const string EMPTY_FILE = "empty.dat";
44 const string SECURE_FILE = "secure.dat";
45 const int FILE_CONTENT_2_LEN = 4;
46 const char FILE_CONTENT_2[FILE_CONTENT_2_LEN] = {0x5B, 0x3A, 0x29, 0x3E};
47 const int BUFFER_SIZE = 4096;
48 const int DEVICE_ID_LEN = 32;
49 const vector<uint8_t> DIVICE_ID = {'a', 'e', 'i', 'o', 'u'};
50
RemovePath(const string & path)51 void RemovePath(const string &path)
52 {
53 list<OS::FileAttr> files;
54 int errCode = OS::GetFileAttrFromPath(path, files);
55 ASSERT_EQ(errCode, E_OK);
56 for (auto file : files) {
57 string fileName = path + "/" + file.fileName;
58 switch (file.fileType) {
59 case OS::FILE:
60 (void)remove(fileName.c_str());
61 break;
62 case OS::PATH:
63 if (file.fileName != "." && file.fileName != "..") {
64 RemovePath(fileName);
65 }
66 break;
67 default:
68 break;
69 }
70 }
71 (void)OS::RemoveDBDirectory(path);
72 }
73
CompareFileName(const OS::FileAttr & file1,const OS::FileAttr & file2)74 bool CompareFileName(const OS::FileAttr &file1, const OS::FileAttr &file2)
75 {
76 return file1.fileName <= file2.fileName;
77 }
78
ComparePath(const string & path1,const string & path2)79 void ComparePath(const string &path1, const string &path2)
80 {
81 list<OS::FileAttr> files1;
82 int errCode = OS::GetFileAttrFromPath(path1, files1);
83 ASSERT_EQ(errCode, E_OK);
84 files1.sort(CompareFileName);
85 list<OS::FileAttr> files2;
86 errCode = OS::GetFileAttrFromPath(path2, files2);
87 ASSERT_EQ(errCode, E_OK);
88 files2.sort(CompareFileName);
89 ASSERT_EQ(files1.size(), files2.size());
90 auto fileIter1 = files1.begin();
91 auto fileIter2 = files2.begin();
92 vector<char> buffer1(BUFFER_SIZE, 0);
93 vector<char> buffer2(BUFFER_SIZE, 0);
94 string bufferStr1;
95 string bufferStr2;
96 for (; fileIter1 != files1.end() && fileIter2 != files2.end(); fileIter1++, fileIter2++) {
97 ASSERT_STREQ(fileIter1->fileName.c_str(), fileIter2->fileName.c_str());
98 ASSERT_EQ(fileIter1->fileType, fileIter2->fileType);
99 ASSERT_EQ(fileIter1->fileLen, fileIter2->fileLen);
100 if (fileIter1->fileType != OS::FILE) {
101 continue;
102 }
103 ifstream file1(path1 + fileIter1->fileName, ios::out | ios::binary);
104 ASSERT_TRUE(file1.is_open());
105 ifstream file2(path2 + fileIter2->fileName, ios::out | ios::binary);
106 ASSERT_TRUE(file2.is_open());
107 buffer1.assign(BUFFER_SIZE, 0);
108 buffer2.assign(BUFFER_SIZE, 0);
109 for (file1.read(buffer1.data(), BUFFER_SIZE), file2.read(buffer2.data(), BUFFER_SIZE);
110 !(file1.eof() || file2.eof());
111 file1.read(buffer1.data(), BUFFER_SIZE), file2.read(buffer2.data(), BUFFER_SIZE)) {
112 bufferStr1.assign(buffer1.begin(), buffer1.end());
113 bufferStr2.assign(buffer2.begin(), buffer2.end());
114 ASSERT_STREQ(bufferStr1.c_str(), bufferStr2.c_str());
115 }
116 file1.close();
117 file2.close();
118 bufferStr1.assign(buffer1.begin(), buffer1.end());
119 bufferStr2.assign(buffer2.begin(), buffer2.end());
120 ASSERT_STREQ(bufferStr1.c_str(), bufferStr2.c_str());
121 }
122 }
123 }
124
125 class DistributedDBFilePackageTest : public testing::Test {
126 public:
127 static void SetUpTestCase(void);
128 static void TearDownTestCase(void);
129 void SetUp();
130 void TearDown();
131 };
132
SetUpTestCase(void)133 void DistributedDBFilePackageTest::SetUpTestCase(void)
134 {
135 DistributedDBToolsUnitTest::TestDirInit(g_testPath);
136 g_sourcePath = g_testPath + g_sourcePath;
137 g_packageResultPath = g_testPath + g_packageResultPath;
138 g_unpackResultPath = g_testPath + g_unpackResultPath;
139 (void)OS::MakeDBDirectory(g_sourcePath);
140 ofstream file1(g_sourcePath + FILE_NAME_1, ios::out | ios::binary | ios::trunc);
141 ASSERT_TRUE(file1.is_open());
142 file1.write(FILE_CONTENT_1.c_str(), FILE_CONTENT_1.size());
143 file1.close();
144 ofstream file2(g_sourcePath + FILE_NAME_2, ios::out | ios::binary | ios::trunc);
145 ASSERT_TRUE(file2.is_open());
146 file2.write(FILE_CONTENT_2, FILE_CONTENT_2_LEN);
147 file2.close();
148 g_fileInfo.dbType = 1;
149 ValueHashCalc calc;
150 int errCode = calc.Initialize();
151 ASSERT_EQ(errCode, E_OK);
152 errCode = calc.Update(DIVICE_ID);
153 ASSERT_EQ(errCode, E_OK);
154 vector<uint8_t> deviceIDVec;
155 errCode = calc.GetResult(deviceIDVec);
156 ASSERT_EQ(errCode, E_OK);
157 g_fileInfo.deviceID.resize(DEVICE_ID_LEN);
158 g_fileInfo.deviceID.assign(deviceIDVec.begin(), deviceIDVec.end());
159 }
160
TearDownTestCase(void)161 void DistributedDBFilePackageTest::TearDownTestCase(void)
162 {
163 RemovePath(g_testPath);
164 }
165
SetUp(void)166 void DistributedDBFilePackageTest::SetUp(void)
167 {
168 DistributedDBToolsUnitTest::PrintTestCaseInfo();
169 (void)OS::MakeDBDirectory(g_packageResultPath);
170 (void)OS::MakeDBDirectory(g_unpackResultPath);
171 }
172
TearDown(void)173 void DistributedDBFilePackageTest::TearDown(void)
174 {
175 RemovePath(g_packageResultPath);
176 RemovePath(g_unpackResultPath);
177 }
178
179 /**
180 * @tc.name: PackageFileTest001
181 * @tc.desc: Test file package and unpack functions.
182 * @tc.type: FUNC
183 * @tc.require:
184 * @tc.author: liujialei
185 */
186 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest001, TestSize.Level0)
187 {
188 int errCode = PackageFile::PackageFiles(g_sourcePath, g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
189 ASSERT_EQ(errCode, E_OK);
190 FileInfo fileInfo;
191 errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_unpackResultPath, fileInfo);
192 ASSERT_EQ(errCode, E_OK);
193 ComparePath(g_sourcePath, g_unpackResultPath);
194 ASSERT_EQ(fileInfo.dbType, g_fileInfo.dbType);
195 }
196
197 /**
198 * @tc.name: PackageFileTest002
199 * @tc.desc: Test file package if source path is not exist.
200 * @tc.type: FUNC
201 * @tc.require:
202 * @tc.author: liujialei
203 */
204 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest002, TestSize.Level0)
205 {
206 int errCode = PackageFile::PackageFiles(g_sourcePath + NON_EXIST_PATH,
207 g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
208 ASSERT_EQ(errCode, -E_INVALID_PATH);
209 }
210
211 /**
212 * @tc.name: PackageFileTest003
213 * @tc.desc: Test file package if result path is not exist.
214 * @tc.type: FUNC
215 * @tc.require:
216 * @tc.author: liujialei
217 */
218 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest003, TestSize.Level0)
219 {
220 int errCode = PackageFile::PackageFiles(g_sourcePath,
221 g_packageResultPath + NON_EXIST_PATH + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
222 ASSERT_EQ(errCode, -E_INVALID_PATH);
223 }
224
225 /**
226 * @tc.name: PackageFileTest004
227 * @tc.desc: Test file package if source path is empty.
228 * @tc.type: FUNC
229 * @tc.require:
230 * @tc.author: liujialei
231 */
232 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest004, TestSize.Level0)
233 {
234 // Clear source files.
235 RemovePath(g_sourcePath);
236 (void)OS::MakeDBDirectory(g_sourcePath);
237 // Test function.
238 int errCode = PackageFile::PackageFiles(g_sourcePath, g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
239 ASSERT_EQ(errCode, -E_EMPTY_PATH);
240 // Create source files again.
241 ofstream file1(g_sourcePath + FILE_NAME_1, ios::out | ios::binary | ios::trunc);
242 ASSERT_TRUE(file1.is_open());
243 file1.write(FILE_CONTENT_1.c_str(), FILE_CONTENT_1.size());
244 file1.close();
245 ofstream file2(g_sourcePath + FILE_NAME_2, ios::out | ios::binary | ios::trunc);
246 ASSERT_TRUE(file2.is_open());
247 file2.write(FILE_CONTENT_2, 4);
248 file2.close();
249 }
250
251 /**
252 * @tc.name: PackageFileTest005
253 * @tc.desc: Test file unpack if source file is not exist.
254 * @tc.type: FUNC
255 * @tc.require:
256 * @tc.author: liujialei
257 */
258 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest005, TestSize.Level0)
259 {
260 FileInfo fileInfo;
261 int errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_unpackResultPath, fileInfo);
262 ASSERT_EQ(errCode, -E_INVALID_PATH);
263 }
264
265 /**
266 * @tc.name: PackageFileTest006
267 * @tc.desc: Test file unpack if result path is not exist.
268 * @tc.type: FUNC
269 * @tc.require:
270 * @tc.author: liujialei
271 */
272 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest006, TestSize.Level0)
273 {
274 int errCode = PackageFile::PackageFiles(g_sourcePath, g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
275 ASSERT_EQ(errCode, E_OK);
276 FileInfo fileInfo;
277 errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME,
278 g_unpackResultPath + NON_EXIST_PATH, fileInfo);
279 ASSERT_EQ(errCode, -E_INVALID_PATH);
280 }
281
282 /**
283 * @tc.name: PackageFileTest007
284 * @tc.desc: Test file unpack if magic check failed.
285 * @tc.type: FUNC
286 * @tc.require:
287 * @tc.author: liujialei
288 */
289 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest007, TestSize.Level0)
290 {
291 int errCode = PackageFile::PackageFiles(g_sourcePath, g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
292 ASSERT_EQ(errCode, E_OK);
293 // Change package file header.
294 const string REPLACE_FILE_HEADER = "test";
295 fstream file(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, ios::in | ios::out | ios::binary);
296 ASSERT_TRUE(file.is_open());
297 file.seekp(0, ios_base::beg);
298 file.write(REPLACE_FILE_HEADER.c_str(), REPLACE_FILE_HEADER.size());
299 file.close();
300 // Unpack file.
301 FileInfo fileInfo;
302 errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_unpackResultPath, fileInfo);
303 ASSERT_EQ(errCode, -E_INVALID_FILE);
304 }
305
306 /**
307 * @tc.name: PackageFileTest008
308 * @tc.desc: Test file unpack if checksum check failed.
309 * @tc.type: FUNC
310 * @tc.require:
311 * @tc.author: liujialei
312 */
313 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest008, TestSize.Level0)
314 {
315 int errCode = PackageFile::PackageFiles(g_sourcePath, g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
316 ASSERT_EQ(errCode, E_OK);
317 // Rewrite package file without file tail.
318 ifstream fileIn(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, ios::in | ios::binary);
319 ASSERT_TRUE(fileIn.is_open());
320 fileIn.seekg(0, ios_base::end);
321 int fileLen = fileIn.tellg();
322 fileIn.seekg(0, ios_base::beg);
323 const int CUT_TAIL = 3;
324 int bufferLen = fileLen > BUFFER_SIZE ? BUFFER_SIZE : fileLen - CUT_TAIL;
325 vector<char> buffer(bufferLen, 0);
326 fileIn.read(buffer.data(), buffer.size());
327 fileIn.close();
328 ofstream fileOut(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, ios::out | ios::binary | ios::trunc);
329 ASSERT_TRUE(fileOut.is_open());
330 fileOut.write(buffer.data(), buffer.size());
331 fileOut.close();
332 // Unpack file.
333 FileInfo fileInfo;
334 errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_unpackResultPath, fileInfo);
335 ASSERT_EQ(errCode, -E_INVALID_FILE);
336 }
337
338 /**
339 * @tc.name: GetPackageVersionTest001
340 * @tc.desc: Test GetPackageVersion func.
341 * @tc.type: FUNC
342 * @tc.require:
343 * @tc.author: tiansimiao
344 */
345 HWTEST_F(DistributedDBFilePackageTest, GetPackageVersionTest001, TestSize.Level0)
346 {
347 uint32_t version;
348 std::ofstream emptyFile(g_packageResultPath + EMPTY_FILE, ios::out | ios::binary | ios::trunc);
349 ASSERT_TRUE(emptyFile.is_open());
350 emptyFile.close();
351 std::ofstream secureFile(g_packageResultPath + SECURE_FILE, ios::out | ios::binary | ios::trunc);
352 ASSERT_TRUE(secureFile.is_open());
353 secureFile.close();
354 EXPECT_EQ(chmod((g_packageResultPath + SECURE_FILE).c_str(), S_IRUSR | S_IRGRP | S_IROTH), E_OK);
355 int errCode = PackageFile::GetPackageVersion(g_packageResultPath + NON_EXIST_FILE, version);
356 EXPECT_EQ(errCode, -E_INVALID_PATH);
357 errCode = PackageFile::GetPackageVersion(g_packageResultPath + EMPTY_FILE, version);
358 EXPECT_EQ(errCode, -E_INVALID_PATH);
359 int oldErr = errno;
360 errno = EKEYREVOKED;
361 errCode = PackageFile::GetPackageVersion(g_packageResultPath + SECURE_FILE, version);
362 EXPECT_EQ(errCode, -E_EKEYREVOKED);
363 errno = oldErr;
364 }