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 <string>
20
21 #include <errno.h>
22
23 #include <android-base/file.h>
24 #include <android-base/result.h>
25 #include <android-base/scopeguard.h>
26 #include <android-base/stringprintf.h>
27 #include <android-base/strings.h>
28 #include <gtest/gtest.h>
29
30 #include "apexd_session.h"
31 #include "apexd_test_utils.h"
32 #include "apexd_utils.h"
33 #include "session_state.pb.h"
34
35 namespace android {
36 namespace apex {
37 namespace {
38
39 using android::apex::testing::IsOk;
40 using android::base::Join;
41 using android::base::make_scope_guard;
42 using ::apex::proto::SessionState;
43
44 // TODO(b/170329726): add unit tests for apexd_sessions.h
45
TEST(ApexdSessionTest,GetSessionsDirSessionsStoredInMetadata)46 TEST(ApexdSessionTest, GetSessionsDirSessionsStoredInMetadata) {
47 if (access("/metadata", F_OK) != 0) {
48 GTEST_SKIP() << "Device doesn't have /metadata partition";
49 }
50
51 std::string result = ApexSession::GetSessionsDir();
52 ASSERT_EQ(result, "/metadata/apex/sessions");
53 }
54
TEST(ApexdSessionTest,GetSessionsDirNoMetadataPartitionFallbackToData)55 TEST(ApexdSessionTest, GetSessionsDirNoMetadataPartitionFallbackToData) {
56 if (access("/metadata", F_OK) == 0) {
57 GTEST_SKIP() << "Device has /metadata partition";
58 }
59
60 std::string result = ApexSession::GetSessionsDir();
61 ASSERT_EQ(result, "/data/apex/sessions");
62 }
63
TEST(ApexdSessionTest,MigrateToMetadataSessionsDir)64 TEST(ApexdSessionTest, MigrateToMetadataSessionsDir) {
65 namespace fs = std::filesystem;
66
67 if (access("/metadata", F_OK) != 0) {
68 GTEST_SKIP() << "Device doesn't have /metadata partition";
69 }
70
71 // This is ugly, but does the job. To have a truly hermetic unit tests we
72 // need to refactor ApexSession class.
73 for (const auto& entry : fs::directory_iterator("/metadata/apex/sessions")) {
74 fs::remove_all(entry.path());
75 }
76
77 // This is a very ugly test set up, but to have something better we need to
78 // refactor ApexSession class.
79 class TestApexSession {
80 public:
81 TestApexSession(int id, const SessionState::State& state) {
82 path_ = "/data/apex/sessions/" + std::to_string(id);
83 if (auto status = CreateDirIfNeeded(path_, 0700); !status.ok()) {
84 ADD_FAILURE() << "Failed to create " << path_ << " : "
85 << status.error();
86 }
87 SessionState session;
88 session.set_id(id);
89 session.set_state(state);
90 std::fstream state_file(
91 path_ + "/state", std::ios::out | std::ios::trunc | std::ios::binary);
92 if (!session.SerializeToOstream(&state_file)) {
93 ADD_FAILURE() << "Failed to write to " << path_;
94 }
95 }
96
97 ~TestApexSession() { fs::remove_all(path_); }
98
99 private:
100 std::string path_;
101 };
102
103 auto deleter = make_scope_guard([&]() {
104 fs::remove_all("/metadata/apex/sessions/239");
105 fs::remove_all("/metadata/apex/sessions/1543");
106 });
107
108 TestApexSession session1(239, SessionState::SUCCESS);
109 TestApexSession session2(1543, SessionState::ACTIVATION_FAILED);
110
111 ASSERT_TRUE(IsOk(ApexSession::MigrateToMetadataSessionsDir()));
112
113 auto sessions = ApexSession::GetSessions();
114 ASSERT_EQ(2u, sessions.size()) << Join(sessions, ',');
115
116 auto migrated_session_1 = ApexSession::GetSession(239);
117 ASSERT_TRUE(IsOk(migrated_session_1));
118 ASSERT_EQ(SessionState::SUCCESS, migrated_session_1->GetState());
119
120 auto migrated_session_2 = ApexSession::GetSession(1543);
121 ASSERT_TRUE(IsOk(migrated_session_2));
122 ASSERT_EQ(SessionState::ACTIVATION_FAILED, migrated_session_2->GetState());
123 }
124
125 } // namespace
126 } // namespace apex
127 } // namespace android
128