Revert^2 "Add unit tests for odrefresh - step 2"
This reverts commit b89649bd95cffec48f6f6746054553f71ab3e807.
Reason for revert: Fixed the fugu build breakage
The test failed on fugu because fugu is running Android O, while the
test depends on a system property introduced in S. Since the whole
odrefresh program is for S and later, we don't need to run the test on
older platforms. This failure is fixed by adding a check on the API
level and skipping the test if the API level is below S.
Bug: 196188549
Test: atest art_standalone_odrefresh_tests
Change-Id: I484696d065d715da65ae262a5aa8b3e1b30ffdcf
diff --git a/odrefresh/Android.bp b/odrefresh/Android.bp
index 2f973a4..acfd97a 100644
--- a/odrefresh/Android.bp
+++ b/odrefresh/Android.bp
@@ -25,8 +25,6 @@
cc_defaults {
name: "odrefresh-defaults",
- host_supported: true,
- defaults: ["art_defaults"],
srcs: [
"odrefresh.cc",
"odr_common.cc",
@@ -45,15 +43,9 @@
shared_libs: [
"libartpalette",
"libbase",
- "libdexfile",
"liblog",
],
static_libs: ["libtinyxml2"],
- target: {
- android: {
- compile_multilib: "first",
- },
- },
tidy: true,
tidy_flags: [
"-format-style=file",
@@ -61,6 +53,24 @@
],
}
+cc_defaults {
+ name: "odrefresh_binary_defaults",
+ host_supported: true,
+ defaults: [
+ "art_defaults",
+ "odrefresh-defaults",
+ ],
+ srcs: ["odrefresh_main.cc"],
+ shared_libs: [
+ "libdexfile",
+ ],
+ target: {
+ android: {
+ compile_multilib: "first",
+ },
+ },
+}
+
cc_library_headers {
name: "odrefresh_headers",
export_include_dirs: ["include"],
@@ -87,8 +97,7 @@
art_cc_binary {
name: "odrefresh",
- defaults: ["odrefresh-defaults"],
- srcs: ["odrefresh_main.cc"],
+ defaults: ["odrefresh_binary_defaults"],
required: [
"dexoptanalyzer",
"dex2oat",
@@ -107,9 +116,8 @@
name: "odrefreshd",
defaults: [
"art_debug_defaults",
- "odrefresh-defaults",
+ "odrefresh_binary_defaults",
],
- srcs: ["odrefresh_main.cc"],
required: [
"dexoptanalyzerd",
"dex2oatd",
@@ -132,7 +140,6 @@
defaults: ["art_defaults"],
host_supported: true,
export_include_dirs: ["include"],
-
local_include_dirs: ["include"],
shared_libs: ["libartbase"],
target: {
@@ -157,21 +164,19 @@
art_cc_defaults {
name: "art_odrefresh_tests_defaults",
- generated_sources: ["art-odrefresh-operator-srcs"],
+ defaults: ["odrefresh-defaults"],
header_libs: ["odrefresh_headers"],
srcs: [
"odr_artifacts_test.cc",
- "odr_compilation_log.cc",
"odr_compilation_log_test.cc",
- "odr_fs_utils.cc",
"odr_fs_utils_test.cc",
- "odr_metrics.cc",
"odr_metrics_test.cc",
- "odr_metrics_record.cc",
"odr_metrics_record_test.cc",
"odrefresh_test.cc",
],
- shared_libs: ["libbase"],
+ static_libs: [
+ "libgmock",
+ ],
}
// Version of ART gtest `art_odrefresh_tests` bundled with the ART APEX on target.
@@ -182,6 +187,10 @@
"art_gtest_defaults",
"art_odrefresh_tests_defaults",
],
+ shared_libs: [
+ "libdexfiled",
+ ],
+ test_config_template: "art_odrefresh_tests.xml",
}
// Standalone version of ART gtest `art_odrefresh_tests`, not bundled with the ART APEX on target.
@@ -191,6 +200,10 @@
"art_standalone_gtest_defaults",
"art_odrefresh_tests_defaults",
],
+ shared_libs: [
+ "libdexfile",
+ ],
+ test_config_template: "art_odrefresh_tests.xml",
}
genrule {
diff --git a/odrefresh/art_odrefresh_tests.xml b/odrefresh/art_odrefresh_tests.xml
new file mode 100644
index 0000000..f9d6df5
--- /dev/null
+++ b/odrefresh/art_odrefresh_tests.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+<!-- Note: This test config file for {MODULE} is generated from a template. -->
+<configuration description="Runs {MODULE}.">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="{MODULE}->/data/local/tmp/nativetest/{MODULE}" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp/nativetest" />
+ <option name="module-name" value="{MODULE}" />
+ <option name="ld-library-path-32" value="/apex/com.android.art/lib" />
+ <option name="ld-library-path-64" value="/apex/com.android.art/lib64" />
+ </test>
+
+ <!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
+ one of the Mainline modules below is present on the device used for testing. -->
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <!-- ART Mainline Module (internal version). -->
+ <option name="mainline-module-package-name" value="com.google.android.art" />
+ <!-- ART Mainline Module (external (AOSP) version). -->
+ <option name="mainline-module-package-name" value="com.android.art" />
+ </object>
+</configuration>
diff --git a/odrefresh/odr_config.h b/odrefresh/odr_config.h
index 23d5cb6..6764e2c 100644
--- a/odrefresh/odr_config.h
+++ b/odrefresh/odr_config.h
@@ -57,6 +57,10 @@
std::string compilation_os_address_;
std::string boot_classpath_;
+ // Staging directory for artifacts. The directory must exist and will be automatically removed
+ // after compilation. If empty, use the default directory.
+ std::string staging_dir_;
+
public:
explicit OdrConfig(const char* program_name)
: dry_run_(false),
@@ -120,7 +124,12 @@
const std::string& GetSystemServerClasspath() const { return system_server_classpath_; }
const std::string& GetUpdatableBcpPackagesFile() const { return updatable_bcp_packages_file_; }
bool UseCompilationOs() const { return !compilation_os_address_.empty(); }
- std::string GetCompilationOsAddress() const { return compilation_os_address_; }
+ const std::string& GetCompilationOsAddress() const {
+ return compilation_os_address_;
+ }
+ const std::string& GetStagingDir() const {
+ return staging_dir_;
+ }
void SetApexInfoListFile(const std::string& file_path) { apex_info_list_file_ = file_path; }
void SetArtBinDir(const std::string& art_bin_dir) { art_bin_dir_ = art_bin_dir; }
@@ -144,6 +153,10 @@
void SetBootClasspath(const std::string& classpath) { boot_classpath_ = classpath; }
+ void SetStagingDir(const std::string& staging_dir) {
+ staging_dir_ = staging_dir;
+ }
+
private:
// Returns a pair for the possible instruction sets for the configured instruction set
// architecture. The first item is the 32-bit architecture and the second item is the 64-bit
diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc
index 5b003c3..9503159 100644
--- a/odrefresh/odrefresh.cc
+++ b/odrefresh/odrefresh.cc
@@ -459,9 +459,17 @@
} // namespace
OnDeviceRefresh::OnDeviceRefresh(const OdrConfig& config)
+ : OnDeviceRefresh(config,
+ Concatenate({kOdrefreshArtifactDirectory, "/", kCacheInfoFile}),
+ std::make_unique<ExecUtils>()) {}
+
+OnDeviceRefresh::OnDeviceRefresh(const OdrConfig& config,
+ const std::string& cache_info_filename,
+ std::unique_ptr<ExecUtils> exec_utils)
: config_{config},
- cache_info_filename_{Concatenate({kOdrefreshArtifactDirectory, "/", kCacheInfoFile})},
- start_time_{time(nullptr)} {
+ cache_info_filename_{cache_info_filename},
+ start_time_{time(nullptr)},
+ exec_utils_{std::move(exec_utils)} {
for (const std::string& jar : android::base::Split(config_.GetDex2oatBootClasspath(), ":")) {
// Boot class path extensions are those not in the ART APEX. Updatable APEXes should not
// have DEX files in the DEX2OATBOOTCLASSPATH. At the time of writing i18n is a non-updatable
@@ -1088,7 +1096,8 @@
std::string error_msg;
bool timed_out = false;
const time_t timeout = GetSubprocessTimeout();
- const int dexoptanalyzer_result = ExecAndReturnCode(args, timeout, &timed_out, &error_msg);
+ const int dexoptanalyzer_result =
+ exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, &error_msg);
if (dexoptanalyzer_result == -1) {
LOG(ERROR) << "Unexpected exit from dexoptanalyzer: " << error_msg;
if (timed_out) {
@@ -1184,7 +1193,8 @@
std::string error_msg;
bool timed_out = false;
const time_t timeout = GetSubprocessTimeout();
- const int dexoptanalyzer_result = ExecAndReturnCode(args, timeout, &timed_out, &error_msg);
+ const int dexoptanalyzer_result =
+ exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, &error_msg);
if (dexoptanalyzer_result == -1) {
LOG(ERROR) << "Unexpected exit from dexoptanalyzer: " << error_msg;
if (timed_out) {
@@ -1363,7 +1373,7 @@
}
bool timed_out = false;
- int dex2oat_exit_code = ExecAndReturnCode(args, timeout, &timed_out, error_msg);
+ int dex2oat_exit_code = exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, error_msg);
if (dex2oat_exit_code != 0) {
if (timed_out) {
metrics.SetStatus(OdrMetrics::Status::kTimeLimitExceeded);
@@ -1513,7 +1523,7 @@
}
bool timed_out = false;
- int dex2oat_exit_code = ExecAndReturnCode(args, timeout, &timed_out, error_msg);
+ int dex2oat_exit_code = exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, error_msg);
if (dex2oat_exit_code != 0) {
if (timed_out) {
metrics.SetStatus(OdrMetrics::Status::kTimeLimitExceeded);
@@ -1544,10 +1554,14 @@
const char* staging_dir = nullptr;
metrics.SetStage(OdrMetrics::Stage::kPreparation);
- // Create staging area and assign label for generating compilation artifacts.
- if (PaletteCreateOdrefreshStagingDirectory(&staging_dir) != PALETTE_STATUS_OK) {
- metrics.SetStatus(OdrMetrics::Status::kStagingFailed);
- return ExitCode::kCleanupFailed;
+ if (!config_.GetStagingDir().empty()) {
+ staging_dir = config_.GetStagingDir().c_str();
+ } else {
+ // Create staging area and assign label for generating compilation artifacts.
+ if (PaletteCreateOdrefreshStagingDirectory(&staging_dir) != PALETTE_STATUS_OK) {
+ metrics.SetStatus(OdrMetrics::Status::kStagingFailed);
+ return ExitCode::kCleanupFailed;
+ }
}
// Emit cache info before compiling. This can be used to throttle compilation attempts later.
diff --git a/odrefresh/odrefresh.h b/odrefresh/odrefresh.h
index c1f7d71..2a7164b 100644
--- a/odrefresh/odrefresh.h
+++ b/odrefresh/odrefresh.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -18,12 +18,14 @@
#define ART_ODREFRESH_ODREFRESH_H_
#include <ctime>
+#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "com_android_apex.h"
#include "com_android_art.h"
+#include "exec_utils.h"
#include "odr_artifacts.h"
#include "odr_config.h"
#include "odr_metrics.h"
@@ -36,6 +38,11 @@
public:
explicit OnDeviceRefresh(const OdrConfig& config);
+ // Constructor with injections. For testing and internal use only.
+ OnDeviceRefresh(const OdrConfig& config,
+ const std::string& cache_info_filename,
+ std::unique_ptr<ExecUtils> exec_utils);
+
// Returns the exit code, a list of ISAs that boot extensions should be compiled for, and a
// boolean indicating whether the system server should be compiled.
WARN_UNUSED ExitCode
@@ -171,6 +178,8 @@
time_t max_child_process_seconds_;
+ std::unique_ptr<ExecUtils> exec_utils_;
+
DISALLOW_COPY_AND_ASSIGN(OnDeviceRefresh);
};
diff --git a/odrefresh/odrefresh_test.cc b/odrefresh/odrefresh_test.cc
index a09accb..a6682ec 100644
--- a/odrefresh/odrefresh_test.cc
+++ b/odrefresh/odrefresh_test.cc
@@ -14,19 +14,230 @@
* limitations under the License.
*/
-#include "odrefresh/odrefresh.h"
+#include "odrefresh.h"
+#include <functional>
+#include <memory>
+#include <string_view>
+
+#ifdef __ANDROID__
+#include <android/api-level.h>
+#endif
+
+#include "android-base/properties.h"
+#include "android-base/scopeguard.h"
+#include "android-base/strings.h"
+#include "arch/instruction_set.h"
#include "base/common_art_test.h"
#include "base/file_utils.h"
+#include "exec_utils.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "odr_common.h"
+#include "odr_config.h"
+#include "odr_fs_utils.h"
+#include "odr_metrics.h"
+#include "odrefresh/odrefresh.h"
namespace art {
namespace odrefresh {
-TEST(OdRefreshTest, OdrefreshArtifactDirectory) {
- // odrefresh.h defines kOdrefreshArtifactDirectory for external callers of odrefresh. This is
- // where compilation artifacts end up.
- ScopedUnsetEnvironmentVariable no_env("ART_APEX_DATA");
- EXPECT_EQ(kOdrefreshArtifactDirectory, GetArtApexData() + "/dalvik-cache");
+using ::testing::AllOf;
+using ::testing::Contains;
+using ::testing::HasSubstr;
+using ::testing::Not;
+using ::testing::Return;
+
+constexpr int kReplace = 1;
+
+void CreateEmptyFile(const std::string& name) {
+ File* file = OS::CreateEmptyFile(name.c_str());
+ ASSERT_TRUE(file != nullptr);
+ file->Release();
+ delete file;
+}
+
+android::base::ScopeGuard<std::function<void()>> ScopedSetProperty(const std::string& key,
+ const std::string& value) {
+ std::string old_value = android::base::GetProperty(key, /*default_value=*/{});
+ android::base::SetProperty(key, value);
+ return android::base::ScopeGuard([=]() { android::base::SetProperty(key, old_value); });
+}
+
+class MockExecUtils : public ExecUtils {
+ public:
+ // A workaround to avoid MOCK_METHOD on a method with an `std::string*` parameter, which will lead
+ // to a conflict between gmock and android-base/logging.h (b/132668253).
+ int ExecAndReturnCode(std::vector<std::string>& arg_vector,
+ time_t,
+ bool*,
+ std::string*) const override {
+ return DoExecAndReturnCode(arg_vector);
+ }
+
+ MOCK_METHOD(int, DoExecAndReturnCode, (std::vector<std::string> & arg_vector), (const));
+};
+
+class OdRefreshTest : public CommonArtTest {
+ public:
+ OdRefreshTest() : config_("odrefresh") {}
+
+ protected:
+ void SetUp() override {
+ CommonArtTest::SetUp();
+
+ temp_dir_ = std::make_unique<ScratchDir>();
+ std::string_view temp_dir_path = temp_dir_->GetPath();
+ android::base::ConsumeSuffix(&temp_dir_path, "/");
+
+ std::string android_root_path = Concatenate({temp_dir_path, "/system"});
+ ASSERT_TRUE(EnsureDirectoryExists(android_root_path));
+ android_root_env_ = std::make_unique<ScopedUnsetEnvironmentVariable>("ANDROID_ROOT");
+ setenv("ANDROID_ROOT", android_root_path.c_str(), kReplace);
+
+ std::string android_art_root_path = Concatenate({temp_dir_path, "/apex/com.android.art"});
+ ASSERT_TRUE(EnsureDirectoryExists(android_art_root_path));
+ android_art_root_env_ = std::make_unique<ScopedUnsetEnvironmentVariable>("ANDROID_ART_ROOT");
+ setenv("ANDROID_ART_ROOT", android_art_root_path.c_str(), kReplace);
+
+ std::string art_apex_data_path = Concatenate({temp_dir_path, kArtApexDataDefaultPath});
+ ASSERT_TRUE(EnsureDirectoryExists(art_apex_data_path));
+ art_apex_data_env_ = std::make_unique<ScopedUnsetEnvironmentVariable>("ART_APEX_DATA");
+ setenv("ART_APEX_DATA", art_apex_data_path.c_str(), kReplace);
+
+ std::string dalvik_cache_dir = art_apex_data_path + "/dalvik-cache";
+ ASSERT_TRUE(EnsureDirectoryExists(dalvik_cache_dir));
+
+ std::string framework_dir = android_root_path + "/framework";
+ framework_jar_ = framework_dir + "/framework.jar";
+ location_provider_jar_ = framework_dir + "/com.android.location.provider.jar";
+ services_jar_ = framework_dir + "/services.jar";
+ std::string services_jar_prof = framework_dir + "/services.jar.prof";
+ std::string javalib_dir = android_art_root_path + "/javalib";
+ std::string boot_art = javalib_dir + "/boot.art";
+
+ // Create placeholder files.
+ ASSERT_TRUE(EnsureDirectoryExists(framework_dir));
+ CreateEmptyFile(framework_jar_);
+ CreateEmptyFile(location_provider_jar_);
+ CreateEmptyFile(services_jar_);
+ CreateEmptyFile(services_jar_prof);
+ ASSERT_TRUE(EnsureDirectoryExists(javalib_dir));
+ CreateEmptyFile(boot_art);
+
+ config_.SetApexInfoListFile(Concatenate({temp_dir_path, "/apex-info-list.xml"}));
+ config_.SetArtBinDir(Concatenate({temp_dir_path, "/bin"}));
+ config_.SetBootClasspath(framework_jar_);
+ config_.SetDex2oatBootclasspath(framework_jar_);
+ config_.SetSystemServerClasspath(Concatenate({location_provider_jar_, ":", services_jar_}));
+ config_.SetIsa(InstructionSet::kX86_64);
+ config_.SetZygoteKind(ZygoteKind::kZygote64_32);
+
+ std::string staging_dir = dalvik_cache_dir + "/staging";
+ ASSERT_TRUE(EnsureDirectoryExists(staging_dir));
+ config_.SetStagingDir(staging_dir);
+
+ auto mock_exec_utils = std::make_unique<MockExecUtils>();
+ mock_exec_utils_ = mock_exec_utils.get();
+
+ metrics_ = std::make_unique<OdrMetrics>(dalvik_cache_dir);
+ odrefresh_ = std::make_unique<OnDeviceRefresh>(
+ config_, dalvik_cache_dir + "/cache-info.xml", std::move(mock_exec_utils));
+ }
+
+ void TearDown() override {
+ metrics_.reset();
+ temp_dir_.reset();
+ android_root_env_.reset();
+ android_art_root_env_.reset();
+ art_apex_data_env_.reset();
+
+ CommonArtTest::TearDown();
+ }
+
+ std::unique_ptr<ScratchDir> temp_dir_;
+ std::unique_ptr<ScopedUnsetEnvironmentVariable> android_root_env_;
+ std::unique_ptr<ScopedUnsetEnvironmentVariable> android_art_root_env_;
+ std::unique_ptr<ScopedUnsetEnvironmentVariable> art_apex_data_env_;
+ OdrConfig config_;
+ MockExecUtils* mock_exec_utils_;
+ std::unique_ptr<OdrMetrics> metrics_;
+ std::unique_ptr<OnDeviceRefresh> odrefresh_;
+ std::string framework_jar_;
+ std::string location_provider_jar_;
+ std::string services_jar_;
+};
+
+TEST_F(OdRefreshTest, OdrefreshArtifactDirectory) {
+ // odrefresh.h defines kOdrefreshArtifactDirectory for external callers of odrefresh. This is
+ // where compilation artifacts end up.
+ ScopedUnsetEnvironmentVariable no_env("ART_APEX_DATA");
+ EXPECT_EQ(kOdrefreshArtifactDirectory, GetArtApexData() + "/dalvik-cache");
+}
+
+TEST_F(OdRefreshTest, CompileSetsCompilerFilter) {
+#ifdef __ANDROID__
+ // This test depends on a system property introduced in S. Since the whole odrefresh program is
+ // for S and later, we don't need to run the test on older platforms.
+ if (android_get_device_api_level() < __ANDROID_API_S__) {
+ return;
+ }
+#endif
+
+ {
+ // Defaults to "speed".
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", location_provider_jar_})),
+ Not(Contains(HasSubstr("--profile-file-fd="))),
+ Contains("--compiler-filter=speed"))))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", services_jar_})),
+ Not(Contains(HasSubstr("--profile-file-fd="))),
+ Contains("--compiler-filter=speed"))))
+ .WillOnce(Return(0));
+ EXPECT_EQ(odrefresh_->Compile(
+ *metrics_, /*compile_boot_extensions=*/{}, /*compile_system_server=*/true),
+ ExitCode::kCompilationSuccess);
+ }
+
+ {
+ auto guard = ScopedSetProperty("dalvik.vm.systemservercompilerfilter", "speed-profile");
+ // services.jar has a profile, while location.provider.jar does not.
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", location_provider_jar_})),
+ Not(Contains(HasSubstr("--profile-file-fd="))),
+ Contains("--compiler-filter=speed"))))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", services_jar_})),
+ Contains(HasSubstr("--profile-file-fd=")),
+ Contains("--compiler-filter=speed-profile"))))
+ .WillOnce(Return(0));
+ EXPECT_EQ(odrefresh_->Compile(
+ *metrics_, /*compile_boot_extensions=*/{}, /*compile_system_server=*/true),
+ ExitCode::kCompilationSuccess);
+ }
+
+ {
+ auto guard = ScopedSetProperty("dalvik.vm.systemservercompilerfilter", "verify");
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", location_provider_jar_})),
+ Not(Contains(HasSubstr("--profile-file-fd="))),
+ Contains("--compiler-filter=verify"))))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", services_jar_})),
+ Not(Contains(HasSubstr("--profile-file-fd="))),
+ Contains("--compiler-filter=verify"))))
+ .WillOnce(Return(0));
+ EXPECT_EQ(odrefresh_->Compile(
+ *metrics_, /*compile_boot_extensions=*/{}, /*compile_system_server=*/true),
+ ExitCode::kCompilationSuccess);
+ }
}
} // namespace odrefresh
diff --git a/runtime/exec_utils.h b/runtime/exec_utils.h
index 5e22639..e011c82 100644
--- a/runtime/exec_utils.h
+++ b/runtime/exec_utils.h
@@ -37,6 +37,28 @@
/*out*/ bool* timed_out,
/*out*/ std::string* error_msg);
+// A wrapper class to make the functions above mockable.
+class ExecUtils {
+ public:
+ virtual ~ExecUtils() = default;
+
+ virtual bool Exec(std::vector<std::string>& arg_vector, /*out*/ std::string* error_msg) const {
+ return art::Exec(arg_vector, error_msg);
+ }
+
+ virtual int ExecAndReturnCode(std::vector<std::string>& arg_vector,
+ /*out*/ std::string* error_msg) const {
+ return art::ExecAndReturnCode(arg_vector, error_msg);
+ }
+
+ virtual int ExecAndReturnCode(std::vector<std::string>& arg_vector,
+ time_t timeout_secs,
+ /*out*/ bool* timed_out,
+ /*out*/ std::string* error_msg) const {
+ return art::ExecAndReturnCode(arg_vector, timeout_secs, timed_out, error_msg);
+ }
+};
+
} // namespace art
#endif // ART_RUNTIME_EXEC_UTILS_H_