summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Martin Stjernholm <mast@google.com> 2024-08-23 23:59:56 +0100
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-08-29 19:54:54 +0000
commit4809d2fceecbfeb16324ee382587934bb5cc8d69 (patch)
treeb59bb076a85dd47dcbc7a4f777187cc4ade10105
parente40d236781908dc7b63368f57f0adca2d475ede0 (diff)
Fix error propagation from dex2oat command execution in tests.
There's no magic to report assertion errors just by creating ::testing::AssertionFailure objects - they have to be returned and checked. Fix that by using Result wrappers. Add the libgmock dependency to art_dex2oat_tests_defaults, because it's necessary for the macros in android-base/result-gmock.h but libbase doesn't pull it in. #codehealth Test: atest art_standalone_dex2oat_cts_tests \ art_standalone_dex2oat_tests Bug: 360737799 Change-Id: I3ca73c5ee625ff09329bb36272d3a654c719768f
-rw-r--r--dex2oat/Android.bp1
-rw-r--r--dex2oat/dex2oat_cts_test.cc30
-rw-r--r--dex2oat/dex2oat_test.cc236
-rw-r--r--dex2oat/dex2oat_vdex_test.cc83
-rw-r--r--runtime/dex2oat_environment_test.h29
5 files changed, 198 insertions, 181 deletions
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 25125fee38..84eb7a529b 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -519,6 +519,7 @@ art_cc_defaults {
],
static_libs: [
"libcrypto_for_art",
+ "libgmock",
"liblz4", // libart(d)-dex2oat dependency; must be repeated here since it's a static lib.
],
}
diff --git a/dex2oat/dex2oat_cts_test.cc b/dex2oat/dex2oat_cts_test.cc
index 0143fa6d72..63a7fea59e 100644
--- a/dex2oat/dex2oat_cts_test.cc
+++ b/dex2oat/dex2oat_cts_test.cc
@@ -14,11 +14,19 @@
* limitations under the License.
*/
+#include <sys/wait.h>
+
+#include "android-base/result-gmock.h"
+#include "android-base/result.h"
+#include "android-base/strings.h"
#include "base/file_utils.h"
#include "dex2oat_environment_test.h"
namespace art {
+using ::android::base::Result;
+using ::android::base::testing::HasValue;
+
// Test the binary with the same bitness as the test. This is also done to avoid
// the symlink /apex/com.android.art/bin/dex2oat, which we don't have selinux
// permission to read on S.
@@ -43,9 +51,7 @@ class Dex2oatCtsTest : public CommonArtTest, public Dex2oatScratchDirs {
protected:
// Stripped down counterpart to Dex2oatEnvironmentTest::Dex2Oat that only adds
// enough arguments for our purposes.
- int Dex2Oat(const std::vector<std::string>& dex2oat_args,
- std::string* output,
- std::string* error_msg) {
+ Result<int> Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* output) {
std::vector<std::string> argv = {std::string(kAndroidArtApexDefaultPath) + "/bin/" +
kDex2oatBinary};
argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end());
@@ -57,18 +63,20 @@ class Dex2oatCtsTest : public CommonArtTest, public Dex2oatScratchDirs {
// We need dex2oat to actually log things.
auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:d", 1) == 0; };
+
ForkAndExecResult res = ForkAndExec(argv, post_fork_fn, output);
if (res.stage != ForkAndExecResult::kFinished) {
- *error_msg = strerror(errno);
- ::testing::AssertionFailure() << "Failed to finish dex2oat invocation: " << *error_msg;
+ return ErrnoErrorf("Failed to finish dex2oat invocation '{}'",
+ android::base::Join(argv, ' '));
}
- if (!res.StandardSuccess()) {
- // We cannot use ASSERT_TRUE since the method returns an int and not void.
- ::testing::AssertionFailure() << "dex2oat fork/exec failed: " << *error_msg;
+ if (!WIFEXITED(res.status_code)) {
+ return Errorf("dex2oat didn't terminate normally (status_code={:#x}): {}",
+ res.status_code,
+ android::base::Join(argv, ' '));
}
- return res.status_code;
+ return WEXITSTATUS(res.status_code);
}
};
@@ -94,9 +102,7 @@ TEST_F(Dex2oatCtsTest, CompilationHooks) {
args.emplace_back("--force-palette-compilation-hooks");
std::string output = "";
- std::string error_msg;
- int res = Dex2Oat(args, &output, &error_msg);
- EXPECT_EQ(res, 0) << error_msg;
+ EXPECT_THAT(Dex2Oat(args, &output), HasValue(0));
EXPECT_EQ(oat_file->FlushCloseOrErase(), 0);
EXPECT_EQ(vdex_file->FlushCloseOrErase(), 0);
}
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 3956608086..05af1d1b7e 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -27,6 +27,8 @@
#include "android-base/logging.h"
#include "android-base/macros.h"
+#include "android-base/result-gmock.h"
+#include "android-base/result.h"
#include "android-base/stringprintf.h"
#include "arch/instruction_set_features.h"
#include "base/macros.h"
@@ -54,7 +56,15 @@
namespace art {
-using android::base::StringPrintf;
+using ::android::base::Result;
+using ::android::base::StringPrintf;
+using ::android::base::testing::HasValue;
+using ::android::base::testing::Ok;
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+using ::testing::Ne;
+using ::testing::Not;
class Dex2oatTest : public Dex2oatEnvironmentTest {
public:
@@ -62,16 +72,14 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
Dex2oatEnvironmentTest::TearDown();
output_ = "";
- error_msg_ = "";
}
protected:
- int GenerateOdexForTestWithStatus(const std::vector<std::string>& dex_locations,
- const std::string& odex_location,
- CompilerFilter::Filter filter,
- std::string* error_msg,
- const std::vector<std::string>& extra_args = {},
- bool use_fd = false) {
+ Result<int> GenerateOdexForTestWithStatus(const std::vector<std::string>& dex_locations,
+ const std::string& odex_location,
+ CompilerFilter::Filter filter,
+ const std::vector<std::string>& extra_args = {},
+ bool use_fd = false) {
std::unique_ptr<File> oat_file;
std::vector<std::string> args;
args.reserve(dex_locations.size() + extra_args.size() + 6);
@@ -81,7 +89,9 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
}
if (use_fd) {
oat_file.reset(OS::CreateEmptyFile(odex_location.c_str()));
- CHECK(oat_file != nullptr) << odex_location;
+ if (oat_file == nullptr) {
+ return ErrnoErrorf("CreateEmptyFile failed on {}", odex_location);
+ }
args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
args.push_back("--oat-location=" + odex_location);
} else {
@@ -97,20 +107,24 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
args.insert(args.end(), extra_args.begin(), extra_args.end());
- int status = Dex2Oat(args, &output_, error_msg);
+ int status = OR_RETURN(Dex2Oat(args, &output_));
if (oat_file != nullptr) {
- CHECK_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file";
+ int fc_errno = oat_file->FlushClose();
+ if (fc_errno != 0) {
+ return Errorf(
+ "Could not flush and close oat file {}: {}", odex_location, strerror(-fc_errno));
+ }
}
return status;
}
- ::testing::AssertionResult GenerateOdexForTest(const std::string& dex_location,
- const std::string& odex_location,
- CompilerFilter::Filter filter,
- const std::vector<std::string>& extra_args = {},
- bool expect_success = true,
- bool use_fd = false,
- bool use_zip_fd = false) WARN_UNUSED {
+ AssertionResult GenerateOdexForTest(const std::string& dex_location,
+ const std::string& odex_location,
+ CompilerFilter::Filter filter,
+ const std::vector<std::string>& extra_args = {},
+ bool expect_success = true,
+ bool use_fd = false,
+ bool use_zip_fd = false) WARN_UNUSED {
return GenerateOdexForTest(dex_location,
odex_location,
filter,
@@ -124,14 +138,14 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
bool test_accepts_odex_file_on_failure = false;
template <typename T>
- ::testing::AssertionResult GenerateOdexForTest(const std::string& dex_location,
- const std::string& odex_location,
- CompilerFilter::Filter filter,
- const std::vector<std::string>& extra_args,
- bool expect_success,
- bool use_fd,
- bool use_zip_fd,
- T check_oat) WARN_UNUSED {
+ AssertionResult GenerateOdexForTest(const std::string& dex_location,
+ const std::string& odex_location,
+ CompilerFilter::Filter filter,
+ const std::vector<std::string>& extra_args,
+ bool expect_success,
+ bool use_fd,
+ bool use_zip_fd,
+ T check_oat) WARN_UNUSED {
std::vector<std::string> dex_locations;
if (use_zip_fd) {
std::string loc_arg = "--zip-location=" + dex_location;
@@ -144,17 +158,21 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
} else {
dex_locations.push_back(dex_location);
}
- std::string error_msg;
- int status = GenerateOdexForTestWithStatus(
- dex_locations, odex_location, filter, &error_msg, extra_args, use_fd);
- bool success = (WIFEXITED(status) && WEXITSTATUS(status) == 0);
+
+ int status = UNWRAP_OR_DO(
+ res,
+ GenerateOdexForTestWithStatus(dex_locations, odex_location, filter, extra_args, use_fd),
+ { return AssertionFailure() << res.error(); });
+
+ bool success = status == 0;
if (expect_success) {
if (!success) {
- return ::testing::AssertionFailure() << "Failed to compile odex: " << error_msg << std::endl
- << output_;
+ return AssertionFailure() << "Failed to compile odex (status=" << status
+ << "): " << output_;
}
// Verify the odex file was generated as expected.
+ std::string error_msg;
std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
odex_location,
odex_location,
@@ -163,20 +181,19 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
dex_location,
&error_msg));
if (odex_file == nullptr) {
- return ::testing::AssertionFailure() << "Could not open odex file: " << error_msg;
+ return AssertionFailure() << "Could not open odex file: " << error_msg;
}
CheckFilter(filter, odex_file->GetCompilerFilter());
check_oat(*(odex_file.get()));
} else {
if (success) {
- return ::testing::AssertionFailure() << "Succeeded to compile odex: " << output_;
+ return AssertionFailure() << "Succeeded to compile odex: " << output_;
}
- error_msg_ = error_msg;
-
if (!test_accepts_odex_file_on_failure) {
// Verify there's no loadable odex file.
+ std::string error_msg;
std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/-1,
odex_location,
odex_location,
@@ -185,11 +202,11 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
dex_location,
&error_msg));
if (odex_file != nullptr) {
- return ::testing::AssertionFailure() << "Could open odex file: " << error_msg;
+ return AssertionFailure() << "Could open odex file: " << error_msg;
}
}
}
- return ::testing::AssertionSuccess();
+ return AssertionSuccess();
}
// Check the input compiler filter against the generated oat file's filter. May be overridden
@@ -199,7 +216,6 @@ class Dex2oatTest : public Dex2oatEnvironmentTest {
}
std::string output_ = "";
- std::string error_msg_ = "";
};
// This test class provides an easy way to validate an expected filter which is different
@@ -1023,7 +1039,6 @@ class Dex2oatClassLoaderContextTest : public Dex2oatTest {
Copy(use_second_source ? GetDexSrc2() : GetDexSrc1(), dex_location);
- std::string error_msg;
std::vector<std::string> extra_args;
if (class_loader_context != nullptr) {
extra_args.push_back(std::string("--class-loader-context=") + class_loader_context);
@@ -1179,18 +1194,15 @@ TEST_F(Dex2oatDeterminism, UnloadCompile) {
const std::string unload_vdex_name = out_dir + "/unload.vdex";
const std::string no_unload_oat_name = out_dir + "/nounload.oat";
const std::string no_unload_vdex_name = out_dir + "/nounload.vdex";
- std::string error_msg;
const std::vector<gc::space::ImageSpace*>& spaces = runtime->GetHeap()->GetBootImageSpaces();
ASSERT_GT(spaces.size(), 0u);
const std::string image_location = spaces[0]->GetImageLocation();
// Without passing in an app image, it will unload in between compilations.
- const int res =
- GenerateOdexForTestWithStatus(GetLibCoreDexFileNames(),
- base_oat_name,
- CompilerFilter::Filter::kVerify,
- &error_msg,
- {"--force-determinism", "--avoid-storing-invocation"});
- ASSERT_EQ(res, 0);
+ ASSERT_THAT(GenerateOdexForTestWithStatus(GetLibCoreDexFileNames(),
+ base_oat_name,
+ CompilerFilter::Filter::kVerify,
+ {"--force-determinism", "--avoid-storing-invocation"}),
+ HasValue(0));
Copy(base_oat_name, unload_oat_name);
Copy(base_vdex_name, unload_vdex_name);
std::unique_ptr<File> unload_oat(OS::OpenFileForReading(unload_oat_name.c_str()));
@@ -1201,13 +1213,12 @@ TEST_F(Dex2oatDeterminism, UnloadCompile) {
EXPECT_GT(unload_vdex->GetLength(), 0u);
// Regenerate with an app image to disable the dex2oat unloading and verify that the output is
// the same.
- const int res2 = GenerateOdexForTestWithStatus(
- GetLibCoreDexFileNames(),
- base_oat_name,
- CompilerFilter::Filter::kVerify,
- &error_msg,
- {"--force-determinism", "--avoid-storing-invocation", "--compile-individually"});
- ASSERT_EQ(res2, 0);
+ ASSERT_THAT(GenerateOdexForTestWithStatus(
+ GetLibCoreDexFileNames(),
+ base_oat_name,
+ CompilerFilter::Filter::kVerify,
+ {"--force-determinism", "--avoid-storing-invocation", "--compile-individually"}),
+ HasValue(0));
Copy(base_oat_name, no_unload_oat_name);
Copy(base_vdex_name, no_unload_vdex_name);
std::unique_ptr<File> no_unload_oat(OS::OpenFileForReading(no_unload_oat_name.c_str()));
@@ -1232,20 +1243,18 @@ TEST_F(Dex2oatVerifierAbort, HardFail) {
std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDeps"));
std::string out_dir = GetScratchDir();
const std::string base_oat_name = out_dir + "/base.oat";
- std::string error_msg;
- const int res_fail = GenerateOdexForTestWithStatus({dex->GetLocation()},
- base_oat_name,
- CompilerFilter::Filter::kVerify,
- &error_msg,
- {"--abort-on-hard-verifier-error"});
- EXPECT_NE(0, res_fail);
-
- const int res_no_fail = GenerateOdexForTestWithStatus({dex->GetLocation()},
- base_oat_name,
- CompilerFilter::Filter::kVerify,
- &error_msg,
- {"--no-abort-on-hard-verifier-error"});
- EXPECT_EQ(0, res_no_fail);
+
+ EXPECT_THAT(GenerateOdexForTestWithStatus({dex->GetLocation()},
+ base_oat_name,
+ CompilerFilter::Filter::kVerify,
+ {"--abort-on-hard-verifier-error"}),
+ HasValue(Ne(0)));
+
+ EXPECT_THAT(GenerateOdexForTestWithStatus({dex->GetLocation()},
+ base_oat_name,
+ CompilerFilter::Filter::kVerify,
+ {"--no-abort-on-hard-verifier-error"}),
+ HasValue(0));
}
class Dex2oatDedupeCode : public Dex2oatTest {};
@@ -1308,31 +1317,25 @@ TEST_F(Dex2oatTest, MissingBootImageTest) {
TEST_F(Dex2oatTest, EmptyUncompressedDexTest) {
std::string out_dir = GetScratchDir();
const std::string base_oat_name = out_dir + "/base.oat";
- std::string error_msg;
- int status = GenerateOdexForTestWithStatus({GetTestDexFileName("MainEmptyUncompressed")},
- base_oat_name,
- CompilerFilter::Filter::kVerify,
- &error_msg,
- {},
- /*use_fd*/ false);
// Expect to fail with code 1 and not SIGSEGV or SIGABRT.
- ASSERT_TRUE(WIFEXITED(status));
- ASSERT_EQ(WEXITSTATUS(status), 1) << error_msg;
+ EXPECT_THAT(GenerateOdexForTestWithStatus({GetTestDexFileName("MainEmptyUncompressed")},
+ base_oat_name,
+ CompilerFilter::Filter::kVerify,
+ /*extra_args*/ {},
+ /*use_fd*/ false),
+ HasValue(1));
}
TEST_F(Dex2oatTest, EmptyUncompressedAlignedDexTest) {
std::string out_dir = GetScratchDir();
const std::string base_oat_name = out_dir + "/base.oat";
- std::string error_msg;
- int status = GenerateOdexForTestWithStatus({GetTestDexFileName("MainEmptyUncompressedAligned")},
- base_oat_name,
- CompilerFilter::Filter::kVerify,
- &error_msg,
- {},
- /*use_fd*/ false);
// Expect to fail with code 1 and not SIGSEGV or SIGABRT.
- ASSERT_TRUE(WIFEXITED(status));
- ASSERT_EQ(WEXITSTATUS(status), 1) << error_msg;
+ EXPECT_THAT(GenerateOdexForTestWithStatus({GetTestDexFileName("MainEmptyUncompressedAligned")},
+ base_oat_name,
+ CompilerFilter::Filter::kVerify,
+ /*extra_args*/ {},
+ /*use_fd*/ false),
+ HasValue(1));
}
TEST_F(Dex2oatTest, StderrLoggerOutput) {
@@ -1510,10 +1513,10 @@ TEST_F(Dex2oatTest, CompactDexInvalidSource) {
}
const std::string& dex_location = invalid_dex.GetFilename();
const std::string odex_location = GetOdexDir() + "/output.odex";
- std::string error_msg;
- int status = GenerateOdexForTestWithStatus(
- {dex_location}, odex_location, CompilerFilter::kVerify, &error_msg, {});
- ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
+ EXPECT_THAT(GenerateOdexForTestWithStatus(
+ {dex_location}, odex_location, CompilerFilter::kVerify, /*extra_args*/ {}),
+ HasValue(Ne(0)))
+ << " " << output_;
}
// Retain the header magic for the now removed compact dex files.
@@ -1557,22 +1560,20 @@ TEST_F(Dex2oatTest, CompactDexInZip) {
ASSERT_GE(invalid_dex.GetFile()->WriteFully(&header, sizeof(header)), 0);
ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0);
}
- std::string error_msg;
- int status = 0u;
-
- status = GenerateOdexForTestWithStatus({invalid_dex_zip.GetFilename()},
- GetOdexDir() + "/output_apk.odex",
- CompilerFilter::kVerify,
- &error_msg,
- {});
- ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
-
- status = GenerateOdexForTestWithStatus({invalid_dex.GetFilename()},
- GetOdexDir() + "/output.odex",
- CompilerFilter::kVerify,
- &error_msg,
- {});
- ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_;
+
+ EXPECT_THAT(GenerateOdexForTestWithStatus({invalid_dex_zip.GetFilename()},
+ GetOdexDir() + "/output_apk.odex",
+ CompilerFilter::kVerify,
+ /*extra_args*/ {}),
+ HasValue(Ne(0)))
+ << " " << output_;
+
+ EXPECT_THAT(GenerateOdexForTestWithStatus({invalid_dex.GetFilename()},
+ GetOdexDir() + "/output.odex",
+ CompilerFilter::kVerify,
+ /*extra_args*/ {}),
+ HasValue(Ne(0)))
+ << " " << output_;
}
TEST_F(Dex2oatWithExpectedFilterTest, AppImageNoProfile) {
@@ -1962,21 +1963,18 @@ TEST_F(LinkageTest, LinkageEnabled) {
std::unique_ptr<const DexFile> dex(OpenTestDexFile("LinkageTest"));
std::string out_dir = GetScratchDir();
const std::string base_oat_name = out_dir + "/base.oat";
- std::string error_msg;
- const int res_fail =
+ EXPECT_THAT(
GenerateOdexForTestWithStatus({dex->GetLocation()},
base_oat_name,
CompilerFilter::Filter::kSpeed,
- &error_msg,
- {"--check-linkage-conditions", "--crash-on-linkage-violation"});
- EXPECT_NE(0, res_fail);
-
- const int res_no_fail = GenerateOdexForTestWithStatus({dex->GetLocation()},
- base_oat_name,
- CompilerFilter::Filter::kSpeed,
- &error_msg,
- {"--check-linkage-conditions"});
- EXPECT_EQ(0, res_no_fail);
+ {"--check-linkage-conditions", "--crash-on-linkage-violation"}),
+ Not(Ok()));
+
+ EXPECT_THAT(GenerateOdexForTestWithStatus({dex->GetLocation()},
+ base_oat_name,
+ CompilerFilter::Filter::kSpeed,
+ {"--check-linkage-conditions"}),
+ HasValue(0));
}
// Regression test for bug 179221298.
diff --git a/dex2oat/dex2oat_vdex_test.cc b/dex2oat/dex2oat_vdex_test.cc
index 27fcc180a5..afea20cadf 100644
--- a/dex2oat/dex2oat_vdex_test.cc
+++ b/dex2oat/dex2oat_vdex_test.cc
@@ -17,6 +17,8 @@
#include <string>
#include <vector>
+#include "android-base/result-gmock.h"
+#include "android-base/result.h"
#include "common_runtime_test.h"
#include "dex2oat_environment_test.h"
#include "vdex_file.h"
@@ -24,6 +26,8 @@
namespace art {
+using ::android::base::Result;
+using ::android::base::testing::HasValue;
using verifier::VerifierDeps;
class Dex2oatVdexTest : public Dex2oatEnvironmentTest {
@@ -32,16 +36,15 @@ class Dex2oatVdexTest : public Dex2oatEnvironmentTest {
Dex2oatEnvironmentTest::TearDown();
output_ = "";
- error_msg_ = "";
opened_vdex_files_.clear();
}
protected:
- bool RunDex2oat(const std::string& dex_location,
- const std::string& odex_location,
- const std::string* public_sdk,
- bool copy_dex_files = false,
- const std::vector<std::string>& extra_args = {}) {
+ Result<bool> RunDex2oat(const std::string& dex_location,
+ const std::string& odex_location,
+ const std::string* public_sdk,
+ bool copy_dex_files = false,
+ const std::vector<std::string>& extra_args = {}) {
std::vector<std::string> args;
args.push_back("--dex-file=" + dex_location);
args.push_back("--oat-file=" + odex_location);
@@ -62,25 +65,27 @@ class Dex2oatVdexTest : public Dex2oatEnvironmentTest {
args.insert(args.end(), extra_args.begin(), extra_args.end());
- return Dex2Oat(args, &output_, &error_msg_) == 0;
+ int status = OR_RETURN(Dex2Oat(args, &output_));
+ return status == 0;
}
- std::unique_ptr<VerifierDeps> GetVerifierDeps(const std::string& vdex_location,
- const DexFile* dex_file) {
+ Result<std::unique_ptr<VerifierDeps>> GetVerifierDeps(const std::string& vdex_location,
+ const DexFile* dex_file) {
// Verify the vdex file content: only the classes using public APIs should be verified.
+ std::string error_msg;
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location,
/*writable=*/false,
/*low_4gb=*/false,
- &error_msg_));
+ &error_msg));
// Check the vdex doesn't have dex.
if (vdex->HasDexSection()) {
- ::testing::AssertionFailure() << "The vdex should not contain dex code";
+ return Errorf("The vdex {} should not contain dex code", vdex_location);
}
// Verify the deps.
VdexFile::VdexFileHeader vdex_header = vdex->GetVdexFileHeader();
if (!vdex_header.IsValid()) {
- ::testing::AssertionFailure() << "Invalid vdex header";
+ return Errorf("Invalid vdex header in {}", vdex_location);
}
std::vector<const DexFile*> dex_files;
@@ -88,7 +93,7 @@ class Dex2oatVdexTest : public Dex2oatEnvironmentTest {
std::unique_ptr<VerifierDeps> deps(new VerifierDeps(dex_files, /*output_only=*/false));
if (!deps->ParseStoredData(dex_files, vdex->GetVerifierDepsData())) {
- ::testing::AssertionFailure() << error_msg_;
+ return Errorf("{}", error_msg);
}
opened_vdex_files_.push_back(std::move(vdex));
@@ -131,7 +136,6 @@ class Dex2oatVdexTest : public Dex2oatEnvironmentTest {
}
std::string output_;
- std::string error_msg_;
std::vector<std::unique_ptr<VdexFile>> opened_vdex_files_;
};
@@ -139,17 +143,17 @@ class Dex2oatVdexTest : public Dex2oatEnvironmentTest {
// - create a vdex file contraints by a predefined list of public API (passed as separate dex)
// - compile with the above vdex file as input to validate the compilation flow
TEST_F(Dex2oatVdexTest, VerifyPublicSdkStubs) {
- std::string error_msg;
-
// Dex2oatVdexTestDex is the subject app using normal APIs found in the boot classpath.
std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Dex2oatVdexTestDex"));
// Dex2oatVdexPublicSdkDex serves as the public API-stubs, restricting what can be verified.
const std::string api_dex_location = GetTestDexFileName("Dex2oatVdexPublicSdkDex");
// Compile the subject app using the predefined API-stubs
- ASSERT_TRUE(RunDex2oat(dex_file->GetLocation(), GetOdex(dex_file), &api_dex_location));
+ ASSERT_THAT(RunDex2oat(dex_file->GetLocation(), GetOdex(dex_file), &api_dex_location),
+ HasValue(true));
- std::unique_ptr<VerifierDeps> deps = GetVerifierDeps(GetVdex(dex_file), dex_file.get());
+ std::unique_ptr<VerifierDeps> deps =
+ OR_ASSERT_FAIL(GetVerifierDeps(GetVdex(dex_file), dex_file.get()));
// Verify public API usage. The classes should be verified.
ASSERT_TRUE(HasVerifiedClass(deps, "LAccessPublicCtor;", *dex_file));
@@ -175,9 +179,11 @@ TEST_F(Dex2oatVdexTest, VerifyPublicSdkStubs) {
std::vector<std::string> extra_args;
extra_args.push_back("--dm-file=" + dm_file);
output_ = "";
- ASSERT_TRUE(RunDex2oat(dex_file->GetLocation(), GetOdex(dex_file), nullptr, false, extra_args));
+ ASSERT_THAT(RunDex2oat(dex_file->GetLocation(), GetOdex(dex_file), nullptr, false, extra_args),
+ HasValue(true));
- std::unique_ptr<VerifierDeps> deps2 = GetVerifierDeps(GetVdex(dex_file), dex_file.get());
+ std::unique_ptr<VerifierDeps> deps2 =
+ OR_ASSERT_FAIL(GetVerifierDeps(GetVdex(dex_file), dex_file.get()));
ASSERT_TRUE(HasVerifiedClass(deps2, "LAccessPublicCtor;", *dex_file));
ASSERT_TRUE(HasVerifiedClass(deps2, "LAccessPublicMethod;", *dex_file));
@@ -194,16 +200,15 @@ TEST_F(Dex2oatVdexTest, VerifyPublicSdkStubs) {
// Check that if the input dm does contain dex files then the compilation fails
TEST_F(Dex2oatVdexTest, VerifyPublicSdkStubsWithDexFiles) {
- std::string error_msg;
-
// Dex2oatVdexTestDex is the subject app using normal APIs found in the boot classpath.
std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Dex2oatVdexTestDex"));
// Compile the subject app using the predefined API-stubs
- ASSERT_TRUE(RunDex2oat(dex_file->GetLocation(),
+ ASSERT_THAT(RunDex2oat(dex_file->GetLocation(),
GetOdex(dex_file),
/*public_sdk=*/nullptr,
- /*copy_dex_files=*/true));
+ /*copy_dex_files=*/true),
+ HasValue(true));
// Create the .dm file with the output.
std::string dm_file = GetScratchDir() + "/base.dm";
@@ -213,17 +218,16 @@ TEST_F(Dex2oatVdexTest, VerifyPublicSdkStubsWithDexFiles) {
// Recompile again with the .dm file which contains a vdex with code.
// The compilation will pass, but dex2oat will not use the vdex file.
- ASSERT_TRUE(RunDex2oat(dex_file->GetLocation(),
+ ASSERT_THAT(RunDex2oat(dex_file->GetLocation(),
GetOdex(dex_file, "v2"),
/*public_sdk=*/nullptr,
/*copy_dex_files=*/true,
- extra_args));
+ extra_args),
+ HasValue(true));
}
// Check that corrupt vdex files from .dm archives are ignored.
TEST_F(Dex2oatVdexTest, VerifyCorruptVdexFile) {
- std::string error_msg;
-
// Dex2oatVdexTestDex is the subject app using normal APIs found in the boot classpath.
std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Dex2oatVdexTestDex"));
@@ -236,25 +240,25 @@ TEST_F(Dex2oatVdexTest, VerifyCorruptVdexFile) {
extra_args.push_back("--dm-file=" + dm_file);
// Compile the dex file. Despite having a corrupt input .vdex, we should not crash.
- ASSERT_TRUE(RunDex2oat(dex_file->GetLocation(),
+ ASSERT_THAT(RunDex2oat(dex_file->GetLocation(),
GetOdex(dex_file),
/*public_sdk=*/nullptr,
/*copy_dex_files=*/true,
- extra_args))
+ extra_args),
+ HasValue(true))
<< output_;
}
// Check that if the input dm a vdex with mismatching checksums the compilation fails
TEST_F(Dex2oatVdexTest, VerifyInputDmWithMismatchedChecksums) {
- std::string error_msg;
-
// Generate a vdex file for Dex2oatVdexTestDex.
std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Dex2oatVdexTestDex"));
- ASSERT_TRUE(RunDex2oat(dex_file->GetLocation(),
+ ASSERT_THAT(RunDex2oat(dex_file->GetLocation(),
GetOdex(dex_file),
/*public_sdk=*/nullptr,
- /*copy_dex_files=*/false));
+ /*copy_dex_files=*/false),
+ HasValue(true));
// Create the .dm file with the output.
std::string dm_file = GetScratchDir() + "/base.dm";
@@ -265,11 +269,12 @@ TEST_F(Dex2oatVdexTest, VerifyInputDmWithMismatchedChecksums) {
// Try to compile Main using an input dm which contains the vdex for
// Dex2oatVdexTestDex. It should fail.
std::unique_ptr<const DexFile> dex_file2(OpenTestDexFile("Main"));
- ASSERT_FALSE(RunDex2oat(dex_file2->GetLocation(),
- GetOdex(dex_file2, "v2"),
- /*public_sdk=*/nullptr,
- /*copy_dex_files=*/false,
- extra_args))
+ ASSERT_THAT(RunDex2oat(dex_file2->GetLocation(),
+ GetOdex(dex_file2, "v2"),
+ /*public_sdk=*/nullptr,
+ /*copy_dex_files=*/false,
+ extra_args),
+ HasValue(false))
<< output_;
}
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index 08b36bbb37..7e8378aa67 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -17,11 +17,15 @@
#ifndef ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
#define ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_
+#include <sys/wait.h>
+
#include <fstream>
#include <optional>
#include <string>
#include <vector>
+#include "android-base/result.h"
+#include "android-base/strings.h"
#include "base/file_utils.h"
#include "base/macros.h"
#include "base/os.h"
@@ -41,6 +45,8 @@
namespace art HIDDEN {
+using ::android::base::Result;
+
static constexpr bool kDebugArgs = false;
class Dex2oatScratchDirs {
@@ -193,12 +199,11 @@ class Dex2oatEnvironmentTest : public Dex2oatScratchDirs, public CommonRuntimeTe
return GetTestDexFileName("Nested");
}
- int Dex2Oat(const std::vector<std::string>& dex2oat_args,
- std::string* output,
- std::string* error_msg) {
+ Result<int> Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* output) {
std::vector<std::string> argv;
- if (!CommonRuntimeTest::StartDex2OatCommandLine(&argv, error_msg)) {
- ::testing::AssertionFailure() << "Could not start dex2oat cmd line " << *error_msg;
+ std::string error_msg;
+ if (!CommonRuntimeTest::StartDex2OatCommandLine(&argv, &error_msg)) {
+ return Errorf("Could not start dex2oat cmd line: {}", error_msg);
}
Runtime* runtime = Runtime::Current();
@@ -235,18 +240,20 @@ class Dex2oatEnvironmentTest : public Dex2oatScratchDirs, public CommonRuntimeTe
// We need dex2oat to actually log things.
auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:d", 1) == 0; };
+
ForkAndExecResult res = ForkAndExec(argv, post_fork_fn, output);
if (res.stage != ForkAndExecResult::kFinished) {
- *error_msg = strerror(errno);
- ::testing::AssertionFailure() << "Failed to finish dex2oat invocation: " << *error_msg;
+ return ErrnoErrorf("Failed to finish dex2oat invocation '{}'",
+ android::base::Join(argv, ' '));
}
- if (!res.StandardSuccess()) {
- // We cannot use ASSERT_TRUE since the method returns an int and not void.
- ::testing::AssertionFailure() << "dex2oat fork/exec failed: " << *error_msg;
+ if (!WIFEXITED(res.status_code)) {
+ return Errorf("dex2oat didn't terminate normally (status_code={:#x}): {}",
+ res.status_code,
+ android::base::Join(argv, ' '));
}
- return res.status_code;
+ return WEXITSTATUS(res.status_code);
}
void CreateDexMetadata(const std::string& vdex, const std::string& out_dm) {