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 "apexd_session.h"
18
19 #include <android-base/file.h>
20 #include <android-base/result-gmock.h>
21 #include <android-base/result.h>
22 #include <android-base/scopeguard.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25 #include <errno.h>
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28
29 #include <algorithm>
30 #include <filesystem>
31 #include <fstream>
32 #include <string>
33
34 #include "apexd_test_utils.h"
35 #include "apexd_utils.h"
36 #include "session_state.pb.h"
37
38 namespace android {
39 namespace apex {
40 namespace {
41
42 using android::base::Join;
43 using android::base::make_scope_guard;
44 using android::base::testing::Ok;
45 using ::apex::proto::SessionState;
46 using ::testing::Not;
47 using ::testing::UnorderedElementsAre;
48
49 // TODO(b/170329726): add unit tests for apexd_sessions.h
50
TEST(ApexdSessionTest,GetSessionsDirSessionsStoredInMetadata)51 TEST(ApexdSessionTest, GetSessionsDirSessionsStoredInMetadata) {
52 if (access("/metadata", F_OK) != 0) {
53 GTEST_SKIP() << "Device doesn't have /metadata partition";
54 }
55
56 std::string result = GetSessionsDir();
57 ASSERT_EQ(result, "/metadata/apex/sessions");
58 }
59
TEST(ApexdSessionTest,GetSessionsDirNoMetadataPartitionFallbackToData)60 TEST(ApexdSessionTest, GetSessionsDirNoMetadataPartitionFallbackToData) {
61 if (access("/metadata", F_OK) == 0) {
62 GTEST_SKIP() << "Device has /metadata partition";
63 }
64
65 std::string result = GetSessionsDir();
66 ASSERT_EQ(result, "/data/apex/sessions");
67 }
68
TEST(ApexSessionManagerTest,CreateSession)69 TEST(ApexSessionManagerTest, CreateSession) {
70 TemporaryDir td;
71 auto manager = ApexSessionManager::Create(std::string(td.path));
72
73 auto session = manager->CreateSession(239);
74 ASSERT_RESULT_OK(session);
75 ASSERT_EQ(239, session->GetId());
76 std::string session_dir = std::string(td.path) + "/239";
77 ASSERT_EQ(session_dir, session->GetSessionDir());
78 }
79
TEST(ApexSessionManagerTest,GetSessionsNoSessionReturnsError)80 TEST(ApexSessionManagerTest, GetSessionsNoSessionReturnsError) {
81 TemporaryDir td;
82 auto manager = ApexSessionManager::Create(std::string(td.path));
83
84 ASSERT_THAT(manager->GetSession(37), Not(Ok()));
85 }
86
TEST(ApexSessionManagerTest,GetSessionsReturnsErrorSessionNotCommitted)87 TEST(ApexSessionManagerTest, GetSessionsReturnsErrorSessionNotCommitted) {
88 TemporaryDir td;
89 auto manager = ApexSessionManager::Create(std::string(td.path));
90
91 auto session = manager->CreateSession(73);
92 ASSERT_RESULT_OK(session);
93 ASSERT_THAT(manager->GetSession(73), Not(Ok()));
94 }
95
TEST(ApexSessionManagerTest,CreateCommitGetSession)96 TEST(ApexSessionManagerTest, CreateCommitGetSession) {
97 TemporaryDir td;
98 auto manager = ApexSessionManager::Create(std::string(td.path));
99
100 auto session = manager->CreateSession(23);
101 ASSERT_RESULT_OK(session);
102 session->SetErrorMessage("error");
103 ASSERT_RESULT_OK(session->UpdateStateAndCommit(SessionState::STAGED));
104
105 auto same_session = manager->GetSession(23);
106 ASSERT_RESULT_OK(same_session);
107 ASSERT_EQ(23, same_session->GetId());
108 ASSERT_EQ("error", same_session->GetErrorMessage());
109 ASSERT_EQ(SessionState::STAGED, same_session->GetState());
110 }
111
TEST(ApexSessionManagerTest,GetSessionsNoSessionsCommitted)112 TEST(ApexSessionManagerTest, GetSessionsNoSessionsCommitted) {
113 TemporaryDir td;
114 auto manager = ApexSessionManager::Create(std::string(td.path));
115
116 ASSERT_RESULT_OK(manager->CreateSession(3));
117
118 auto sessions = manager->GetSessions();
119 ASSERT_EQ(0u, sessions.size());
120 }
121
TEST(ApexSessionManager,GetSessionsCommittedSessions)122 TEST(ApexSessionManager, GetSessionsCommittedSessions) {
123 TemporaryDir td;
124 auto manager = ApexSessionManager::Create(std::string(td.path));
125
126 auto session1 = manager->CreateSession(1543);
127 ASSERT_RESULT_OK(session1);
128 ASSERT_RESULT_OK(session1->UpdateStateAndCommit(SessionState::ACTIVATED));
129
130 auto session2 = manager->CreateSession(179);
131 ASSERT_RESULT_OK(session2);
132 ASSERT_RESULT_OK(session2->UpdateStateAndCommit(SessionState::SUCCESS));
133
134 // This sessions is not committed, it won't be returned in GetSessions.
135 ASSERT_RESULT_OK(manager->CreateSession(101));
136
137 auto sessions = manager->GetSessions();
138 std::sort(
139 sessions.begin(), sessions.end(),
140 [](const auto& s1, const auto& s2) { return s1.GetId() < s2.GetId(); });
141
142 ASSERT_EQ(2u, sessions.size());
143
144 ASSERT_EQ(179, sessions[0].GetId());
145 ASSERT_EQ(SessionState::SUCCESS, sessions[0].GetState());
146
147 ASSERT_EQ(1543, sessions[1].GetId());
148 ASSERT_EQ(SessionState::ACTIVATED, sessions[1].GetState());
149 }
150
TEST(ApexSessionManager,GetSessionsInState)151 TEST(ApexSessionManager, GetSessionsInState) {
152 TemporaryDir td;
153 auto manager = ApexSessionManager::Create(std::string(td.path));
154
155 auto session1 = manager->CreateSession(43);
156 ASSERT_RESULT_OK(session1);
157 ASSERT_RESULT_OK(session1->UpdateStateAndCommit(SessionState::ACTIVATED));
158
159 auto session2 = manager->CreateSession(41);
160 ASSERT_RESULT_OK(session2);
161 ASSERT_RESULT_OK(session2->UpdateStateAndCommit(SessionState::SUCCESS));
162
163 auto session3 = manager->CreateSession(23);
164 ASSERT_RESULT_OK(session3);
165 ASSERT_RESULT_OK(session3->UpdateStateAndCommit(SessionState::SUCCESS));
166
167 auto sessions = manager->GetSessionsInState(SessionState::SUCCESS);
168 std::sort(
169 sessions.begin(), sessions.end(),
170 [](const auto& s1, const auto& s2) { return s1.GetId() < s2.GetId(); });
171
172 ASSERT_EQ(2u, sessions.size());
173
174 ASSERT_EQ(23, sessions[0].GetId());
175 ASSERT_EQ(SessionState::SUCCESS, sessions[0].GetState());
176
177 ASSERT_EQ(41, sessions[1].GetId());
178 ASSERT_EQ(SessionState::SUCCESS, sessions[1].GetState());
179 }
180
TEST(ApexSessionManager,MigrateFromOldSessionsDir)181 TEST(ApexSessionManager, MigrateFromOldSessionsDir) {
182 TemporaryDir td;
183 auto old_manager = ApexSessionManager::Create(std::string(td.path));
184
185 auto session1 = old_manager->CreateSession(239);
186 ASSERT_RESULT_OK(session1);
187 ASSERT_RESULT_OK(session1->UpdateStateAndCommit(SessionState::STAGED));
188
189 auto session2 = old_manager->CreateSession(13);
190 ASSERT_RESULT_OK(session2);
191 ASSERT_RESULT_OK(session2->UpdateStateAndCommit(SessionState::SUCCESS));
192
193 auto session3 = old_manager->CreateSession(31);
194 ASSERT_RESULT_OK(session3);
195 ASSERT_RESULT_OK(session3->UpdateStateAndCommit(SessionState::ACTIVATED));
196
197 TemporaryDir td2;
198 auto new_manager = ApexSessionManager::Create(std::string(td2.path));
199
200 ASSERT_RESULT_OK(
201 new_manager->MigrateFromOldSessionsDir(std::string(td.path)));
202
203 auto sessions = new_manager->GetSessions();
204 std::sort(
205 sessions.begin(), sessions.end(),
206 [](const auto& s1, const auto& s2) { return s1.GetId() < s2.GetId(); });
207
208 ASSERT_EQ(3u, sessions.size());
209
210 ASSERT_EQ(13, sessions[0].GetId());
211 ASSERT_EQ(SessionState::SUCCESS, sessions[0].GetState());
212
213 ASSERT_EQ(31, sessions[1].GetId());
214 ASSERT_EQ(SessionState::ACTIVATED, sessions[1].GetState());
215
216 ASSERT_EQ(239, sessions[2].GetId());
217 ASSERT_EQ(SessionState::STAGED, sessions[2].GetState());
218
219 // Check that old manager directory doesn't have anything
220 auto old_sessions = old_manager->GetSessions();
221 ASSERT_TRUE(old_sessions.empty());
222 }
223
TEST(ApexSessionManager,MigrateFromOldSessionsDirSameDir)224 TEST(ApexSessionManager, MigrateFromOldSessionsDirSameDir) {
225 TemporaryDir td;
226 auto old_manager = ApexSessionManager::Create(std::string(td.path));
227
228 auto session1 = old_manager->CreateSession(239);
229 ASSERT_RESULT_OK(session1);
230 ASSERT_RESULT_OK(session1->UpdateStateAndCommit(SessionState::STAGED));
231
232 auto session2 = old_manager->CreateSession(13);
233 ASSERT_RESULT_OK(session2);
234 ASSERT_RESULT_OK(session2->UpdateStateAndCommit(SessionState::SUCCESS));
235
236 auto session3 = old_manager->CreateSession(31);
237 ASSERT_RESULT_OK(session3);
238 ASSERT_RESULT_OK(session3->UpdateStateAndCommit(SessionState::ACTIVATED));
239
240 auto new_manager = ApexSessionManager::Create(std::string(td.path));
241
242 ASSERT_RESULT_OK(
243 new_manager->MigrateFromOldSessionsDir(std::string(td.path)));
244
245 auto sessions = new_manager->GetSessions();
246 std::sort(
247 sessions.begin(), sessions.end(),
248 [](const auto& s1, const auto& s2) { return s1.GetId() < s2.GetId(); });
249
250 ASSERT_EQ(3u, sessions.size());
251
252 ASSERT_EQ(13, sessions[0].GetId());
253 ASSERT_EQ(SessionState::SUCCESS, sessions[0].GetState());
254
255 ASSERT_EQ(31, sessions[1].GetId());
256 ASSERT_EQ(SessionState::ACTIVATED, sessions[1].GetState());
257
258 ASSERT_EQ(239, sessions[2].GetId());
259 ASSERT_EQ(SessionState::STAGED, sessions[2].GetState());
260
261 // Directory is the same, so using old_manager should also work.
262 auto old_sessions = old_manager->GetSessions();
263 std::sort(
264 old_sessions.begin(), old_sessions.end(),
265 [](const auto& s1, const auto& s2) { return s1.GetId() < s2.GetId(); });
266
267 ASSERT_EQ(3u, old_sessions.size());
268
269 ASSERT_EQ(13, old_sessions[0].GetId());
270 ASSERT_EQ(SessionState::SUCCESS, old_sessions[0].GetState());
271
272 ASSERT_EQ(31, old_sessions[1].GetId());
273 ASSERT_EQ(SessionState::ACTIVATED, old_sessions[1].GetState());
274
275 ASSERT_EQ(239, old_sessions[2].GetId());
276 ASSERT_EQ(SessionState::STAGED, old_sessions[2].GetState());
277 }
278
TEST(ApexSessionManagerTest,GetStagedApexDirsSelf)279 TEST(ApexSessionManagerTest, GetStagedApexDirsSelf) {
280 TemporaryDir td;
281 auto manager = ApexSessionManager::Create(std::string(td.path));
282
283 auto session = manager->CreateSession(239);
284 ASSERT_RESULT_OK(session);
285
286 ASSERT_THAT(session->GetStagedApexDirs("/path/to/staged_session_dir"),
287 UnorderedElementsAre("/path/to/staged_session_dir/session_239"));
288 }
289
TEST(ApexSessionManagerTest,GetStagedApexDirsChildren)290 TEST(ApexSessionManagerTest, GetStagedApexDirsChildren) {
291 TemporaryDir td;
292 auto manager = ApexSessionManager::Create(std::string(td.path));
293
294 auto session = manager->CreateSession(239);
295 ASSERT_RESULT_OK(session);
296 auto child_session_1 = manager->CreateSession(240);
297 ASSERT_RESULT_OK(child_session_1);
298 auto child_session_2 = manager->CreateSession(241);
299 ASSERT_RESULT_OK(child_session_2);
300 session->SetChildSessionIds({240, 241});
301
302 ASSERT_THAT(session->GetStagedApexDirs("/path/to/staged_session_dir"),
303 UnorderedElementsAre("/path/to/staged_session_dir/session_240",
304 "/path/to/staged_session_dir/session_241"));
305 }
306
307 } // namespace
308 } // namespace apex
309 } // namespace android
310