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 int FILE_CONTENT_2_LEN = 4;
43 const char FILE_CONTENT_2[FILE_CONTENT_2_LEN] = {0x5B, 0x3A, 0x29, 0x3E};
44 const int BUFFER_SIZE = 4096;
45 const int DEVICE_ID_LEN = 32;
46 const vector<uint8_t> DIVICE_ID = {'a', 'e', 'i', 'o', 'u'};
47
RemovePath(const string & path)48 void RemovePath(const string &path)
49 {
50 list<OS::FileAttr> files;
51 int errCode = OS::GetFileAttrFromPath(path, files);
52 ASSERT_EQ(errCode, E_OK);
53 for (auto file : files) {
54 string fileName = path + "/" + file.fileName;
55 switch (file.fileType) {
56 case OS::FILE:
57 (void)remove(fileName.c_str());
58 break;
59 case OS::PATH:
60 if (file.fileName != "." && file.fileName != "..") {
61 RemovePath(fileName);
62 }
63 break;
64 default:
65 break;
66 }
67 }
68 (void)OS::RemoveDBDirectory(path);
69 }
70
CompareFileName(const OS::FileAttr & file1,const OS::FileAttr & file2)71 bool CompareFileName(const OS::FileAttr &file1, const OS::FileAttr &file2)
72 {
73 return file1.fileName <= file2.fileName;
74 }
75
ComparePath(const string & path1,const string & path2)76 void ComparePath(const string &path1, const string &path2)
77 {
78 list<OS::FileAttr> files1;
79 int errCode = OS::GetFileAttrFromPath(path1, files1);
80 ASSERT_EQ(errCode, E_OK);
81 files1.sort(CompareFileName);
82 list<OS::FileAttr> files2;
83 errCode = OS::GetFileAttrFromPath(path2, files2);
84 ASSERT_EQ(errCode, E_OK);
85 files2.sort(CompareFileName);
86 ASSERT_EQ(files1.size(), files2.size());
87 auto fileIter1 = files1.begin();
88 auto fileIter2 = files2.begin();
89 vector<char> buffer1(BUFFER_SIZE, 0);
90 vector<char> buffer2(BUFFER_SIZE, 0);
91 string bufferStr1;
92 string bufferStr2;
93 for (; fileIter1 != files1.end() && fileIter2 != files2.end(); fileIter1++, fileIter2++) {
94 ASSERT_STREQ(fileIter1->fileName.c_str(), fileIter2->fileName.c_str());
95 ASSERT_EQ(fileIter1->fileType, fileIter2->fileType);
96 ASSERT_EQ(fileIter1->fileLen, fileIter2->fileLen);
97 if (fileIter1->fileType != OS::FILE) {
98 continue;
99 }
100 ifstream file1(path1 + fileIter1->fileName, ios::out | ios::binary);
101 ASSERT_TRUE(file1.is_open());
102 ifstream file2(path2 + fileIter2->fileName, ios::out | ios::binary);
103 ASSERT_TRUE(file2.is_open());
104 buffer1.assign(BUFFER_SIZE, 0);
105 buffer2.assign(BUFFER_SIZE, 0);
106 for (file1.read(buffer1.data(), BUFFER_SIZE), file2.read(buffer2.data(), BUFFER_SIZE);
107 !(file1.eof() || file2.eof());
108 file1.read(buffer1.data(), BUFFER_SIZE), file2.read(buffer2.data(), BUFFER_SIZE)) {
109 bufferStr1.assign(buffer1.begin(), buffer1.end());
110 bufferStr2.assign(buffer2.begin(), buffer2.end());
111 ASSERT_STREQ(bufferStr1.c_str(), bufferStr2.c_str());
112 }
113 file1.close();
114 file2.close();
115 bufferStr1.assign(buffer1.begin(), buffer1.end());
116 bufferStr2.assign(buffer2.begin(), buffer2.end());
117 ASSERT_STREQ(bufferStr1.c_str(), bufferStr2.c_str());
118 }
119 }
120 }
121
122 class DistributedDBFilePackageTest : public testing::Test {
123 public:
124 static void SetUpTestCase(void);
125 static void TearDownTestCase(void);
126 void SetUp();
127 void TearDown();
128 };
129
SetUpTestCase(void)130 void DistributedDBFilePackageTest::SetUpTestCase(void)
131 {
132 DistributedDBToolsUnitTest::TestDirInit(g_testPath);
133 g_sourcePath = g_testPath + g_sourcePath;
134 g_packageResultPath = g_testPath + g_packageResultPath;
135 g_unpackResultPath = g_testPath + g_unpackResultPath;
136 (void)OS::MakeDBDirectory(g_sourcePath);
137 ofstream file1(g_sourcePath + FILE_NAME_1, ios::out | ios::binary | ios::trunc);
138 ASSERT_TRUE(file1.is_open());
139 file1.write(FILE_CONTENT_1.c_str(), FILE_CONTENT_1.size());
140 file1.close();
141 ofstream file2(g_sourcePath + FILE_NAME_2, ios::out | ios::binary | ios::trunc);
142 ASSERT_TRUE(file2.is_open());
143 file2.write(FILE_CONTENT_2, FILE_CONTENT_2_LEN);
144 file2.close();
145 g_fileInfo.dbType = 1;
146 ValueHashCalc calc;
147 int errCode = calc.Initialize();
148 ASSERT_EQ(errCode, E_OK);
149 errCode = calc.Update(DIVICE_ID);
150 ASSERT_EQ(errCode, E_OK);
151 vector<uint8_t> deviceIDVec;
152 errCode = calc.GetResult(deviceIDVec);
153 ASSERT_EQ(errCode, E_OK);
154 g_fileInfo.deviceID.resize(DEVICE_ID_LEN);
155 g_fileInfo.deviceID.assign(deviceIDVec.begin(), deviceIDVec.end());
156 }
157
TearDownTestCase(void)158 void DistributedDBFilePackageTest::TearDownTestCase(void)
159 {
160 RemovePath(g_testPath);
161 }
162
SetUp(void)163 void DistributedDBFilePackageTest::SetUp(void)
164 {
165 DistributedDBToolsUnitTest::PrintTestCaseInfo();
166 (void)OS::MakeDBDirectory(g_packageResultPath);
167 (void)OS::MakeDBDirectory(g_unpackResultPath);
168 }
169
TearDown(void)170 void DistributedDBFilePackageTest::TearDown(void)
171 {
172 RemovePath(g_packageResultPath);
173 RemovePath(g_unpackResultPath);
174 }
175
176 /**
177 * @tc.name: PackageFileTest001
178 * @tc.desc: Test file package and unpack functions.
179 * @tc.type: FUNC
180 * @tc.require: AR000D4879
181 * @tc.author: liujialei
182 */
183 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest001, TestSize.Level1)
184 {
185 int errCode = PackageFile::PackageFiles(g_sourcePath, g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
186 ASSERT_EQ(errCode, E_OK);
187 FileInfo fileInfo;
188 errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_unpackResultPath, fileInfo);
189 ASSERT_EQ(errCode, E_OK);
190 ComparePath(g_sourcePath, g_unpackResultPath);
191 ASSERT_EQ(fileInfo.dbType, g_fileInfo.dbType);
192 return;
193 }
194
195 /**
196 * @tc.name: PackageFileTest002
197 * @tc.desc: Test file package if source path is not exist.
198 * @tc.type: FUNC
199 * @tc.require: AR000D4879
200 * @tc.author: liujialei
201 */
202 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest002, TestSize.Level1)
203 {
204 int errCode = PackageFile::PackageFiles(g_sourcePath + NON_EXIST_PATH,
205 g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
206 ASSERT_EQ(errCode, -E_INVALID_PATH);
207 return;
208 }
209
210 /**
211 * @tc.name: PackageFileTest003
212 * @tc.desc: Test file package if result path is not exist.
213 * @tc.type: FUNC
214 * @tc.require: AR000D4879
215 * @tc.author: liujialei
216 */
217 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest003, TestSize.Level1)
218 {
219 int errCode = PackageFile::PackageFiles(g_sourcePath,
220 g_packageResultPath + NON_EXIST_PATH + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
221 ASSERT_EQ(errCode, -E_INVALID_PATH);
222 return;
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: AR000D4879
230 * @tc.author: liujialei
231 */
232 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest004, TestSize.Level1)
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 return;
250 }
251
252 /**
253 * @tc.name: PackageFileTest005
254 * @tc.desc: Test file unpack if source file is not exist.
255 * @tc.type: FUNC
256 * @tc.require: AR000D4879
257 * @tc.author: liujialei
258 */
259 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest005, TestSize.Level1)
260 {
261 FileInfo fileInfo;
262 int errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_unpackResultPath, fileInfo);
263 ASSERT_EQ(errCode, -E_INVALID_PATH);
264 return;
265 }
266
267 /**
268 * @tc.name: PackageFileTest006
269 * @tc.desc: Test file unpack if result path is not exist.
270 * @tc.type: FUNC
271 * @tc.require: AR000D4879
272 * @tc.author: liujialei
273 */
274 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest006, TestSize.Level1)
275 {
276 int errCode = PackageFile::PackageFiles(g_sourcePath, g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
277 ASSERT_EQ(errCode, E_OK);
278 FileInfo fileInfo;
279 errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME,
280 g_unpackResultPath + NON_EXIST_PATH, fileInfo);
281 ASSERT_EQ(errCode, -E_INVALID_PATH);
282 return;
283 }
284
285 /**
286 * @tc.name: PackageFileTest007
287 * @tc.desc: Test file unpack if magic check failed.
288 * @tc.type: FUNC
289 * @tc.require: AR000D4879
290 * @tc.author: liujialei
291 */
292 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest007, TestSize.Level1)
293 {
294 int errCode = PackageFile::PackageFiles(g_sourcePath, g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
295 ASSERT_EQ(errCode, E_OK);
296 // Change package file header.
297 const string REPLACE_FILE_HEADER = "test";
298 fstream file(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, ios::in | ios::out | ios::binary);
299 ASSERT_TRUE(file.is_open());
300 file.seekp(0, ios_base::beg);
301 file.write(REPLACE_FILE_HEADER.c_str(), REPLACE_FILE_HEADER.size());
302 file.close();
303 // Unpack file.
304 FileInfo fileInfo;
305 errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_unpackResultPath, fileInfo);
306 ASSERT_EQ(errCode, -E_INVALID_FILE);
307 return;
308 }
309
310 /**
311 * @tc.name: PackageFileTest008
312 * @tc.desc: Test file unpack if checksum check failed.
313 * @tc.type: FUNC
314 * @tc.require: AR000D4879
315 * @tc.author: liujialei
316 */
317 HWTEST_F(DistributedDBFilePackageTest, PackageFileTest008, TestSize.Level1)
318 {
319 int errCode = PackageFile::PackageFiles(g_sourcePath, g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_fileInfo);
320 ASSERT_EQ(errCode, E_OK);
321 // Rewrite package file without file tail.
322 ifstream fileIn(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, ios::in | ios::binary);
323 ASSERT_TRUE(fileIn.is_open());
324 fileIn.seekg(0, ios_base::end);
325 int fileLen = fileIn.tellg();
326 fileIn.seekg(0, ios_base::beg);
327 const int CUT_TAIL = 3;
328 int bufferLen = fileLen > BUFFER_SIZE ? BUFFER_SIZE : fileLen - CUT_TAIL;
329 vector<char> buffer(bufferLen, 0);
330 fileIn.read(buffer.data(), buffer.size());
331 fileIn.close();
332 ofstream fileOut(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, ios::out | ios::binary | ios::trunc);
333 ASSERT_TRUE(fileOut.is_open());
334 fileOut.write(buffer.data(), buffer.size());
335 fileOut.close();
336 // Unpack file.
337 FileInfo fileInfo;
338 errCode = PackageFile::UnpackFile(g_packageResultPath + PACKAGE_RESULT_FILE_NAME, g_unpackResultPath, fileInfo);
339 ASSERT_EQ(errCode, -E_INVALID_FILE);
340 return;
341 }
342
343