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