blob: 164f94282e15db6a59b2a425859fe8ccef46e23c [file] [log] [blame]
//
// Copyright (C) 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "host/commands/cvd/unittests/selector/instance_database_test_helper.h"
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <android-base/file.h>
#include "common/libs/fs/shared_buf.h"
#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/environment.h"
#include "common/libs/utils/files.h"
#include "host/commands/cvd/selector/selector_constants.h"
namespace cuttlefish {
namespace instance_db {
namespace {
// mktemp with /tmp/<subdir>.XXXXXX, and if failed,
// mkdir -p /tmp/<subdir>.<default_suffix>
std::optional<std::string> CreateTempDirectory(
const std::string& subdir, const std::string& default_suffix) {
std::string path_pattern = "/tmp/" + subdir + ".XXXXXX";
auto ptr = mkdtemp(path_pattern.data());
if (ptr) {
return {std::string(ptr)};
}
std::string default_path = "/tmp/" + subdir + "." + default_suffix;
return (EnsureDirectoryExists(default_path).ok() ? std::optional(default_path)
: std::nullopt);
}
// Linux "touch" a(n empty) file
bool Touch(const std::string& full_path) {
// this file is required only to make FileExists() true.
SharedFD new_file = SharedFD::Creat(full_path, S_IRUSR | S_IWUSR);
return new_file->IsOpen();
}
} // namespace
CvdInstanceDatabaseTest::CvdInstanceDatabaseTest()
: error_{.error_code = ErrorCode::kOk, .msg = ""} {
InitWorkspace() && InitMockAndroidHostOut();
}
CvdInstanceDatabaseTest::~CvdInstanceDatabaseTest() { ClearWorkspace(); }
void CvdInstanceDatabaseTest::ClearWorkspace() {
if (!workspace_dir_.empty()) {
RecursivelyRemoveDirectory(workspace_dir_);
}
}
void CvdInstanceDatabaseTest::SetErrorCode(const ErrorCode error_code,
const std::string& msg) {
error_.error_code = error_code;
error_.msg = msg;
}
bool CvdInstanceDatabaseTest::InitWorkspace() {
// creating a parent dir of the mock home directories for each fake group
auto result_opt = CreateTempDirectory("cf_unittest", "default_location");
if (!result_opt) {
SetErrorCode(ErrorCode::kFileError, "Failed to create workspace");
return false;
}
workspace_dir_ = std::move(result_opt.value());
return true;
}
bool CvdInstanceDatabaseTest::InitMockAndroidHostOut() {
/* creating a fake host out directory
*
* As the automated testing system does not guarantee that there is either
* ANDROID_HOST_OUT or ".", where we can find host tools, we create a fake
* host tool directory just enough to deceive InstanceDatabase APIs.
*
*/
std::string android_host_out = workspace_dir_ + "/android_host_out";
if (!EnsureDirectoryExists(android_host_out).ok()) {
SetErrorCode(ErrorCode::kFileError, "Failed to create " + android_host_out);
return false;
}
android_binaries_dir_ = android_host_out + "/bin";
if (!EnsureDirectoryExists(android_binaries_dir_).ok()) {
SetErrorCode(ErrorCode::kFileError,
"Failed to create " + android_binaries_dir_);
return false;
}
if (!Touch(android_binaries_dir_ + "/launch_cvd")) {
SetErrorCode(ErrorCode::kFileError, "Failed to create mock launch_cvd");
return false;
}
return true;
}
// Add an InstanceGroups with each home directory and android_host_out_
bool CvdInstanceDatabaseTest::AddGroups(
const std::unordered_set<std::string>& base_names) {
for (const auto& base_name : base_names) {
const std::string home(Workspace() + "/" + base_name);
if (!EnsureDirectoryExists(home).ok()) {
SetErrorCode(ErrorCode::kFileError, home + " directory is not found.");
return false;
}
if (!db_.AddInstanceGroup(base_name, home, android_binaries_dir_).ok()) {
SetErrorCode(ErrorCode::kInstanceDabaseError, "Failed to add group");
return false;
}
}
return true;
}
bool CvdInstanceDatabaseTest::AddInstances(
const ConstRef<LocalInstanceGroup> group,
const std::vector<InstanceInfo>& instances_info) {
for (const auto& [id, per_instance_name] : instances_info) {
if (!db_.AddInstance(group, id, per_instance_name).ok()) {
SetErrorCode(ErrorCode::kInstanceDabaseError,
"Failed to add instance " + per_instance_name);
return false;
}
}
return true;
}
} // namespace instance_db
} // namespace cuttlefish