xref: /aosp_15_r20/frameworks/native/cmds/installd/tests/installd_file_test.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <android-base/stringprintf.h>
20 #include <gtest/gtest.h>
21 #include <log/log.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "restorable_file.h"
26 #include "unique_file.h"
27 #include "utils.h"
28 
29 #undef LOG_TAG
30 #define LOG_TAG "installd_file_test"
31 
32 namespace {
33 
34 constexpr char kFileTestDir[] = "/data/local/tmp/installd_file_test_data";
35 constexpr char kTmpFileSuffix[] = ".tmp";
36 constexpr char kBackupFileSuffix[] = ".backup";
37 
UnlinkWithAssert(const std::string & path)38 void UnlinkWithAssert(const std::string& path) {
39     ASSERT_EQ(0, unlink(path.c_str()));
40 }
41 
42 } // namespace
43 
44 namespace android {
45 namespace installd {
46 
47 // Add these as macros as functions make it hard to tell where the failure has happened.
48 #define ASSERT_FILE_NOT_EXISTING(path)           \
49     {                                            \
50         struct stat st;                          \
51         ASSERT_NE(0, ::stat(path.c_str(), &st)); \
52     }
53 #define ASSERT_FILE_EXISTING(path)               \
54     {                                            \
55         struct stat st;                          \
56         ASSERT_EQ(0, ::stat(path.c_str(), &st)); \
57     }
58 #define ASSERT_FILE_CONTENT(path, expectedContent) ASSERT_EQ(expectedContent, ReadTestFile(path))
59 #define ASSERT_FILE_OPEN(path, fd)       \
60     {                                    \
61         fd = open(path.c_str(), O_RDWR); \
62         ASSERT_TRUE(fd >= 0);            \
63     }
64 #define ASSERT_WRITE_TO_FD(fd, content) \
65     ASSERT_TRUE(android::base::WriteStringToFd(content, android::base::borrowed_fd(fd)))
66 
67 class FileTest : public testing::Test {
68 protected:
SetUp()69     virtual void SetUp() {
70         setenv("ANDROID_LOG_TAGS", "*:v", 1);
71         android::base::InitLogging(nullptr);
72 
73         ASSERT_EQ(0, create_dir_if_needed(kFileTestDir, 0777));
74     }
75 
TearDown()76     virtual void TearDown() {
77         system(android::base::StringPrintf("rm -rf %s", kFileTestDir).c_str());
78     }
79 
GetTestFilePath(const std::string & fileName)80     std::string GetTestFilePath(const std::string& fileName) {
81         return android::base::StringPrintf("%s/%s", kFileTestDir, fileName.c_str());
82     }
83 
CreateTestFileWithContents(const std::string & path,const std::string & content)84     void CreateTestFileWithContents(const std::string& path, const std::string& content) {
85         ALOGI("CreateTestFileWithContents:%s", path.c_str());
86         ASSERT_TRUE(android::base::WriteStringToFile(content, path));
87     }
88 
GetTestName()89     std::string GetTestName() {
90         std::string name(testing::UnitTest::GetInstance()->current_test_info()->name());
91         return name;
92     }
93 
ReadTestFile(const std::string & path)94     std::string ReadTestFile(const std::string& path) {
95         std::string content;
96         bool r = android::base::ReadFileToString(path, &content);
97         if (!r) {
98             PLOG(ERROR) << "Cannot read file:" << path;
99         }
100         return content;
101     }
102 };
103 
TEST_F(FileTest,TestUniqueFileMoveConstruction)104 TEST_F(FileTest, TestUniqueFileMoveConstruction) {
105     const int fd = 101;
106     std::string testFile = GetTestFilePath(GetTestName());
107     UniqueFile uf1(fd, testFile);
108     uf1.DisableAutoClose();
109 
110     UniqueFile uf2(std::move(uf1));
111 
112     ASSERT_EQ(fd, uf2.fd());
113     ASSERT_EQ(testFile, uf2.path());
114 }
115 
TEST_F(FileTest,TestUniqueFileAssignment)116 TEST_F(FileTest, TestUniqueFileAssignment) {
117     const int fd1 = 101;
118     const int fd2 = 102;
119     std::string testFile1 = GetTestFilePath(GetTestName());
120     std::string testFile2 = GetTestFilePath(GetTestName() + "2");
121 
122     UniqueFile uf1(fd1, testFile1);
123     uf1.DisableAutoClose();
124 
125     UniqueFile uf2(fd2, testFile2);
126     uf2.DisableAutoClose();
127 
128     ASSERT_EQ(fd2, uf2.fd());
129     ASSERT_EQ(testFile2, uf2.path());
130 
131     uf2 = std::move(uf1);
132 
133     ASSERT_EQ(fd1, uf2.fd());
134     ASSERT_EQ(testFile1, uf2.path());
135 }
136 
TEST_F(FileTest,TestUniqueFileCleanup)137 TEST_F(FileTest, TestUniqueFileCleanup) {
138     std::string testFile = GetTestFilePath(GetTestName());
139     CreateTestFileWithContents(testFile, "OriginalContent");
140 
141     int fd;
142     ASSERT_FILE_OPEN(testFile, fd);
143 
144     { UniqueFile uf = UniqueFile(fd, testFile, UnlinkWithAssert); }
145 
146     ASSERT_FILE_NOT_EXISTING(testFile);
147 }
148 
TEST_F(FileTest,TestUniqueFileNoCleanup)149 TEST_F(FileTest, TestUniqueFileNoCleanup) {
150     std::string testFile = GetTestFilePath(GetTestName());
151     CreateTestFileWithContents(testFile, "OriginalContent");
152 
153     int fd;
154     ASSERT_FILE_OPEN(testFile, fd);
155 
156     {
157         UniqueFile uf = UniqueFile(fd, testFile, UnlinkWithAssert);
158         uf.DisableCleanup();
159     }
160 
161     ASSERT_FILE_CONTENT(testFile, "OriginalContent");
162 }
163 
TEST_F(FileTest,TestUniqueFileFd)164 TEST_F(FileTest, TestUniqueFileFd) {
165     std::string testFile = GetTestFilePath(GetTestName());
166     CreateTestFileWithContents(testFile, "OriginalContent");
167 
168     int fd;
169     ASSERT_FILE_OPEN(testFile, fd);
170 
171     UniqueFile uf(fd, testFile, UnlinkWithAssert);
172 
173     ASSERT_EQ(fd, uf.fd());
174 
175     uf.reset();
176 
177     ASSERT_EQ(-1, uf.fd());
178 }
179 
TEST_F(FileTest,TestRestorableFileMoveConstruction)180 TEST_F(FileTest, TestRestorableFileMoveConstruction) {
181     std::string testFile = GetTestFilePath(GetTestName());
182 
183     RestorableFile rf1 = RestorableFile::CreateWritableFile(testFile, 0600);
184     int fd = rf1.fd();
185 
186     RestorableFile rf2(std::move(rf1));
187 
188     ASSERT_EQ(fd, rf2.fd());
189     ASSERT_EQ(testFile, rf2.path());
190 }
191 
TEST_F(FileTest,TestRestorableFileAssignment)192 TEST_F(FileTest, TestRestorableFileAssignment) {
193     std::string testFile1 = GetTestFilePath(GetTestName());
194     std::string testFile2 = GetTestFilePath(GetTestName() + "2");
195 
196     RestorableFile rf1 = RestorableFile::CreateWritableFile(testFile1, 0600);
197     int fd1 = rf1.fd();
198 
199     RestorableFile rf2 = RestorableFile::CreateWritableFile(testFile2, 0600);
200     int fd2 = rf2.fd();
201 
202     ASSERT_EQ(fd2, rf2.fd());
203     ASSERT_EQ(testFile2, rf2.path());
204 
205     rf2 = std::move(rf1);
206 
207     ASSERT_EQ(fd1, rf2.fd());
208     ASSERT_EQ(testFile1, rf2.path());
209 }
210 
TEST_F(FileTest,TestRestorableFileVerifyUniqueFileWithReset)211 TEST_F(FileTest, TestRestorableFileVerifyUniqueFileWithReset) {
212     std::string testFile = GetTestFilePath(GetTestName());
213     std::string tmpFile = testFile + kTmpFileSuffix;
214 
215     {
216         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
217 
218         ASSERT_FILE_EXISTING(tmpFile);
219 
220         const UniqueFile& uf = rf.GetUniqueFile();
221 
222         ASSERT_EQ(rf.fd(), uf.fd());
223         ASSERT_EQ(rf.path(), uf.path());
224 
225         rf.reset();
226 
227         ASSERT_EQ(rf.fd(), uf.fd());
228         ASSERT_EQ(rf.path(), uf.path());
229         ASSERT_EQ(-1, rf.fd());
230         ASSERT_TRUE(rf.path().empty());
231     }
232 }
233 
TEST_F(FileTest,TestRestorableFileVerifyUniqueFileWithCommit)234 TEST_F(FileTest, TestRestorableFileVerifyUniqueFileWithCommit) {
235     std::string testFile = GetTestFilePath(GetTestName());
236     std::string tmpFile = testFile + kTmpFileSuffix;
237     std::string backupFile = testFile + kBackupFileSuffix;
238 
239     {
240         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
241 
242         ASSERT_FILE_EXISTING(tmpFile);
243 
244         const UniqueFile& uf = rf.GetUniqueFile();
245 
246         ASSERT_EQ(rf.fd(), uf.fd());
247         ASSERT_EQ(rf.path(), uf.path());
248 
249         ASSERT_TRUE(rf.CreateBackupFile());
250 
251         ASSERT_FILE_NOT_EXISTING(backupFile);
252 
253         rf.CommitWorkFile();
254 
255         ASSERT_EQ(rf.fd(), uf.fd());
256         ASSERT_EQ(rf.path(), uf.path());
257         ASSERT_EQ(-1, rf.fd());
258         ASSERT_EQ(testFile, rf.path());
259     }
260 }
261 
TEST_F(FileTest,TestRestorableFileNewFileNotCommitted)262 TEST_F(FileTest, TestRestorableFileNewFileNotCommitted) {
263     std::string testFile = GetTestFilePath(GetTestName());
264     std::string tmpFile = testFile + kTmpFileSuffix;
265 
266     {
267         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
268 
269         ASSERT_FILE_EXISTING(tmpFile);
270         ASSERT_FILE_NOT_EXISTING(testFile);
271 
272         ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
273 
274         ASSERT_FILE_CONTENT(tmpFile, "NewContent");
275     }
276 
277     ASSERT_FILE_NOT_EXISTING(tmpFile);
278     ASSERT_FILE_NOT_EXISTING(testFile);
279 }
280 
TEST_F(FileTest,TestRestorableFileNotCommittedWithOriginal)281 TEST_F(FileTest, TestRestorableFileNotCommittedWithOriginal) {
282     std::string testFile = GetTestFilePath(GetTestName());
283     std::string tmpFile = testFile + kTmpFileSuffix;
284     CreateTestFileWithContents(testFile, "OriginalContent");
285 
286     {
287         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
288         ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
289 
290         ASSERT_FILE_CONTENT(tmpFile, "NewContent");
291         ASSERT_FILE_EXISTING(testFile);
292     }
293 
294     ASSERT_FILE_NOT_EXISTING(tmpFile);
295     ASSERT_FILE_CONTENT(testFile, "OriginalContent");
296 }
297 
TEST_F(FileTest,TestRestorableFileNotCommittedWithOriginalAndOldTmp)298 TEST_F(FileTest, TestRestorableFileNotCommittedWithOriginalAndOldTmp) {
299     std::string testFile = GetTestFilePath(GetTestName());
300     std::string tmpFile = testFile + kTmpFileSuffix;
301     CreateTestFileWithContents(testFile, "OriginalContent");
302     CreateTestFileWithContents(testFile + kTmpFileSuffix, "OldTmp");
303 
304     {
305         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
306         ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
307 
308         ASSERT_FILE_CONTENT(tmpFile, "NewContent");
309         ASSERT_FILE_EXISTING(testFile);
310     }
311 
312     ASSERT_FILE_NOT_EXISTING(tmpFile);
313     ASSERT_FILE_CONTENT(testFile, "OriginalContent");
314 }
315 
TEST_F(FileTest,TestRestorableFileNewFileCommitted)316 TEST_F(FileTest, TestRestorableFileNewFileCommitted) {
317     std::string testFile = GetTestFilePath(GetTestName());
318     std::string tmpFile = testFile + kTmpFileSuffix;
319     std::string backupFile = testFile + kBackupFileSuffix;
320 
321     {
322         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
323 
324         ASSERT_FILE_EXISTING(tmpFile);
325         ASSERT_FILE_NOT_EXISTING(testFile);
326 
327         ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
328         ASSERT_FILE_CONTENT(tmpFile, "NewContent");
329 
330         ASSERT_TRUE(rf.CreateBackupFile());
331 
332         ASSERT_FILE_NOT_EXISTING(backupFile);
333 
334         ASSERT_TRUE(rf.CommitWorkFile());
335         rf.RemoveBackupFile();
336 
337         ASSERT_FILE_CONTENT(testFile, "NewContent");
338     }
339 
340     ASSERT_FILE_NOT_EXISTING(tmpFile);
341     ASSERT_FILE_NOT_EXISTING(backupFile);
342     ASSERT_FILE_CONTENT(testFile, "NewContent");
343 }
344 
TEST_F(FileTest,TestRestorableFileCommittedWithOriginal)345 TEST_F(FileTest, TestRestorableFileCommittedWithOriginal) {
346     std::string testFile = GetTestFilePath(GetTestName());
347     std::string tmpFile = testFile + kTmpFileSuffix;
348     std::string backupFile = testFile + kBackupFileSuffix;
349     CreateTestFileWithContents(testFile, "OriginalContent");
350 
351     {
352         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
353         ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
354         ASSERT_FILE_CONTENT(tmpFile, "NewContent");
355 
356         ASSERT_TRUE(rf.CreateBackupFile());
357 
358         ASSERT_FILE_NOT_EXISTING(testFile);
359         ASSERT_FILE_EXISTING(backupFile);
360 
361         ASSERT_TRUE(rf.CommitWorkFile());
362 
363         ASSERT_FILE_EXISTING(backupFile);
364         ASSERT_FILE_CONTENT(testFile, "NewContent");
365 
366         rf.RemoveBackupFile();
367 
368         ASSERT_FILE_NOT_EXISTING(backupFile);
369     }
370 
371     ASSERT_FILE_NOT_EXISTING(tmpFile);
372     ASSERT_FILE_CONTENT(testFile, "NewContent");
373 }
374 
TEST_F(FileTest,TestRestorableFileCommittedWithOriginalAndOldTmp)375 TEST_F(FileTest, TestRestorableFileCommittedWithOriginalAndOldTmp) {
376     std::string testFile = GetTestFilePath(GetTestName());
377     std::string tmpFile = testFile + kTmpFileSuffix;
378     CreateTestFileWithContents(testFile, "OriginalContent");
379     CreateTestFileWithContents(testFile + kTmpFileSuffix, "OldTmp");
380 
381     {
382         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
383         ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
384         ASSERT_FILE_CONTENT(tmpFile, "NewContent");
385 
386         ASSERT_TRUE(rf.CommitWorkFile());
387 
388         ASSERT_FILE_CONTENT(testFile, "NewContent");
389     }
390 
391     ASSERT_FILE_NOT_EXISTING(tmpFile);
392     ASSERT_FILE_CONTENT(testFile, "NewContent");
393 }
394 
TEST_F(FileTest,TestRestorableFileCommitFailureNoOriginal)395 TEST_F(FileTest, TestRestorableFileCommitFailureNoOriginal) {
396     std::string testFile = GetTestFilePath(GetTestName());
397     std::string tmpFile = testFile + kTmpFileSuffix;
398     std::string backupFile = testFile + kBackupFileSuffix;
399 
400     {
401         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
402         ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
403 
404         ASSERT_TRUE(rf.CreateBackupFile());
405 
406         ASSERT_FILE_NOT_EXISTING(testFile);
407         ASSERT_FILE_NOT_EXISTING(backupFile);
408 
409         // Now remove tmp file to force commit failure.
410         close(rf.fd());
411         ASSERT_EQ(0, unlink(tmpFile.c_str()));
412         ASSERT_FILE_NOT_EXISTING(tmpFile);
413 
414         ASSERT_FALSE(rf.CommitWorkFile());
415 
416         ASSERT_EQ(-1, rf.fd());
417         ASSERT_EQ(testFile, rf.path());
418         ASSERT_FILE_NOT_EXISTING(testFile);
419         ASSERT_FILE_NOT_EXISTING(tmpFile);
420 
421         ASSERT_TRUE(rf.RestoreBackupFile());
422     }
423 
424     ASSERT_FILE_NOT_EXISTING(testFile);
425     ASSERT_FILE_NOT_EXISTING(tmpFile);
426     ASSERT_FILE_NOT_EXISTING(backupFile);
427 }
428 
TEST_F(FileTest,TestRestorableFileCommitFailureAndRollback)429 TEST_F(FileTest, TestRestorableFileCommitFailureAndRollback) {
430     std::string testFile = GetTestFilePath(GetTestName());
431     std::string tmpFile = testFile + kTmpFileSuffix;
432     std::string backupFile = testFile + kBackupFileSuffix;
433     CreateTestFileWithContents(testFile, "OriginalContent");
434 
435     {
436         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
437         ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
438 
439         ASSERT_TRUE(rf.CreateBackupFile());
440 
441         ASSERT_FILE_NOT_EXISTING(testFile);
442         ASSERT_FILE_EXISTING(backupFile);
443 
444         // Now remove tmp file to force commit failure.
445         close(rf.fd());
446         ASSERT_EQ(0, unlink(tmpFile.c_str()));
447         ASSERT_FILE_NOT_EXISTING(tmpFile);
448 
449         ASSERT_FALSE(rf.CommitWorkFile());
450 
451         ASSERT_EQ(-1, rf.fd());
452         ASSERT_EQ(testFile, rf.path());
453         ASSERT_FILE_NOT_EXISTING(testFile);
454         ASSERT_FILE_NOT_EXISTING(tmpFile);
455         ASSERT_FILE_EXISTING(backupFile);
456 
457         ASSERT_TRUE(rf.RestoreBackupFile());
458     }
459 
460     ASSERT_FILE_EXISTING(testFile);
461     ASSERT_FILE_NOT_EXISTING(tmpFile);
462     ASSERT_FILE_NOT_EXISTING(backupFile);
463 }
464 
TEST_F(FileTest,TestRestorableFileResetAndRemoveAllFiles)465 TEST_F(FileTest, TestRestorableFileResetAndRemoveAllFiles) {
466     std::string testFile = GetTestFilePath(GetTestName());
467     std::string tmpFile = testFile + kTmpFileSuffix;
468     std::string backupFile = testFile + kBackupFileSuffix;
469     CreateTestFileWithContents(testFile, "OriginalContent");
470 
471     {
472         RestorableFile rf = RestorableFile::CreateWritableFile(testFile, 0600);
473         ASSERT_WRITE_TO_FD(rf.fd(), "NewContent");
474 
475         ASSERT_TRUE(rf.CreateBackupFile());
476 
477         ASSERT_FILE_NOT_EXISTING(testFile);
478         ASSERT_FILE_EXISTING(backupFile);
479 
480         rf.ResetAndRemoveAllFiles();
481 
482         ASSERT_EQ(-1, rf.fd());
483         ASSERT_FILE_NOT_EXISTING(tmpFile);
484         ASSERT_FILE_NOT_EXISTING(testFile);
485         ASSERT_FILE_NOT_EXISTING(backupFile);
486     }
487 
488     ASSERT_FILE_NOT_EXISTING(tmpFile);
489     ASSERT_FILE_NOT_EXISTING(testFile);
490     ASSERT_FILE_NOT_EXISTING(backupFile);
491 }
492 
TEST_F(FileTest,TestRestorableFileRemoveFileAndTmpFileWithContentFile)493 TEST_F(FileTest, TestRestorableFileRemoveFileAndTmpFileWithContentFile) {
494     std::string testFile = GetTestFilePath(GetTestName());
495     std::string tmpFile = testFile + kTmpFileSuffix;
496     std::string backupFile = testFile + kBackupFileSuffix;
497     CreateTestFileWithContents(testFile, "OriginalContent");
498 
499     RestorableFile::RemoveAllFiles(testFile);
500 
501     ASSERT_FILE_NOT_EXISTING(tmpFile);
502     ASSERT_FILE_NOT_EXISTING(testFile);
503     ASSERT_FILE_NOT_EXISTING(backupFile);
504 }
505 
TEST_F(FileTest,TestRestorableFileRemoveFileAndTmpFileWithContentAndTmpFile)506 TEST_F(FileTest, TestRestorableFileRemoveFileAndTmpFileWithContentAndTmpFile) {
507     std::string testFile = GetTestFilePath(GetTestName());
508     std::string tmpFile = testFile + kTmpFileSuffix;
509     std::string backupFile = testFile + kBackupFileSuffix;
510     CreateTestFileWithContents(testFile, "OriginalContent");
511     CreateTestFileWithContents(testFile + kTmpFileSuffix, "TmpContent");
512 
513     RestorableFile::RemoveAllFiles(testFile);
514 
515     ASSERT_FILE_NOT_EXISTING(tmpFile);
516     ASSERT_FILE_NOT_EXISTING(testFile);
517     ASSERT_FILE_NOT_EXISTING(backupFile);
518 }
519 
520 } // namespace installd
521 } // namespace android
522