• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2022 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 #include "host/commands/cvd/unittests/selector/instance_database_helper.h"
17 
18 #include <algorithm>
19 #include <cstdio>
20 #include <cstdlib>
21 
22 #include <android-base/file.h>
23 
24 #include "common/libs/fs/shared_buf.h"
25 #include "common/libs/fs/shared_fd.h"
26 #include "common/libs/utils/environment.h"
27 #include "common/libs/utils/files.h"
28 #include "host/commands/cvd/selector/selector_constants.h"
29 
30 namespace cuttlefish {
31 namespace selector {
32 namespace {
33 
34 // mktemp with /tmp/<subdir>.XXXXXX, and if failed,
35 // mkdir -p /tmp/<subdir>.<default_suffix>
CreateTempDirectory(const std::string & subdir,const std::string & default_suffix)36 std::optional<std::string> CreateTempDirectory(
37     const std::string& subdir, const std::string& default_suffix) {
38   std::string path_pattern = "/tmp/" + subdir + ".XXXXXX";
39   auto ptr = mkdtemp(path_pattern.data());
40   if (ptr) {
41     return {std::string(ptr)};
42   }
43   std::string default_path = "/tmp/" + subdir + "." + default_suffix;
44   return (EnsureDirectoryExists(default_path).ok() ? std::optional(default_path)
45                                                    : std::nullopt);
46 }
47 
48 // Linux "touch" a(n empty) file
Touch(const std::string & full_path)49 bool Touch(const std::string& full_path) {
50   // this file is required only to make FileExists() true.
51   SharedFD new_file = SharedFD::Creat(full_path, S_IRUSR | S_IWUSR);
52   return new_file->IsOpen();
53 }
54 
55 }  // namespace
56 
CvdInstanceDatabaseTest()57 CvdInstanceDatabaseTest::CvdInstanceDatabaseTest()
58     : error_{.error_code = ErrorCode::kOk, .msg = ""} {
59   InitWorkspace() && InitMockAndroidHostOut();
60 }
61 
~CvdInstanceDatabaseTest()62 CvdInstanceDatabaseTest::~CvdInstanceDatabaseTest() { ClearWorkspace(); }
63 
ClearWorkspace()64 void CvdInstanceDatabaseTest::ClearWorkspace() {
65   if (!workspace_dir_.empty()) {
66     RecursivelyRemoveDirectory(workspace_dir_);
67   }
68 }
69 
SetErrorCode(const ErrorCode error_code,const std::string & msg)70 void CvdInstanceDatabaseTest::SetErrorCode(const ErrorCode error_code,
71                                            const std::string& msg) {
72   error_.error_code = error_code;
73   error_.msg = msg;
74 }
75 
InitWorkspace()76 bool CvdInstanceDatabaseTest::InitWorkspace() {
77   // creating a parent dir of the mock home directories for each fake group
78   auto result_opt = CreateTempDirectory("cf_unittest", "default_location");
79   if (!result_opt) {
80     SetErrorCode(ErrorCode::kFileError, "Failed to create workspace");
81     return false;
82   }
83   workspace_dir_ = std::move(result_opt.value());
84   return true;
85 }
86 
InitMockAndroidHostOut()87 bool CvdInstanceDatabaseTest::InitMockAndroidHostOut() {
88   /* creating a fake host out directory
89    *
90    * As the automated testing system does not guarantee that there is either
91    * ANDROID_HOST_OUT or ".", where we can find host tools, we create a fake
92    * host tool directory just enough to deceive InstanceDatabase APIs.
93    *
94    */
95   std::string android_host_out = workspace_dir_ + "/android_host_out";
96   if (!EnsureDirectoryExists(android_host_out).ok()) {
97     SetErrorCode(ErrorCode::kFileError, "Failed to create " + android_host_out);
98     return false;
99   }
100   android_artifacts_path_ = android_host_out;
101   if (!EnsureDirectoryExists(android_artifacts_path_ + "/bin").ok()) {
102     SetErrorCode(ErrorCode::kFileError,
103                  "Failed to create " + android_artifacts_path_ + "/bin");
104     return false;
105   }
106   if (!Touch(android_artifacts_path_ + "/bin" + "/launch_cvd")) {
107     SetErrorCode(ErrorCode::kFileError, "Failed to create mock launch_cvd");
108     return false;
109   }
110   return true;
111 }
112 
113 // Add an InstanceGroups with each home directory and android_host_out_
AddGroups(const std::unordered_set<std::string> & base_names)114 bool CvdInstanceDatabaseTest::AddGroups(
115     const std::unordered_set<std::string>& base_names) {
116   for (const auto& base_name : base_names) {
117     const std::string home(Workspace() + "/" + base_name);
118     if (!EnsureDirectoryExists(home).ok()) {
119       SetErrorCode(ErrorCode::kFileError, home + " directory is not found.");
120       return false;
121     }
122     InstanceDatabase::AddInstanceGroupParam param{
123         .group_name = base_name,
124         .home_dir = home,
125         .host_artifacts_path = android_artifacts_path_,
126         .product_out_path = android_artifacts_path_};
127     if (!db_.AddInstanceGroup(param).ok()) {
128       SetErrorCode(ErrorCode::kInstanceDabaseError, "Failed to add group");
129       return false;
130     }
131   }
132   return true;
133 }
134 
AddInstances(const std::string & group_name,const std::vector<InstanceInfo> & instances_info)135 bool CvdInstanceDatabaseTest::AddInstances(
136     const std::string& group_name,
137     const std::vector<InstanceInfo>& instances_info) {
138   for (const auto& [id, per_instance_name] : instances_info) {
139     if (!db_.AddInstance(group_name, id, per_instance_name).ok()) {
140       SetErrorCode(ErrorCode::kInstanceDabaseError,
141                    "Failed to add instance " + per_instance_name);
142       return false;
143     }
144   }
145   return true;
146 }
147 
148 }  // namespace selector
149 }  // namespace cuttlefish
150