• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 <filesystem>
18 #include <fstream>
19 #include <new>
20 #include <string>
21 
22 #include <errno.h>
23 
24 #include <android-base/file.h>
25 #include <android-base/result.h>
26 #include <android-base/stringprintf.h>
27 #include <android-base/strings.h>
28 #include <gtest/gtest.h>
29 
30 #include "apexd.h"
31 #include "apexd_test_utils.h"
32 #include "apexd_utils.h"
33 
34 namespace android {
35 namespace apex {
36 namespace {
37 
38 namespace fs = std::filesystem;
39 
40 using android::apex::testing::IsOk;
41 using android::base::Basename;
42 using android::base::Join;
43 using android::base::StringPrintf;
44 using ::testing::UnorderedElementsAre;
45 using ::testing::UnorderedElementsAreArray;
46 
47 // TODO(b/170327382): add unit tests for apexd_utils.h
48 
49 TEST(ApexdUtilTest, DeleteDirContent) {
50   TemporaryDir root_dir;
51   TemporaryFile child_file_1(root_dir.path);
52   TemporaryFile child_file_2(root_dir.path);
53   std::string child_dir = StringPrintf("%s/child-dir", root_dir.path);
54   CreateDirIfNeeded(child_dir, 0755);
55   TemporaryFile nested_file(child_dir);
56 
57   auto content = ReadDir(root_dir.path, [](auto _) { return true; });
58   IsOk(content);
59   ASSERT_EQ(content->size(), 3u);
60 
61   auto del_result = DeleteDirContent(root_dir.path);
62   IsOk(del_result);
63   content = ReadDir(root_dir.path, [](auto _) { return true; });
64   IsOk(content);
65   ASSERT_EQ(content->size(), 0u);
66 }
67 
68 TEST(ApexdUtilTest, FindFirstExistingDirectoryBothExist) {
69   TemporaryDir first_dir;
70   TemporaryDir second_dir;
71   auto result = FindFirstExistingDirectory(first_dir.path, second_dir.path);
72   ASSERT_TRUE(IsOk(result));
73   ASSERT_EQ(*result, first_dir.path);
74 }
75 
76 TEST(ApexdUtilTest, FindFirstExistingDirectoryOnlyFirstExist) {
77   TemporaryDir first_dir;
78   auto second_dir = "/data/local/tmp/does/not/exist";
79   auto result = FindFirstExistingDirectory(first_dir.path, second_dir);
80   ASSERT_TRUE(IsOk(result));
81   ASSERT_EQ(*result, first_dir.path);
82 }
83 
84 TEST(ApexdUtilTest, FindFirstExistingDirectoryOnlySecondExist) {
85   auto first_dir = "/data/local/tmp/does/not/exist";
86   TemporaryDir second_dir;
87   auto result = FindFirstExistingDirectory(first_dir, second_dir.path);
88   ASSERT_TRUE(IsOk(result));
89   ASSERT_EQ(*result, second_dir.path);
90 }
91 
92 TEST(ApexdUtilTest, FindFirstExistingDirectoryNoneExist) {
93   auto first_dir = "/data/local/tmp/does/not/exist";
94   auto second_dir = "/data/local/tmp/also/does/not/exist";
95   auto result = FindFirstExistingDirectory(first_dir, second_dir);
96   ASSERT_FALSE(IsOk(result));
97 }
98 
99 TEST(ApexdUtilTest, FindFirstExistingDirectoryFirstFileSecondDir) {
100   TemporaryFile first_file;
101   TemporaryDir second_dir;
102   auto result = FindFirstExistingDirectory(first_file.path, second_dir.path);
103   ASSERT_TRUE(IsOk(result));
104   ASSERT_EQ(*result, second_dir.path);
105 }
106 
107 TEST(ApexdUtilTest, FindFirstExistingDirectoryFirstDirSecondFile) {
108   TemporaryDir first_dir;
109   TemporaryFile second_file;
110   auto result = FindFirstExistingDirectory(first_dir.path, second_file.path);
111   ASSERT_TRUE(IsOk(result));
112   ASSERT_EQ(*result, first_dir.path);
113 }
114 
115 TEST(ApexdUtilTest, FindFirstExistingDirectoryBothFiles) {
116   TemporaryFile first_file;
117   TemporaryFile second_file;
118   auto result = FindFirstExistingDirectory(first_file.path, second_file.path);
119   ASSERT_FALSE(IsOk(result));
120 }
121 
122 TEST(ApexdUtilTest, FindFirstExistingDirectoryFirstFileSecondDoesNotExist) {
123   TemporaryFile first_file;
124   auto second_dir = "/data/local/tmp/does/not/exist";
125   auto result = FindFirstExistingDirectory(first_file.path, second_dir);
126   ASSERT_FALSE(IsOk(result));
127 }
128 
129 TEST(ApexdUtilTest, FindFirstExistingDirectoryFirsDoesNotExistSecondFile) {
130   auto first_dir = "/data/local/tmp/does/not/exist";
131   TemporaryFile second_file;
132   auto result = FindFirstExistingDirectory(first_dir, second_file.path);
133   ASSERT_FALSE(IsOk(result));
134 }
135 
136 TEST(ApexdUtilTest, MoveDir) {
137   TemporaryDir from;
138   TemporaryDir to;
139 
140   TemporaryFile from_1(from.path);
141   auto from_subdir = StringPrintf("%s/subdir", from.path);
142   if (mkdir(from_subdir.c_str(), 07000) != 0) {
143     FAIL() << "Failed to mkdir " << from_subdir << " : " << strerror(errno);
144   }
145   TemporaryFile from_2(from_subdir);
146 
147   auto result = MoveDir(from.path, to.path);
148   ASSERT_TRUE(IsOk(result));
149   ASSERT_TRUE(fs::is_empty(from.path));
150 
151   std::vector<std::string> content;
152   for (const auto& it : fs::recursive_directory_iterator(to.path)) {
153     content.push_back(it.path());
154   }
155 
156   static const std::vector<std::string> expected = {
157       StringPrintf("%s/%s", to.path, Basename(from_1.path).c_str()),
158       StringPrintf("%s/subdir", to.path),
159       StringPrintf("%s/subdir/%s", to.path, Basename(from_2.path).c_str()),
160   };
161   ASSERT_THAT(content, UnorderedElementsAreArray(expected));
162 }
163 
164 TEST(ApexdUtilTest, MoveDirFromIsNotDirectory) {
165   TemporaryFile from;
166   TemporaryDir to;
167   ASSERT_FALSE(IsOk(MoveDir(from.path, to.path)));
168 }
169 
170 TEST(ApexdUtilTest, MoveDirToIsNotDirectory) {
171   TemporaryDir from;
172   TemporaryFile to;
173   TemporaryFile from_1(from.path);
174   ASSERT_FALSE(IsOk(MoveDir(from.path, to.path)));
175 }
176 
177 TEST(ApexdUtilTest, MoveDirFromDoesNotExist) {
178   TemporaryDir to;
179   ASSERT_FALSE(IsOk(MoveDir("/data/local/tmp/does/not/exist", to.path)));
180 }
181 
182 TEST(ApexdUtilTest, MoveDirToDoesNotExist) {
183   namespace fs = std::filesystem;
184 
185   TemporaryDir from;
186   TemporaryFile from_1(from.path);
187   auto from_subdir = StringPrintf("%s/subdir", from.path);
188   if (mkdir(from_subdir.c_str(), 07000) != 0) {
189     FAIL() << "Failed to mkdir " << from_subdir << " : " << strerror(errno);
190   }
191   TemporaryFile from_2(from_subdir);
192 
193   ASSERT_FALSE(IsOk(MoveDir(from.path, "/data/local/tmp/does/not/exist")));
194 
195   // Check that |from| directory is not empty.
196   std::vector<std::string> content;
197   for (const auto& it : fs::recursive_directory_iterator(from.path)) {
198     content.push_back(it.path());
199   }
200 
201   ASSERT_THAT(content,
202               UnorderedElementsAre(from_1.path, from_subdir, from_2.path));
203 }
204 
205 TEST(ApexdUtilTest, FindFilesBySuffix) {
206   TemporaryDir td;
207 
208   // create files with different suffix
209   const std::string first_filename = StringPrintf("%s/first.a", td.path);
210   const std::string second_filename = StringPrintf("%s/second.b", td.path);
211   const std::string third_filename = StringPrintf("%s/third.c", td.path);
212   const std::string fourth_filename = StringPrintf("%s/fourth.c", td.path);
213 
214   std::ofstream first_file(first_filename);
215   std::ofstream second_file(second_filename);
216   std::ofstream third_file(third_filename);
217   std::ofstream fourth_file(fourth_filename);
218 
219   auto result = FindFilesBySuffix(td.path, {".b", ".c"});
220   ASSERT_TRUE(IsOk(result));
221   ASSERT_THAT(*result, UnorderedElementsAre(second_filename, third_filename,
222                                             fourth_filename));
223 }
224 
225 TEST(ApexdTestUtilsTest, MountNamespaceRestorer) {
226   auto original_namespace = GetCurrentMountNamespace();
227   ASSERT_RESULT_OK(original_namespace);
228   {
229     MountNamespaceRestorer restorer;
230     // Switch to new mount namespace.
231     ASSERT_NE(-1, unshare(CLONE_NEWNS));
232     auto current_namespace = GetCurrentMountNamespace();
233     ASSERT_RESULT_OK(current_namespace);
234     ASSERT_NE(original_namespace, current_namespace);
235   }
236   // Check that we switched back to the original namespace upon exiting the
237   // scope.
238   auto current_namespace = GetCurrentMountNamespace();
239   ASSERT_RESULT_OK(current_namespace);
240   ASSERT_EQ(*original_namespace, *current_namespace);
241 }
242 
243 TEST(ApexdTestUtilsTest, SetUpApexTestEnvironment) {
244   auto original_apex_mounts = GetApexMounts();
245   ASSERT_GT(original_apex_mounts.size(), 0u);
246   auto original_dir_content = ReadDir("/apex", [](auto _) { return true; });
247   ASSERT_TRUE(IsOk(original_dir_content));
248   {
249     MountNamespaceRestorer restorer;
250     ASSERT_TRUE(IsOk(SetUpApexTestEnvironment()));
251     // Check /apex is apex_mnt_dir.
252     char* context;
253     ASSERT_GT(getfilecon("/apex", &context), 0);
254     EXPECT_EQ(std::string(context), "u:object_r:apex_mnt_dir:s0");
255     freecon(context);
256     // Check no apexes are mounted in our test environment.
257     auto new_apex_mounts = GetApexMounts();
258     ASSERT_EQ(new_apex_mounts.size(), 0u);
259     // Check that /apex is empty.
260     auto dir_content = ReadDir("/apex", [](auto _) { return true; });
261     ASSERT_TRUE(IsOk(dir_content));
262     ASSERT_EQ(dir_content->size(), 0u)
263         << "Found following entries: " << Join(*dir_content, ',');
264     // Check that we can still access /data.
265     std::string test_dir = android::base::GetExecutableDirectory();
266     ASSERT_TRUE(android::base::StartsWith(test_dir, "/data"));
267     TemporaryFile tf(test_dir);
268     // Check that we can write.
269     ASSERT_TRUE(android::base::WriteStringToFile("secret", tf.path));
270     // And check that we can still read it
271     std::string content;
272     ASSERT_TRUE(android::base::ReadFileToString(tf.path, &content));
273     ASSERT_EQ(content, "secret");
274   }
275   auto apex_mounts = GetApexMounts();
276   ASSERT_THAT(apex_mounts, UnorderedElementsAreArray(original_apex_mounts));
277   auto apex_dir_content = ReadDir("/apex", [](auto _) { return true; });
278   ASSERT_TRUE(IsOk(apex_dir_content));
279   ASSERT_EQ(apex_dir_content->size(), original_dir_content->size());
280 }
281 
282 }  // namespace
283 }  // namespace apex
284 }  // namespace android
285