Snap for 4794708 from 8717f7c6f075b7be7bb9669880a07d6592286400 to sdk-release
Change-Id: I7dbfcbee810eef926943c833a721d03ed58f8a5d
diff --git a/Android.bp b/Android.bp
index 1beb3d6..9165626 100644
--- a/Android.bp
+++ b/Android.bp
@@ -17,5 +17,6 @@
"proto",
"compilation_tools",
"runners/target/vts_hal_hidl_target",
+ "testcases",
"utils",
]
diff --git a/OWNERS b/OWNERS
index b9c362e..4fd0eae 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,3 @@
-ryanjcampbell@google.com
-trong@google.com
yim@google.com
yuexima@google.com
zhuoyao@google.com
diff --git a/agents/apps/vts_agent_app/Android.mk b/agents/apps/vts_agent_app/Android.mk
index ee9d4c9..87b7f6d 100644
--- a/agents/apps/vts_agent_app/Android.mk
+++ b/agents/apps/vts_agent_app/Android.mk
@@ -23,6 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := VtsAgentApp
+LOCAL_SDK_VERSION := current
LOCAL_JNI_SHARED_LIBRARIES := \
libvts_agent_app_jni \
diff --git a/agents/hal/BinderClientToDriver.cpp b/agents/hal/BinderClientToDriver.cpp
index 7deb9cb..55b71b8 100644
--- a/agents/hal/BinderClientToDriver.cpp
+++ b/agents/hal/BinderClientToDriver.cpp
@@ -16,9 +16,9 @@
#include <iostream>
-#include <utils/RefBase.h>
#define LOG_TAG "VtsFuzzerBinderClient"
-#include <utils/Log.h>
+#include <log/log.h>
+#include <utils/RefBase.h>
#include <binder/IBinder.h>
#include <binder/IInterface.h>
diff --git a/compilation_tools/vtsc/VtsCompilerUtils.cpp b/compilation_tools/vtsc/VtsCompilerUtils.cpp
index c852f99..286bd1f 100644
--- a/compilation_tools/vtsc/VtsCompilerUtils.cpp
+++ b/compilation_tools/vtsc/VtsCompilerUtils.cpp
@@ -577,6 +577,16 @@
return GetVersionString(message.component_type_version(), for_macro);
}
+int GetMajorVersion(const ComponentSpecificationMessage& message) {
+ string version = GetVersion(message);
+ return stoi(version.substr(0, version.find('.')));
+}
+
+int GetMinorVersion(const ComponentSpecificationMessage& message) {
+ string version = GetVersion(message);
+ return stoi(version.substr(version.find('.') + 1));
+}
+
string GetComponentBaseName(const ComponentSpecificationMessage& message) {
if (!message.component_name().empty()) {
return (message.component_name() == "types"
diff --git a/compilation_tools/vtsc/VtsCompilerUtils.h b/compilation_tools/vtsc/VtsCompilerUtils.h
index a851569..344ce9d 100644
--- a/compilation_tools/vtsc/VtsCompilerUtils.h
+++ b/compilation_tools/vtsc/VtsCompilerUtils.h
@@ -79,6 +79,12 @@
std::string GetVersion(const ComponentSpecificationMessage& message,
bool for_macro = false);
+// Get component major version from the message. e.g. 1.0 -> 1
+int GetMajorVersion(const ComponentSpecificationMessage& message);
+
+// Get component minor version from the message. e.g. 1.0 -> 0
+int GetMinorVersion(const ComponentSpecificationMessage& message);
+
// Get the base name of component from the message. e.g. typs, Foo.
std::string GetComponentBaseName(const ComponentSpecificationMessage& message);
diff --git a/compilation_tools/vtsc/code_gen/driver/DriverCodeGenBase.cpp b/compilation_tools/vtsc/code_gen/driver/DriverCodeGenBase.cpp
index 8aeb78f..fc9e517 100644
--- a/compilation_tools/vtsc/code_gen/driver/DriverCodeGenBase.cpp
+++ b/compilation_tools/vtsc/code_gen/driver/DriverCodeGenBase.cpp
@@ -166,11 +166,16 @@
out << "#include " << header << "\n";
}
out << "\n";
- out << "#include <stdio.h>" << "\n";
- out << "#include <stdarg.h>" << "\n";
- out << "#include <stdlib.h>" << "\n";
- out << "#include <string.h>" << "\n";
- out << "#include <utils/Log.h>" << "\n";
+ out << "#include <log/log.h>"
+ << "\n";
+ out << "#include <stdarg.h>"
+ << "\n";
+ out << "#include <stdio.h>"
+ << "\n";
+ out << "#include <stdlib.h>"
+ << "\n";
+ out << "#include <string.h>"
+ << "\n";
out << "\n";
out << "#include <driver_base/DriverBase.h>"
<< "\n";
diff --git a/compilation_tools/vtsc/code_gen/driver/HalHidlCodeGen.cpp b/compilation_tools/vtsc/code_gen/driver/HalHidlCodeGen.cpp
index 49dc0b1..3b85148 100644
--- a/compilation_tools/vtsc/code_gen/driver/HalHidlCodeGen.cpp
+++ b/compilation_tools/vtsc/code_gen/driver/HalHidlCodeGen.cpp
@@ -527,7 +527,11 @@
out << "#include <hidl/HidlSupport.h>" << "\n";
for (const auto& import : message.import()) {
- FQName import_name = FQName(import);
+ FQName import_name;
+ if (!FQName::parse(import, &import_name)) {
+ abort();
+ }
+
string import_package_name = import_name.package();
string import_package_version = import_name.version();
string import_component_name = import_name.name();
@@ -672,7 +676,7 @@
+ ClearStringWithNameSpaceAccess(attribute.name());
out << "void " << func_name
<< "(const VariableSpecificationMessage& var_msg, " << attribute.name()
- << "* arg);\n";
+ << "* arg, const string& callback_socket_name);\n";
} else if (attribute.type() == TYPE_ENUM) {
string func_name = "EnumValue"
+ ClearStringWithNameSpaceAccess(attribute.name());
@@ -711,9 +715,11 @@
}
string func_name = "MessageTo"
+ ClearStringWithNameSpaceAccess(attribute.name());
- out << "void " << func_name << "(const VariableSpecificationMessage& "
- "var_msg __attribute__((__unused__)), "
- << attribute.name() << "* arg __attribute__((__unused__))) {"
+ out << "void " << func_name
+ << "(const VariableSpecificationMessage& "
+ "var_msg __attribute__((__unused__)), "
+ << attribute.name() << "* arg __attribute__((__unused__)), "
+ << "const string& callback_socket_name __attribute__((__unused__))) {"
<< "\n";
out.indent();
int struct_index = 0;
@@ -737,7 +743,9 @@
+ ClearStringWithNameSpaceAccess(attribute.name());
out << "void " << func_name
<< "(const VariableSpecificationMessage& var_msg, "
- << attribute.name() << "* arg) {" << "\n";
+ << attribute.name() << "* arg, "
+ << "const string& callback_socket_name __attribute__((__unused__))) {"
+ << "\n";
out.indent();
int union_index = 0;
for (const auto& union_value : attribute.union_value()) {
@@ -870,8 +878,8 @@
if (val.has_predefined_type()) {
string func_name = "MessageTo"
+ ClearStringWithNameSpaceAccess(val.predefined_type());
- out << func_name << "(" << arg_value_name << ", &("
- << arg_name << "));\n";
+ out << func_name << "(" << arg_value_name << ", &(" << arg_name
+ << "), callback_socket_name);\n";
} else {
int struct_index = 0;
for (const auto struct_field : val.struct_value()) {
@@ -892,7 +900,7 @@
string func_name = "MessageTo"
+ ClearStringWithNameSpaceAccess(val.predefined_type());
out << func_name << "(" << arg_value_name << ", &(" << arg_name
- << "));\n";
+ << "), callback_socket_name);\n";
} else {
int union_index = 0;
for (const auto union_field : val.union_value()) {
diff --git a/compilation_tools/vtsc/code_gen/profiler/HalHidlProfilerCodeGen.cpp b/compilation_tools/vtsc/code_gen/profiler/HalHidlProfilerCodeGen.cpp
index 7d11ad0..d9e603a 100644
--- a/compilation_tools/vtsc/code_gen/profiler/HalHidlProfilerCodeGen.cpp
+++ b/compilation_tools/vtsc/code_gen/profiler/HalHidlProfilerCodeGen.cpp
@@ -445,7 +445,11 @@
// Include imported classes.
for (const auto& import : message.import()) {
- FQName import_name = FQName(import);
+ FQName import_name;
+ if (!FQName::parse(import, &import_name)) {
+ abort();
+ }
+
string imported_package_name = import_name.package();
string imported_package_version = import_name.version();
string imported_component_name = import_name.name();
@@ -503,11 +507,16 @@
out << "return;\n";
out.unindent();
out << "}\n";
-
- out << "if (strcmp(version, \"" << GetVersion(message) << "\") != 0) {\n";
+ out << "std::string version_str = std::string(version);\n";
+ out << "int major_version = stoi(version_str.substr(0, "
+ "version_str.find('.')));\n";
+ out << "int minor_version = stoi(version_str.substr(version_str.find('.') + "
+ "1));\n";
+ out << "if (major_version != " << GetMajorVersion(message)
+ << " || minor_version > " << GetMinorVersion(message) << ") {\n";
out.indent();
out << "LOG(WARNING) << \"incorrect version. Expect: " << GetVersion(message)
- << " actual: \" << interface;\n";
+ << " or lower (if version != x.0), actual: \" << version;\n";
out << "return;\n";
out.unindent();
out << "}\n";
diff --git a/compilation_tools/vtsc/test/Android.mk b/compilation_tools/vtsc/test/Android.mk
index 136db8c..9d5b82b 100644
--- a/compilation_tools/vtsc/test/Android.mk
+++ b/compilation_tools/vtsc/test/Android.mk
@@ -32,7 +32,7 @@
$(LOCAL_BUILT_MODULE): $(PRIVATE_PY_SCRIPT) $(HOST_OUT_EXECUTABLES)/vtsc
$(LOCAL_BUILT_MODULE): $(PRIVATE_PY_SCRIPT) $(HOST_OUT_EXECUTABLES)/hidl-gen
@echo "Regression test (build time): $(PRIVATE_MODULE)"
- $(hide) PYTHONPATH=$$PYTHONPATH:test \
+ $(hide) PYTHONPATH=$$PYTHONPATH:external/python/futures:test \
python $(PRIVATE_PY_SCRIPT) -h $(PRIVATE_HIDL_EXEC) -p $(PRIVATE_VTSC_EXEC) \
-c $(PRIVATE_CANONICAL_DIR) -o $(PRIVATE_OUT_DIR) -t $(PRIVATE_TEMP_DIR)
$(hide) touch $@
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/Bar.driver.cpp b/compilation_tools/vtsc/test/golden/DRIVER/Bar.driver.cpp
index 576890a..dbd9302 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/Bar.driver.cpp
+++ b/compilation_tools/vtsc/test/golden/DRIVER/Bar.driver.cpp
@@ -10,8 +10,8 @@
using namespace android::hardware::tests::bar::V1_0;
namespace android {
namespace vts {
-void MessageTo__android__hardware__tests__bar__V1_0__IBar__SomethingRelated(const VariableSpecificationMessage& var_msg __attribute__((__unused__)), ::android::hardware::tests::bar::V1_0::IBar::SomethingRelated* arg __attribute__((__unused__))) {
- MessageTo__android__hardware__tests__foo__V1_0__Unrelated(var_msg.struct_value(0), &(arg->myRelated));
+void MessageTo__android__hardware__tests__bar__V1_0__IBar__SomethingRelated(const VariableSpecificationMessage& var_msg __attribute__((__unused__)), ::android::hardware::tests::bar::V1_0::IBar::SomethingRelated* arg __attribute__((__unused__)), const string& callback_socket_name __attribute__((__unused__))) {
+ MessageTo__android__hardware__tests__foo__V1_0__Unrelated(var_msg.struct_value(0), &(arg->myRelated), callback_socket_name);
}
bool Verify__android__hardware__tests__bar__V1_0__IBar__SomethingRelated(const VariableSpecificationMessage& expected_result __attribute__((__unused__)), const VariableSpecificationMessage& actual_result __attribute__((__unused__))){
if (!Verify__android__hardware__tests__foo__V1_0__Unrelated(expected_result.struct_value(0), actual_result.struct_value(0))) { return false; }
@@ -45,6 +45,29 @@
}
+::android::hardware::Return<void> Vts_android_hardware_tests_bar_V1_0_IBar::convertToBoolIfSmall(
+ ::android::hardware::tests::foo::V1_0::IFoo::Discriminator arg0 __attribute__((__unused__)),
+ const ::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::Union>& arg1 __attribute__((__unused__)), std::function<void(const ::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::ContainsUnion>& arg0)> cb) {
+ LOG(INFO) << "convertToBoolIfSmall called";
+ AndroidSystemCallbackRequestMessage callback_message;
+ callback_message.set_id(GetCallbackID("convertToBoolIfSmall"));
+ callback_message.set_name("Vts_android_hardware_tests_bar_V1_0_IBar::convertToBoolIfSmall");
+ VariableSpecificationMessage* var_msg0 = callback_message.add_arg();
+ var_msg0->set_type(TYPE_ENUM);
+ SetResult__android__hardware__tests__foo__V1_0__IFoo__Discriminator(var_msg0, arg0);
+ VariableSpecificationMessage* var_msg1 = callback_message.add_arg();
+ var_msg1->set_type(TYPE_VECTOR);
+ var_msg1->set_vector_size(arg1.size());
+ for (int i = 0; i < (int)arg1.size(); i++) {
+ auto *var_msg1_vector_i = var_msg1->add_vector_value();
+ var_msg1_vector_i->set_type(TYPE_UNION);
+ SetResult__android__hardware__tests__foo__V1_0__IFoo__Union(var_msg1_vector_i, arg1[i]);
+ }
+ RpcCallToAgent(callback_message, callback_socket_name_);
+ cb(::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::ContainsUnion>());
+ return ::android::hardware::Void();
+}
+
::android::hardware::Return<void> Vts_android_hardware_tests_bar_V1_0_IBar::doThis(
float arg0 __attribute__((__unused__))) {
LOG(INFO) << "doThis called";
@@ -623,6 +646,31 @@
LOG(ERROR) << "hw_binder_proxy_ is null. ";
return false;
}
+ if (!strcmp(func_name, "convertToBoolIfSmall")) {
+ ::android::hardware::tests::foo::V1_0::IFoo::Discriminator arg0;
+ arg0 = EnumValue__android__hardware__tests__foo__V1_0__IFoo__Discriminator(func_msg.arg(0).scalar_value());
+ ::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::Union> arg1;
+ arg1.resize(func_msg.arg(1).vector_value_size());
+ for (int arg1_index = 0; arg1_index < func_msg.arg(1).vector_value_size(); arg1_index++) {
+ MessageTo__android__hardware__tests__foo__V1_0__IFoo__Union(func_msg.arg(1).vector_value(arg1_index), &(arg1[arg1_index]), callback_socket_name);
+ }
+ LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
+ ::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::ContainsUnion> result0;
+ hw_binder_proxy_->convertToBoolIfSmall(arg0, arg1, [&](const ::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::ContainsUnion>& arg0){
+ LOG(INFO) << "callback convertToBoolIfSmall called";
+ result0 = arg0;
+ });
+ result_msg->set_name("convertToBoolIfSmall");
+ VariableSpecificationMessage* result_val_0 = result_msg->add_return_type_hidl();
+ result_val_0->set_type(TYPE_VECTOR);
+ result_val_0->set_vector_size(result0.size());
+ for (int i = 0; i < (int)result0.size(); i++) {
+ auto *result_val_0_vector_i = result_val_0->add_vector_value();
+ result_val_0_vector_i->set_type(TYPE_STRUCT);
+ SetResult__android__hardware__tests__foo__V1_0__IFoo__ContainsUnion(result_val_0_vector_i, result0[i]);
+ }
+ return true;
+ }
if (!strcmp(func_name, "doThis")) {
float arg0 = 0;
arg0 = func_msg.arg(0).scalar_value().float_t();
@@ -749,7 +797,7 @@
::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::Goober> arg0;
arg0.resize(func_msg.arg(0).vector_value_size());
for (int arg0_index = 0; arg0_index < func_msg.arg(0).vector_value_size(); arg0_index++) {
- MessageTo__android__hardware__tests__foo__V1_0__IFoo__Goober(func_msg.arg(0).vector_value(arg0_index), &(arg0[arg0_index]));
+ MessageTo__android__hardware__tests__foo__V1_0__IFoo__Goober(func_msg.arg(0).vector_value(arg0_index), &(arg0[arg0_index]), callback_socket_name);
}
LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
hw_binder_proxy_->haveAGooberVec(arg0);
@@ -758,7 +806,7 @@
}
if (!strcmp(func_name, "haveAGoober")) {
::android::hardware::tests::foo::V1_0::IFoo::Goober arg0;
- MessageTo__android__hardware__tests__foo__V1_0__IFoo__Goober(func_msg.arg(0), &(arg0));
+ MessageTo__android__hardware__tests__foo__V1_0__IFoo__Goober(func_msg.arg(0), &(arg0), callback_socket_name);
LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
hw_binder_proxy_->haveAGoober(arg0);
result_msg->set_name("haveAGoober");
@@ -773,8 +821,8 @@
for (int arg0_arg0_index__numbers_index = 0; arg0_arg0_index__numbers_index < func_msg.arg(0).vector_value(arg0_index).struct_value(3).vector_value_size(); arg0_arg0_index__numbers_index++) {
arg0[arg0_index].numbers[arg0_arg0_index__numbers_index] = func_msg.arg(0).vector_value(arg0_index).struct_value(3).vector_value(arg0_arg0_index__numbers_index).scalar_value().double_t();
}
- MessageTo__android__hardware__tests__foo__V1_0__IFoo__Fumble(func_msg.arg(0).vector_value(arg0_index).struct_value(4), &(arg0[arg0_index].fumble));
- MessageTo__android__hardware__tests__foo__V1_0__IFoo__Fumble(func_msg.arg(0).vector_value(arg0_index).struct_value(5), &(arg0[arg0_index].gumble));
+ MessageTo__android__hardware__tests__foo__V1_0__IFoo__Fumble(func_msg.arg(0).vector_value(arg0_index).struct_value(4), &(arg0[arg0_index].fumble), callback_socket_name);
+ MessageTo__android__hardware__tests__foo__V1_0__IFoo__Fumble(func_msg.arg(0).vector_value(arg0_index).struct_value(5), &(arg0[arg0_index].gumble), callback_socket_name);
}
LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
hw_binder_proxy_->haveAGooberArray(arg0);
@@ -783,7 +831,7 @@
}
if (!strcmp(func_name, "haveATypeFromAnotherFile")) {
::android::hardware::tests::foo::V1_0::Abc arg0;
- MessageTo__android__hardware__tests__foo__V1_0__Abc(func_msg.arg(0), &(arg0));
+ MessageTo__android__hardware__tests__foo__V1_0__Abc(func_msg.arg(0), &(arg0), callback_socket_name);
LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
hw_binder_proxy_->haveATypeFromAnotherFile(arg0);
result_msg->set_name("haveATypeFromAnotherFile");
@@ -868,7 +916,7 @@
}
if (!strcmp(func_name, "callingDrWho")) {
::android::hardware::tests::foo::V1_0::IFoo::MultiDimensional arg0;
- MessageTo__android__hardware__tests__foo__V1_0__IFoo__MultiDimensional(func_msg.arg(0), &(arg0));
+ MessageTo__android__hardware__tests__foo__V1_0__IFoo__MultiDimensional(func_msg.arg(0), &(arg0), callback_socket_name);
LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
::android::hardware::tests::foo::V1_0::IFoo::MultiDimensional result0;
hw_binder_proxy_->callingDrWho(arg0, [&](const ::android::hardware::tests::foo::V1_0::IFoo::MultiDimensional& arg0){
@@ -883,7 +931,7 @@
}
if (!strcmp(func_name, "transpose")) {
::android::hardware::tests::foo::V1_0::IFoo::StringMatrix5x3 arg0;
- MessageTo__android__hardware__tests__foo__V1_0__IFoo__StringMatrix5x3(func_msg.arg(0), &(arg0));
+ MessageTo__android__hardware__tests__foo__V1_0__IFoo__StringMatrix5x3(func_msg.arg(0), &(arg0), callback_socket_name);
LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
::android::hardware::tests::foo::V1_0::IFoo::StringMatrix3x5 result0;
hw_binder_proxy_->transpose(arg0, [&](const ::android::hardware::tests::foo::V1_0::IFoo::StringMatrix3x5& arg0){
@@ -1175,7 +1223,7 @@
arg0 = nullptr;
}
::android::hardware::tests::foo::V1_0::Abc arg1;
- MessageTo__android__hardware__tests__foo__V1_0__Abc(func_msg.arg(1), &(arg1));
+ MessageTo__android__hardware__tests__foo__V1_0__Abc(func_msg.arg(1), &(arg1), callback_socket_name);
LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
bool result0;
bool result1;
@@ -1201,7 +1249,7 @@
uint8_t arg1;
arg1 = func_msg.arg(1).scalar_value().uint8_t();
::android::hardware::tests::foo::V1_0::IFoo::MyMask arg2;
- MessageTo__android__hardware__tests__foo__V1_0__IFoo__MyMask(func_msg.arg(2), &(arg2));
+ MessageTo__android__hardware__tests__foo__V1_0__IFoo__MyMask(func_msg.arg(2), &(arg2), callback_socket_name);
uint8_t arg3;
arg3 = func_msg.arg(3).scalar_value().uint8_t();
LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
@@ -1267,6 +1315,17 @@
bool FuzzerExtended_android_hardware_tests_bar_V1_0_IBar::VerifyResults(const FunctionSpecificationMessage& expected_result __attribute__((__unused__)),
const FunctionSpecificationMessage& actual_result __attribute__((__unused__))) {
+ if (!strcmp(actual_result.name().c_str(), "convertToBoolIfSmall")) {
+ if (actual_result.return_type_hidl_size() != expected_result.return_type_hidl_size() ) { return false; }
+ if (actual_result.return_type_hidl(0).vector_value_size() != expected_result.return_type_hidl(0).vector_value_size()) {
+ LOG(ERROR) << "Verification failed for vector size. expected: " << expected_result.return_type_hidl(0).vector_value_size() << " actual: " << actual_result.return_type_hidl(0).vector_value_size();
+ return false;
+ }
+ for (int i = 0; i <expected_result.return_type_hidl(0).vector_value_size(); i++) {
+ if (!Verify__android__hardware__tests__foo__V1_0__IFoo__ContainsUnion(expected_result.return_type_hidl(0).vector_value(i), actual_result.return_type_hidl(0).vector_value(i))) { return false; }
+ }
+ return true;
+ }
if (!strcmp(actual_result.name().c_str(), "doThis")) {
if (actual_result.return_type_hidl_size() != expected_result.return_type_hidl_size() ) { return false; }
return true;
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/Bar.vts.h b/compilation_tools/vtsc/test/golden/DRIVER/Bar.vts.h
index 9492188..83fdfaf 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/Bar.vts.h
+++ b/compilation_tools/vtsc/test/golden/DRIVER/Bar.vts.h
@@ -4,11 +4,11 @@
#undef LOG_TAG
#define LOG_TAG "FuzzerExtended_android_hardware_tests_bar_V1_0_IBar"
-#include <stdio.h>
+#include <log/log.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <utils/Log.h>
#include <driver_base/DriverBase.h>
#include <driver_base/DriverCallbackBase.h>
@@ -35,7 +35,7 @@
using namespace android::hardware::tests::bar::V1_0;
namespace android {
namespace vts {
-void MessageTo__android__hardware__tests__bar__V1_0__IBar__SomethingRelated(const VariableSpecificationMessage& var_msg, ::android::hardware::tests::bar::V1_0::IBar::SomethingRelated* arg);
+void MessageTo__android__hardware__tests__bar__V1_0__IBar__SomethingRelated(const VariableSpecificationMessage& var_msg, ::android::hardware::tests::bar::V1_0::IBar::SomethingRelated* arg, const string& callback_socket_name);
bool Verify__android__hardware__tests__bar__V1_0__IBar__SomethingRelated(const VariableSpecificationMessage& expected_result, const VariableSpecificationMessage& actual_result);
void SetResult__android__hardware__tests__bar__V1_0__IBar__SomethingRelated(VariableSpecificationMessage* result_msg, ::android::hardware::tests::bar::V1_0::IBar::SomethingRelated result_value);
@@ -46,6 +46,10 @@
virtual ~Vts_android_hardware_tests_bar_V1_0_IBar() = default;
+ ::android::hardware::Return<void> convertToBoolIfSmall(
+ ::android::hardware::tests::foo::V1_0::IFoo::Discriminator arg0,
+ const ::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::Union>& arg1, std::function<void(const ::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::ContainsUnion>& arg0)> cb) override;
+
::android::hardware::Return<void> doThis(
float arg0) override;
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/MemoryTest.driver.cpp b/compilation_tools/vtsc/test/golden/DRIVER/MemoryTest.driver.cpp
index f2b544d..2209b45 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/MemoryTest.driver.cpp
+++ b/compilation_tools/vtsc/test/golden/DRIVER/MemoryTest.driver.cpp
@@ -175,7 +175,7 @@
}
if (!strcmp(func_name, "haveSomeMemoryBlock")) {
::android::hidl::memory::block::V1_0::MemoryBlock arg0;
- MessageTo__android__hidl__memory__block__V1_0__MemoryBlock(func_msg.arg(0), &(arg0));
+ MessageTo__android__hidl__memory__block__V1_0__MemoryBlock(func_msg.arg(0), &(arg0), callback_socket_name);
LOG(DEBUG) << "local_device = " << hw_binder_proxy_.get();
::android::hidl::memory::block::V1_0::MemoryBlock result0;
hw_binder_proxy_->haveSomeMemoryBlock(arg0, [&](const ::android::hidl::memory::block::V1_0::MemoryBlock& arg0){
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/MemoryTest.vts.h b/compilation_tools/vtsc/test/golden/DRIVER/MemoryTest.vts.h
index 747c2e1..6c1bfe6 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/MemoryTest.vts.h
+++ b/compilation_tools/vtsc/test/golden/DRIVER/MemoryTest.vts.h
@@ -4,11 +4,11 @@
#undef LOG_TAG
#define LOG_TAG "FuzzerExtended_android_hardware_tests_memory_V1_0_IMemoryTest"
-#include <stdio.h>
+#include <log/log.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <utils/Log.h>
#include <driver_base/DriverBase.h>
#include <driver_base/DriverCallbackBase.h>
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/Nfc.vts.h b/compilation_tools/vtsc/test/golden/DRIVER/Nfc.vts.h
index 499528b..107ae2d 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/Nfc.vts.h
+++ b/compilation_tools/vtsc/test/golden/DRIVER/Nfc.vts.h
@@ -4,11 +4,11 @@
#undef LOG_TAG
#define LOG_TAG "FuzzerExtended_android_hardware_nfc_V1_0_INfc"
-#include <stdio.h>
+#include <log/log.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <utils/Log.h>
#include <driver_base/DriverBase.h>
#include <driver_base/DriverCallbackBase.h>
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/NfcClientCallback.vts.h b/compilation_tools/vtsc/test/golden/DRIVER/NfcClientCallback.vts.h
index b8457b1..9626955 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/NfcClientCallback.vts.h
+++ b/compilation_tools/vtsc/test/golden/DRIVER/NfcClientCallback.vts.h
@@ -4,11 +4,11 @@
#undef LOG_TAG
#define LOG_TAG "FuzzerExtended_android_hardware_nfc_V1_0_INfcClientCallback"
-#include <stdio.h>
+#include <log/log.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <utils/Log.h>
#include <driver_base/DriverBase.h>
#include <driver_base/DriverCallbackBase.h>
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/TestMsgQ.vts.h b/compilation_tools/vtsc/test/golden/DRIVER/TestMsgQ.vts.h
index 3514a75..15a69da 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/TestMsgQ.vts.h
+++ b/compilation_tools/vtsc/test/golden/DRIVER/TestMsgQ.vts.h
@@ -4,11 +4,11 @@
#undef LOG_TAG
#define LOG_TAG "FuzzerExtended_android_hardware_tests_msgq_V1_0_ITestMsgQ"
-#include <stdio.h>
+#include <log/log.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <utils/Log.h>
#include <driver_base/DriverBase.h>
#include <driver_base/DriverCallbackBase.h>
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/libcV1.driver.cpp b/compilation_tools/vtsc/test/golden/DRIVER/libcV1.driver.cpp
index c5f72d6..49354f2 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/libcV1.driver.cpp
+++ b/compilation_tools/vtsc/test/golden/DRIVER/libcV1.driver.cpp
@@ -5,7 +5,7 @@
#include <linux/socket.h>
#include "vts_datatype.h"
#include "vts_measurement.h"
-#include <iostream>
+#include <android-base/logging.h>
namespace android {
@@ -14,14 +14,14 @@
FunctionSpecificationMessage* func_msg,
void** result, const string& callback_socket_name) {
const char* func_name = func_msg->name().c_str();
- cout << "Function: " << func_name << endl;
+ LOG(INFO) << "Function: " << func_name;
if (!strcmp(func_name, "socket")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
int32_t arg1 = (func_msg->arg(1).type() == TYPE_SCALAR && func_msg->arg(1).scalar_value().has_int32_t()) ? func_msg->arg(1).scalar_value().int32_t() : RandomInt32();
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
int32_t arg2 = (func_msg->arg(2).type() == TYPE_SCALAR && func_msg->arg(2).scalar_value().has_int32_t()) ? func_msg->arg(2).scalar_value().int32_t() : RandomInt32();
- cout << "arg2 = " << arg2 << endl;
+ LOG(INFO) << "arg2 = " << arg2;
typedef void* (*func_type_socket)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_socket) target_loader_.GetLoaderFunction("socket"))(
arg0,
@@ -31,11 +31,11 @@
}
if (!strcmp(func_name, "accept")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
struct sockaddr* arg1 = (struct sockaddr*) malloc(sizeof(struct sockaddr));
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
socklen_t* arg2 = (socklen_t*) malloc(sizeof(socklen_t));
- cout << "arg2 = " << arg2 << endl;
+ LOG(INFO) << "arg2 = " << arg2;
typedef void* (*func_type_accept)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_accept) target_loader_.GetLoaderFunction("accept"))(
arg0,
@@ -45,11 +45,11 @@
}
if (!strcmp(func_name, "bind")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
struct sockaddr* arg1 = (struct sockaddr*) malloc(sizeof(struct sockaddr));
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
socklen_t* arg2 = (socklen_t*) malloc(sizeof(socklen_t));
- cout << "arg2 = " << arg2 << endl;
+ LOG(INFO) << "arg2 = " << arg2;
typedef void* (*func_type_bind)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_bind) target_loader_.GetLoaderFunction("bind"))(
arg0,
@@ -59,11 +59,11 @@
}
if (!strcmp(func_name, "connect")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
struct sockaddr* arg1 = (struct sockaddr*) malloc(sizeof(struct sockaddr));
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
socklen_t* arg2 = (socklen_t*) malloc(sizeof(socklen_t));
- cout << "arg2 = " << arg2 << endl;
+ LOG(INFO) << "arg2 = " << arg2;
typedef void* (*func_type_connect)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_connect) target_loader_.GetLoaderFunction("connect"))(
arg0,
@@ -73,9 +73,9 @@
}
if (!strcmp(func_name, "listen")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
int32_t arg1 = (func_msg->arg(1).type() == TYPE_SCALAR && func_msg->arg(1).scalar_value().has_int32_t()) ? func_msg->arg(1).scalar_value().int32_t() : RandomInt32();
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
typedef void* (*func_type_listen)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_listen) target_loader_.GetLoaderFunction("listen"))(
arg0,
@@ -84,13 +84,13 @@
}
if (!strcmp(func_name, "recv")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
void* arg1 = (func_msg->arg(1).type() == TYPE_SCALAR && func_msg->arg(1).scalar_value().has_void_pointer()) ? reinterpret_cast<void*>(func_msg->arg(1).scalar_value().void_pointer()) : RandomVoidPointer();
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
uint32_t arg2 = (func_msg->arg(2).type() == TYPE_SCALAR && func_msg->arg(2).scalar_value().has_uint32_t()) ? func_msg->arg(2).scalar_value().uint32_t() : RandomUint32();
- cout << "arg2 = " << arg2 << endl;
+ LOG(INFO) << "arg2 = " << arg2;
int32_t arg3 = (func_msg->arg(3).type() == TYPE_SCALAR && func_msg->arg(3).scalar_value().has_int32_t()) ? func_msg->arg(3).scalar_value().int32_t() : RandomInt32();
- cout << "arg3 = " << arg3 << endl;
+ LOG(INFO) << "arg3 = " << arg3;
typedef void* (*func_type_recv)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_recv) target_loader_.GetLoaderFunction("recv"))(
arg0,
@@ -101,13 +101,13 @@
}
if (!strcmp(func_name, "send")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
void* arg1 = (func_msg->arg(1).type() == TYPE_SCALAR && func_msg->arg(1).scalar_value().has_void_pointer()) ? reinterpret_cast<void*>(func_msg->arg(1).scalar_value().void_pointer()) : RandomVoidPointer();
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
uint32_t arg2 = (func_msg->arg(2).type() == TYPE_SCALAR && func_msg->arg(2).scalar_value().has_uint32_t()) ? func_msg->arg(2).scalar_value().uint32_t() : RandomUint32();
- cout << "arg2 = " << arg2 << endl;
+ LOG(INFO) << "arg2 = " << arg2;
int32_t arg3 = (func_msg->arg(3).type() == TYPE_SCALAR && func_msg->arg(3).scalar_value().has_int32_t()) ? func_msg->arg(3).scalar_value().int32_t() : RandomInt32();
- cout << "arg3 = " << arg3 << endl;
+ LOG(INFO) << "arg3 = " << arg3;
typedef void* (*func_type_send)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_send) target_loader_.GetLoaderFunction("send"))(
arg0,
@@ -124,7 +124,7 @@
strcpy(arg0, RandomCharPointer());
}
;
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
char arg1[func_msg->arg(1).string_value().length() + 1];
if (func_msg->arg(1).type() == TYPE_SCALAR && func_msg->arg(1).string_value().has_message()) {
strcpy(arg1, func_msg->arg(1).string_value().message().c_str());
@@ -132,7 +132,7 @@
strcpy(arg1, RandomCharPointer());
}
;
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
typedef void* (*func_type_fopen)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_fopen) target_loader_.GetLoaderFunction("fopen"))(
arg0,
@@ -141,11 +141,11 @@
}
if (!strcmp(func_name, "read")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
void* arg1 = (func_msg->arg(1).type() == TYPE_SCALAR && func_msg->arg(1).scalar_value().has_void_pointer()) ? reinterpret_cast<void*>(func_msg->arg(1).scalar_value().void_pointer()) : RandomVoidPointer();
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
uint32_t arg2 = (func_msg->arg(2).type() == TYPE_SCALAR && func_msg->arg(2).scalar_value().has_uint32_t()) ? func_msg->arg(2).scalar_value().uint32_t() : RandomUint32();
- cout << "arg2 = " << arg2 << endl;
+ LOG(INFO) << "arg2 = " << arg2;
typedef void* (*func_type_read)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_read) target_loader_.GetLoaderFunction("read"))(
arg0,
@@ -155,11 +155,11 @@
}
if (!strcmp(func_name, "write")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
void* arg1 = (func_msg->arg(1).type() == TYPE_SCALAR && func_msg->arg(1).scalar_value().has_void_pointer()) ? reinterpret_cast<void*>(func_msg->arg(1).scalar_value().void_pointer()) : RandomVoidPointer();
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
int32_t arg2 = (func_msg->arg(2).type() == TYPE_SCALAR && func_msg->arg(2).scalar_value().has_int32_t()) ? func_msg->arg(2).scalar_value().int32_t() : RandomInt32();
- cout << "arg2 = " << arg2 << endl;
+ LOG(INFO) << "arg2 = " << arg2;
typedef void* (*func_type_write)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_write) target_loader_.GetLoaderFunction("write"))(
arg0,
@@ -169,11 +169,11 @@
}
if (!strcmp(func_name, "lseek")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
int32_t arg1 = (func_msg->arg(1).type() == TYPE_SCALAR && func_msg->arg(1).scalar_value().has_int32_t()) ? func_msg->arg(1).scalar_value().int32_t() : RandomInt32();
- cout << "arg1 = " << arg1 << endl;
+ LOG(INFO) << "arg1 = " << arg1;
int32_t arg2 = (func_msg->arg(2).type() == TYPE_SCALAR && func_msg->arg(2).scalar_value().has_int32_t()) ? func_msg->arg(2).scalar_value().int32_t() : RandomInt32();
- cout << "arg2 = " << arg2 << endl;
+ LOG(INFO) << "arg2 = " << arg2;
typedef void* (*func_type_lseek)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_lseek) target_loader_.GetLoaderFunction("lseek"))(
arg0,
@@ -183,7 +183,7 @@
}
if (!strcmp(func_name, "close")) {
int32_t arg0 = (func_msg->arg(0).type() == TYPE_SCALAR && func_msg->arg(0).scalar_value().has_int32_t()) ? func_msg->arg(0).scalar_value().int32_t() : RandomInt32();
- cout << "arg0 = " << arg0 << endl;
+ LOG(INFO) << "arg0 = " << arg0;
typedef void* (*func_type_close)(...);
*result = const_cast<void*>(reinterpret_cast<const void*>( ((func_type_close) target_loader_.GetLoaderFunction("close"))(
arg0)));
@@ -195,8 +195,8 @@
FunctionSpecificationMessage* func_msg,
void** result) {
const char* func_name = func_msg->name().c_str();
- cout << "Function: " << __func__ << " '" << func_name << "'" << endl;
- cerr << "attribute not supported for shared lib yet" << endl;
+ LOG(INFO) << " '" << func_name << "'";
+ LOG(ERROR) << "attribute not supported for shared lib yet.";
return false;
}
bool FuzzerExtended_libc::CallFunction(const FunctionSpecificationMessage&, const string&, FunctionSpecificationMessage* ) {
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/test/vts/specification/lib/ndk/bionic/1.0/libcV1.vts.h b/compilation_tools/vtsc/test/golden/DRIVER/test/vts/specification/lib/ndk/bionic/1.0/libcV1.vts.h
index b4bd18f..92fce14 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/test/vts/specification/lib/ndk/bionic/1.0/libcV1.vts.h
+++ b/compilation_tools/vtsc/test/golden/DRIVER/test/vts/specification/lib/ndk/bionic/1.0/libcV1.vts.h
@@ -8,11 +8,11 @@
#include <sys/types.h>
#include <linux/socket.h>
-#include <stdio.h>
+#include <log/log.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <utils/Log.h>
#include <driver_base/DriverBase.h>
#include <driver_base/DriverCallbackBase.h>
diff --git a/compilation_tools/vtsc/test/golden/DRIVER/types.vts.h b/compilation_tools/vtsc/test/golden/DRIVER/types.vts.h
index 18593c5..aa2fe29 100644
--- a/compilation_tools/vtsc/test/golden/DRIVER/types.vts.h
+++ b/compilation_tools/vtsc/test/golden/DRIVER/types.vts.h
@@ -4,11 +4,11 @@
#undef LOG_TAG
#define LOG_TAG "FuzzerExtended_android_hardware_nfc_V1_0_types"
-#include <stdio.h>
+#include <log/log.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <utils/Log.h>
#include <driver_base/DriverBase.h>
#include <driver_base/DriverCallbackBase.h>
diff --git a/compilation_tools/vtsc/test/golden/PROFILER/Bar.profiler.cpp b/compilation_tools/vtsc/test/golden/PROFILER/Bar.profiler.cpp
index bf1e490..981e5b2 100644
--- a/compilation_tools/vtsc/test/golden/PROFILER/Bar.profiler.cpp
+++ b/compilation_tools/vtsc/test/golden/PROFILER/Bar.profiler.cpp
@@ -31,8 +31,11 @@
LOG(WARNING) << "incorrect package. Expect: android.hardware.tests.bar actual: " << package;
return;
}
- if (strcmp(version, "1.0") != 0) {
- LOG(WARNING) << "incorrect version. Expect: 1.0 actual: " << interface;
+ std::string version_str = std::string(version);
+ int major_version = stoi(version_str.substr(0, version_str.find('.')));
+ int minor_version = stoi(version_str.substr(version_str.find('.') + 1));
+ if (major_version != 1 || minor_version > 0) {
+ LOG(WARNING) << "incorrect version. Expect: 1.0 or lower (if version != x.0), actual: " << version;
return;
}
if (strcmp(interface, "IBar") != 0) {
@@ -42,6 +45,76 @@
VtsProfilingInterface& profiler = VtsProfilingInterface::getInstance(TRACEFILEPREFIX);
+ if (strcmp(method, "convertToBoolIfSmall") == 0) {
+ FunctionSpecificationMessage msg;
+ msg.set_name("convertToBoolIfSmall");
+ if (!args) {
+ LOG(WARNING) << "no argument passed";
+ } else {
+ switch (event) {
+ case details::HidlInstrumentor::CLIENT_API_ENTRY:
+ case details::HidlInstrumentor::SERVER_API_ENTRY:
+ case details::HidlInstrumentor::PASSTHROUGH_ENTRY:
+ {
+ if ((*args).size() != 2) {
+ LOG(ERROR) << "Number of arguments does not match. expect: 2, actual: " << (*args).size() << ", method name: convertToBoolIfSmall, event type: " << event;
+ break;
+ }
+ auto *arg_0 __attribute__((__unused__)) = msg.add_arg();
+ ::android::hardware::tests::foo::V1_0::IFoo::Discriminator *arg_val_0 __attribute__((__unused__)) = reinterpret_cast<::android::hardware::tests::foo::V1_0::IFoo::Discriminator*> ((*args)[0]);
+ if (arg_val_0 != nullptr) {
+ arg_0->set_type(TYPE_ENUM);
+ profile____android__hardware__tests__foo__V1_0__IFoo__Discriminator(arg_0, (*arg_val_0));
+ } else {
+ LOG(WARNING) << "argument 0 is null.";
+ }
+ auto *arg_1 __attribute__((__unused__)) = msg.add_arg();
+ ::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::Union> *arg_val_1 __attribute__((__unused__)) = reinterpret_cast<::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::Union>*> ((*args)[1]);
+ if (arg_val_1 != nullptr) {
+ arg_1->set_type(TYPE_VECTOR);
+ arg_1->set_vector_size((*arg_val_1).size());
+ for (int arg_1_index = 0; arg_1_index < (int)(*arg_val_1).size(); arg_1_index++) {
+ auto *arg_1_vector_arg_1_index __attribute__((__unused__)) = arg_1->add_vector_value();
+ arg_1_vector_arg_1_index->set_type(TYPE_UNION);
+ profile____android__hardware__tests__foo__V1_0__IFoo__Union(arg_1_vector_arg_1_index, (*arg_val_1)[arg_1_index]);
+ }
+ } else {
+ LOG(WARNING) << "argument 1 is null.";
+ }
+ break;
+ }
+ case details::HidlInstrumentor::CLIENT_API_EXIT:
+ case details::HidlInstrumentor::SERVER_API_EXIT:
+ case details::HidlInstrumentor::PASSTHROUGH_EXIT:
+ {
+ if ((*args).size() != 1) {
+ LOG(ERROR) << "Number of return values does not match. expect: 1, actual: " << (*args).size() << ", method name: convertToBoolIfSmall, event type: " << event;
+ break;
+ }
+ auto *result_0 __attribute__((__unused__)) = msg.add_return_type_hidl();
+ ::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::ContainsUnion> *result_val_0 __attribute__((__unused__)) = reinterpret_cast<::android::hardware::hidl_vec<::android::hardware::tests::foo::V1_0::IFoo::ContainsUnion>*> ((*args)[0]);
+ if (result_val_0 != nullptr) {
+ result_0->set_type(TYPE_VECTOR);
+ result_0->set_vector_size((*result_val_0).size());
+ for (int result_0_index = 0; result_0_index < (int)(*result_val_0).size(); result_0_index++) {
+ auto *result_0_vector_result_0_index __attribute__((__unused__)) = result_0->add_vector_value();
+ result_0_vector_result_0_index->set_type(TYPE_STRUCT);
+ profile____android__hardware__tests__foo__V1_0__IFoo__ContainsUnion(result_0_vector_result_0_index, (*result_val_0)[result_0_index]);
+ }
+ } else {
+ LOG(WARNING) << "return value 0 is null.";
+ }
+ break;
+ }
+ default:
+ {
+ LOG(WARNING) << "not supported. ";
+ break;
+ }
+ }
+ }
+ profiler.AddTraceEvent(event, package, version, interface, msg);
+ }
if (strcmp(method, "doThis") == 0) {
FunctionSpecificationMessage msg;
msg.set_name("doThis");
diff --git a/compilation_tools/vtsc/test/golden/PROFILER/MemoryTest.profiler.cpp b/compilation_tools/vtsc/test/golden/PROFILER/MemoryTest.profiler.cpp
index be28232..62c0fef 100644
--- a/compilation_tools/vtsc/test/golden/PROFILER/MemoryTest.profiler.cpp
+++ b/compilation_tools/vtsc/test/golden/PROFILER/MemoryTest.profiler.cpp
@@ -23,8 +23,11 @@
LOG(WARNING) << "incorrect package. Expect: android.hardware.tests.memory actual: " << package;
return;
}
- if (strcmp(version, "1.0") != 0) {
- LOG(WARNING) << "incorrect version. Expect: 1.0 actual: " << interface;
+ std::string version_str = std::string(version);
+ int major_version = stoi(version_str.substr(0, version_str.find('.')));
+ int minor_version = stoi(version_str.substr(version_str.find('.') + 1));
+ if (major_version != 1 || minor_version > 0) {
+ LOG(WARNING) << "incorrect version. Expect: 1.0 or lower (if version != x.0), actual: " << version;
return;
}
if (strcmp(interface, "IMemoryTest") != 0) {
diff --git a/compilation_tools/vtsc/test/golden/PROFILER/Nfc.profiler.cpp b/compilation_tools/vtsc/test/golden/PROFILER/Nfc.profiler.cpp
index cc5e400..7234a53 100644
--- a/compilation_tools/vtsc/test/golden/PROFILER/Nfc.profiler.cpp
+++ b/compilation_tools/vtsc/test/golden/PROFILER/Nfc.profiler.cpp
@@ -23,8 +23,11 @@
LOG(WARNING) << "incorrect package. Expect: android.hardware.nfc actual: " << package;
return;
}
- if (strcmp(version, "1.0") != 0) {
- LOG(WARNING) << "incorrect version. Expect: 1.0 actual: " << interface;
+ std::string version_str = std::string(version);
+ int major_version = stoi(version_str.substr(0, version_str.find('.')));
+ int minor_version = stoi(version_str.substr(version_str.find('.') + 1));
+ if (major_version != 1 || minor_version > 0) {
+ LOG(WARNING) << "incorrect version. Expect: 1.0 or lower (if version != x.0), actual: " << version;
return;
}
if (strcmp(interface, "INfc") != 0) {
diff --git a/compilation_tools/vtsc/test/golden/PROFILER/NfcClientCallback.profiler.cpp b/compilation_tools/vtsc/test/golden/PROFILER/NfcClientCallback.profiler.cpp
index 61ceb04..00c71f5 100644
--- a/compilation_tools/vtsc/test/golden/PROFILER/NfcClientCallback.profiler.cpp
+++ b/compilation_tools/vtsc/test/golden/PROFILER/NfcClientCallback.profiler.cpp
@@ -23,8 +23,11 @@
LOG(WARNING) << "incorrect package. Expect: android.hardware.nfc actual: " << package;
return;
}
- if (strcmp(version, "1.0") != 0) {
- LOG(WARNING) << "incorrect version. Expect: 1.0 actual: " << interface;
+ std::string version_str = std::string(version);
+ int major_version = stoi(version_str.substr(0, version_str.find('.')));
+ int minor_version = stoi(version_str.substr(version_str.find('.') + 1));
+ if (major_version != 1 || minor_version > 0) {
+ LOG(WARNING) << "incorrect version. Expect: 1.0 or lower (if version != x.0), actual: " << version;
return;
}
if (strcmp(interface, "INfcClientCallback") != 0) {
diff --git a/compilation_tools/vtsc/test/golden/PROFILER/TestMsgQ.profiler.cpp b/compilation_tools/vtsc/test/golden/PROFILER/TestMsgQ.profiler.cpp
index ff97cd0..016b2c1 100644
--- a/compilation_tools/vtsc/test/golden/PROFILER/TestMsgQ.profiler.cpp
+++ b/compilation_tools/vtsc/test/golden/PROFILER/TestMsgQ.profiler.cpp
@@ -30,8 +30,11 @@
LOG(WARNING) << "incorrect package. Expect: android.hardware.tests.msgq actual: " << package;
return;
}
- if (strcmp(version, "1.0") != 0) {
- LOG(WARNING) << "incorrect version. Expect: 1.0 actual: " << interface;
+ std::string version_str = std::string(version);
+ int major_version = stoi(version_str.substr(0, version_str.find('.')));
+ int minor_version = stoi(version_str.substr(version_str.find('.') + 1));
+ if (major_version != 1 || minor_version > 0) {
+ LOG(WARNING) << "incorrect version. Expect: 1.0 or lower (if version != x.0), actual: " << version;
return;
}
if (strcmp(interface, "ITestMsgQ") != 0) {
diff --git a/drivers/hal/common/binder/VtsFuzzerBinderService.cpp b/drivers/hal/common/binder/VtsFuzzerBinderService.cpp
index 283ea8d..3566f5e 100644
--- a/drivers/hal/common/binder/VtsFuzzerBinderService.cpp
+++ b/drivers/hal/common/binder/VtsFuzzerBinderService.cpp
@@ -19,9 +19,9 @@
#include <iostream>
#include <string>
-#include <utils/RefBase.h>
#define LOG_TAG "VtsFuzzerBinderService"
-#include <utils/Log.h>
+#include <log/log.h>
+#include <utils/RefBase.h>
#include <binder/IBinder.h>
#include <binder/IInterface.h>
diff --git a/drivers/hal/server/BinderServer.cpp b/drivers/hal/server/BinderServer.cpp
index 2a1bebc..a616db4 100644
--- a/drivers/hal/server/BinderServer.cpp
+++ b/drivers/hal/server/BinderServer.cpp
@@ -24,9 +24,9 @@
#include <iostream>
#include <string>
-#include <utils/RefBase.h>
#define LOG_TAG "VtsFuzzerBinderServer"
-#include <utils/Log.h>
+#include <log/log.h>
+#include <utils/RefBase.h>
#include <utils/String8.h>
#include <binder/IBinder.h>
diff --git a/hals/light/bullhead/lights.c b/hals/light/bullhead/lights.c
index 8a10ea4..dde468b 100644
--- a/hals/light/bullhead/lights.c
+++ b/hals/light/bullhead/lights.c
@@ -17,7 +17,7 @@
#define LOG_TAG "lights"
#define DEBUG 1
-#include <cutils/log.h>
+#include <log/log.h>
#include <malloc.h>
#include <stdint.h>
diff --git a/harnesses/host_controller/build/README.md b/harnesses/host_controller/build/README.md
deleted file mode 100644
index 845bd85..0000000
--- a/harnesses/host_controller/build/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# To set up client_secrets.json (once only)
-
-* Go to https://console.cloud.google.com/projectselector/apis/credentials/consent
- and create a new project if needed.
-* Once on the consent screen, set the product name to anything and save.
-* Click "Create credentials" and select "OAuth client ID"
-* Under "Application type", select "Other". Click "Create".
-* Click the download button for the client you just created,
- and save the resulting file at client_secrets.json
-
-# Running unit tests
- python pab_client_test.py
\ No newline at end of file
diff --git a/harnesses/host_controller/build/__init__.py b/harnesses/host_controller/build/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/harnesses/host_controller/build/__init__.py
+++ /dev/null
diff --git a/harnesses/host_controller/build/build_flasher.py b/harnesses/host_controller/build/build_flasher.py
deleted file mode 100644
index 6ad77d5..0000000
--- a/harnesses/host_controller/build/build_flasher.py
+++ /dev/null
@@ -1,166 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-"""Class to flash build artifacts onto devices"""
-
-import logging
-import os
-
-from vts.harnesses.host_controller.build import build_provider
-from vts.utils.python.controllers import android_device
-
-
-class BuildFlasher(object):
- """Client that manages build flashing.
-
- Attributes:
- device: AndroidDevice, the device associated with the client.
- """
-
- def __init__(self, serial=""):
- """Initialize the client.
-
- If serial not provided, find single device connected. Error if
- zero or > 1 devices connected.
-
- Args:
- serial: optional string, serial number for the device.
- """
- if serial != "":
- self.device = android_device.AndroidDevice(serial)
- else:
- serials = android_device.list_adb_devices()
- if len(serials) == 0:
- serials = android_device.list_fastboot_devices()
- if len(serials) == 0:
- raise android_device.AndroidDeviceError(
- "ADB and fastboot could not find any target devices.")
- if len(serials) > 1:
- print("ADB or fastboot found more than one device: %s" % serials)
- self.device = android_device.AndroidDevice(
- serials[0], device_callback_port=-1)
-
- def SetSerial(self, serial):
- """Sets device serial.
-
- Args:
- serial: string, a device serial.
-
- Returns:
- True if successful; False otherwise.
- """
- if not serial:
- print("no serial is given to BuildFlasher.SetSerial.")
- return False
-
- self.device = android_device.AndroidDevice(serial)
- return True
-
- def FlashGSI(self, system_img, vbmeta_img=None, skip_check=False):
- """Flash the Generic System Image to the device.
-
- Args:
- system_img: string, path to GSI
- vbmeta_img: string, optional, path to vbmeta image for new devices
- skip_check: boolean, set True to skip adb-based checks when
- the DUT is already running its bootloader.
- """
- if not os.path.exists(system_img):
- raise ValueError("Couldn't find system image at %s" % system_img)
- if not skip_check:
- self.device.adb.wait_for_device()
- if not self.device.isBootloaderMode:
- self.device.log.info(self.device.adb.reboot_bootloader())
- if vbmeta_img is not None:
- self.device.log.info(self.device.fastboot.flash(
- 'vbmeta', vbmeta_img))
- self.device.log.info(self.device.fastboot.erase('system'))
- self.device.log.info(self.device.fastboot.flash('system', system_img))
- self.device.log.info(self.device.fastboot.erase('metadata'))
- self.device.log.info(self.device.fastboot._w())
- self.device.log.info(self.device.fastboot.reboot())
-
- def Flashall(self, directory):
- """Flash all images in a directory to the device using flashall.
-
- Generally the directory is the result of unzipping the .zip from AB.
- Args:
- directory: string, path to directory containing images
- """
- # fastboot flashall looks for imgs in $ANDROID_PRODUCT_OUT
- os.environ['ANDROID_PRODUCT_OUT'] = directory
- self.device.adb.wait_for_device()
- if not self.device.isBootloaderMode:
- self.device.log.info(self.device.adb.reboot_bootloader())
- self.device.log.info(self.device.fastboot.flashall())
-
- def Flash(self, device_images):
- """Flash the Generic System Image to the device.
-
- Args:
- device_images: dict, where the key is partition name and value is
- image file path.
-
- Returns:
- True if succesful; False otherwise
- """
- if not device_images:
- logging.warn("Flash skipped because no device image is given.")
- return False
-
- if not self.device.isBootloaderMode:
- self.device.adb.wait_for_device()
- print("rebooting to bootloader")
- self.device.log.info(self.device.adb.reboot_bootloader())
-
- print("starting to flash vendor and other images...")
- if build_provider.FULL_ZIPFILE in device_images:
- print("fastboot update %s --skip-reboot" % (
- device_images[build_provider.FULL_ZIPFILE]))
- self.device.log.info(self.device.fastboot.update(
- device_images[build_provider.FULL_ZIPFILE],
- "--skip-reboot"))
-
- for partition, image_path in device_images.iteritems():
- if partition in (build_provider.FULL_ZIPFILE, "system", "vbmeta"):
- continue
- if not image_path:
- self.device.log.warning("%s image is empty", partition)
- continue
- self.device.log.info("fastboot flash %s %s", partition, image_path)
- self.device.log.info(
- self.device.fastboot.flash(partition, image_path))
-
- print("starting to flash system and other images...")
- if "system" in device_images and device_images["system"]:
- system_img = device_images["system"]
- vbmeta_img = device_images["vbmeta"] if (
- "vbmeta" in device_images and device_images["vbmeta"]) else None
- self.FlashGSI(system_img, vbmeta_img, skip_check=True)
- else:
- self.device.log.info(self.device.fastboot.reboot())
- return True
-
- def WaitForDevice(self, timeout_secs=600):
- """Waits for the device to boot completely.
-
- Args:
- timeout_secs: integer, the maximum timeout value for this
- operation (unit: seconds).
-
- Returns:
- True if device is booted successfully; False otherwise.
- """
- return self.device.waitForBootCompletion(timeout=timeout_secs)
diff --git a/harnesses/host_controller/build/build_flasher_test.py b/harnesses/host_controller/build/build_flasher_test.py
deleted file mode 100644
index 66b4d86..0000000
--- a/harnesses/host_controller/build/build_flasher_test.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 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.
-#
-
-import unittest
-from vts.harnesses.host_controller.build import build_flasher
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
-
-class BuildFlasherTest(unittest.TestCase):
- """Tests for Build Flasher"""
-
- @mock.patch(
- "vts.harnesses.host_controller.build.build_flasher.android_device")
- @mock.patch("vts.harnesses.host_controller.build.build_flasher.os")
- def testFlashGSIBadPath(self, mock_os, mock_class):
- flasher = build_flasher.BuildFlasher("thisismyserial")
- mock_os.path.exists.return_value = False
- with self.assertRaises(ValueError) as cm:
- flasher.FlashGSI("notexists.img")
- self.assertEqual("Couldn't find system image at notexists.img",
- str(cm.exception))
-
- @mock.patch(
- "vts.harnesses.host_controller.build.build_flasher.android_device")
- @mock.patch("vts.harnesses.host_controller.build.build_flasher.os")
- def testFlashGSISystemOnly(self, mock_os, mock_class):
- mock_device = mock.Mock()
- mock_class.AndroidDevice.return_value = mock_device
- flasher = build_flasher.BuildFlasher("thisismyserial")
- mock_os.path.exists.return_value = True
- flasher.FlashGSI("exists.img")
- mock_device.fastboot.erase.assert_any_call('system')
- mock_device.fastboot.flash.assert_any_call('system', 'exists.img')
- mock_device.fastboot.erase.assert_any_call('metadata')
-
- @mock.patch(
- "vts.harnesses.host_controller.build.build_flasher.android_device")
- def testFlashall(self, mock_class):
- mock_device = mock.Mock()
- mock_class.AndroidDevice.return_value = mock_device
- flasher = build_flasher.BuildFlasher("thisismyserial")
- flasher.Flashall("path/to/dir")
- mock_device.fastboot.flashall.assert_called_with()
-
- @mock.patch(
- "vts.harnesses.host_controller.build.build_flasher.android_device")
- def testEmptySerial(self, mock_class):
- mock_class.list_adb_devices.return_value = ['oneserial']
- flasher = build_flasher.BuildFlasher(serial="")
- mock_class.AndroidDevice.assert_called_with("oneserial",
- device_callback_port=-1)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/harnesses/host_controller/build/build_provider.py b/harnesses/host_controller/build/build_provider.py
deleted file mode 100644
index 012d2e5..0000000
--- a/harnesses/host_controller/build/build_provider.py
+++ /dev/null
@@ -1,154 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import os
-import shutil
-import tempfile
-import zipfile
-
-from vts.runners.host import utils
-
-FULL_ZIPFILE = "full-zipfile"
-
-
-class BuildProvider(object):
- """The base class for build provider.
-
- Attributes:
- _IMAGE_FILE_EXTENSIONS: a list of strings which are common image file
- extensions.
- _BASIC_IMAGE_FILE_NAMES: a list of strings which are the image names in
- an artifact zip.
- _device_images: dict where the key is image file name and value is the
- path.
- _test_suites: dict where the key is test suite type and value is the
- test suite package file path.
- _tmp_dirpath: string, the temp dir path created to keep artifacts.
- """
- _IMAGE_FILE_EXTENSIONS = [".img", ".bin"]
- _BASIC_IMAGE_FILE_NAMES = ["boot.img", "system.img", "vendor.img"]
-
- def __init__(self):
- self._device_images = {}
- self._test_suites = {}
- tempdir_base = os.path.join(os.getcwd(), "tmp")
- if not os.path.exists(tempdir_base):
- os.mkdir(tempdir_base)
- self._tmp_dirpath = tempfile.mkdtemp(dir=tempdir_base)
-
- def __del__(self):
- """Deletes the temp dir if still set."""
- if self._tmp_dirpath:
- shutil.rmtree(self._tmp_dirpath)
- self._tmp_dirpath = None
-
- @property
- def tmp_dirpath(self):
- return self._tmp_dirpath
-
- def CreateNewTmpDir(self):
- return tempfile.mkdtemp(dir=self._tmp_dirpath)
-
- def SetDeviceImage(self, name, path):
- """Sets device image `path` for the specified `name`."""
- self._device_images[name] = path
-
- def _IsFullDeviceImage(self, namelist):
- """Returns true if given namelist list has all common device images."""
- for image_file in self._BASIC_IMAGE_FILE_NAMES:
- if image_file not in namelist:
- return False
- return True
-
- def _IsImageFile(self, file_path):
- """Returns whether a file is an image.
-
- Args:
- file_path: string, the file path.
-
- Returns:
- boolean, whether the file is an image.
- """
- return any(file_path.endswith(ext)
- for ext in self._IMAGE_FILE_EXTENSIONS)
-
- def SetDeviceImagesInDirecotry(self, root_dir):
- """Sets device images to *.img and *.bin in a directory.
-
- Args:
- root_dir: string, the directory to find images in.
- """
- for dir_name, file_name in utils.iterate_files(root_dir):
- if self._IsImageFile(file_name):
- self.SetDeviceImage(file_name,
- os.path.join(dir_name, file_name))
-
- def SetDeviceImageZip(self, path):
- """Sets device image(s) using files in a given zip file.
-
- It extracts image files inside the given zip file and selects
- known Android image files.
-
- Args:
- path: string, the path to a zip file.
- """
- dest_path = path + ".dir"
- with zipfile.ZipFile(path, 'r') as zip_ref:
- if self._IsFullDeviceImage(zip_ref.namelist()):
- self.SetDeviceImage(FULL_ZIPFILE, path)
- else:
- zip_ref.extractall(dest_path)
- self.SetDeviceImagesInDirecotry(dest_path)
-
- def GetDeviceImage(self, name=None):
- """Returns device image info."""
- if name is None:
- return self._device_images
- return self._device_images[name]
-
- def SetTestSuitePackage(self, type, path):
- """Sets test suite package `path` for the specified `type`.
-
- Args:
- type: string, test suite type such as 'vts' or 'cts'.
- path: string, the path of a file. if a file is a zip file,
- it's unziped and its main binary is set.
- """
- if path.endswith("android-vts.zip"):
- dest_path = os.path.join(self.tmp_dirpath, "android-vts")
- with zipfile.ZipFile(path, 'r') as zip_ref:
- zip_ref.extractall(dest_path)
- bin_path = os.path.join(dest_path, "android-vts",
- "tools", "vts-tradefed")
- os.chmod(bin_path, 0766)
- path = bin_path
- else:
- print("unsupported zip file %s" % path)
- self._test_suites[type] = path
-
- def GetTestSuitePackage(self, type=None):
- """Returns test suite package info."""
- if type is None:
- return self._test_suites
- return self._test_suites[type]
-
- def PrintDeviceImageInfo(self):
- """Prints device image info."""
- print("%s" % self.GetDeviceImage())
-
- def PrintGetTestSuitePackageInfo(self):
- """Prints test suite package info."""
- print("%s" % self.GetTestSuitePackage())
diff --git a/harnesses/host_controller/build/build_provider_ab.py b/harnesses/host_controller/build/build_provider_ab.py
deleted file mode 100644
index b14531b..0000000
--- a/harnesses/host_controller/build/build_provider_ab.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import os
-import zipfile
-
-from vts.harnesses.host_controller.build import build_provider
-from vts.utils.python.build.api import artifact_fetcher
-
-
-class BuildProviderAB(build_provider.BuildProvider):
- """A build provider for Android Build (AB)."""
-
- def __init__(self):
- super(BuildProviderAB, self).__init__()
- if 'run_ab_key' in os.environ:
- print("For AB, use the key at %s" % os.environ['run_ab_key'])
- self._artifact_fetcher = artifact_fetcher.AndroidBuildClient(
- os.environ['run_ab_key'])
- else:
- self._artifact_fetcher = None
-
- def Fetch(self, branch, target, artifact_name, build_id="latest"):
- """Fetches Android device artifact file(s) from Android Build.
-
- Args:
- branch: string, androidbranch to pull resource from .
- target: string, build target name.
- artifact_name: string, file name.
- build_id: string, ID of the build or latest.
-
- Returns:
- a dict containing the device image info.
- a dict containing the test suite package info.
- """
- if not self._artifact_fetcher:
- return self.GetDeviceImage(), self.GetTestSuitePackage()
-
- if build_id == "latest":
- recent_build_ids = self._artifact_fetcher.ListBuildIds(
- branch, target)
- build_id = recent_build_ids[0]
-
- if "{build_id}" in artifact_name:
- artifact_name = artifact_name.replace("{build_id}", build_id)
-
- dest_filepath = os.path.join(self.tmp_dirpath, artifact_name)
- self._artifact_fetcher.DownloadArtifactToFile(
- branch, target, build_id, artifact_name,
- dest_filepath=dest_filepath)
-
- if dest_filepath.endswith("android-vts.zip"):
- self.SetTestSuitePackage("vts", dest_filepath)
- elif dest_filepath.endswith(".zip"):
- self.SetDeviceImageZip(dest_filepath)
-
- return self.GetDeviceImage(), self.GetTestSuitePackage()
diff --git a/harnesses/host_controller/build/build_provider_gcs.py b/harnesses/host_controller/build/build_provider_gcs.py
deleted file mode 100644
index b921edf..0000000
--- a/harnesses/host_controller/build/build_provider_gcs.py
+++ /dev/null
@@ -1,99 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import os
-import re
-import zipfile
-
-from vts.harnesses.host_controller.build import build_provider
-from vts.utils.python.common import cmd_utils
-
-
-class BuildProviderGCS(build_provider.BuildProvider):
- """A build provider for GCS (Google Cloud Storage)."""
-
- def __init__(self):
- super(BuildProviderGCS, self).__init__()
-
- @staticmethod
- def GetGsutilPath():
- """Returns the gsutil file path if found; None otherwise."""
- sh_stdout, sh_stderr, ret_code = cmd_utils.ExecuteOneShellCommand(
- "which gsutil")
- if ret_code == 0:
- return sh_stdout.strip()
- else:
- logging.fatal("`gsutil` doesn't exist on the host; "
- "please install Google Cloud SDK before retrying.")
- return None
-
- @staticmethod
- def IsGcsFile(gsutil_path, gs_path):
- """Checks whether a given path is for a GCS file.
-
- Args:
- gsutil_path: string, the path of a gsutil binary.
- gs_path: string, the GCS file path (e.g., gs://<bucket>/<file>.
-
- Returns:
- True if gs_path is a file, False otherwise.
- """
- check_command = "%s stat %s" % (gsutil_path, gs_path)
- _, _, ret_code = cmd_utils.ExecuteOneShellCommand(
- check_command)
- return ret_code == 0
-
- def Fetch(self, path):
- """Fetches Android device artifact file(s) from GCS.
-
- Args:
- path: string, the path of a directory which keeps artifacts.
-
- Returns:
- a dict containing the device image info.
- a dict containing the test suite package info.
- """
- if not path.startswith("gs://"):
- path = "gs://" + re.sub("^/*", "", path)
- path = re.sub("/*$", "", path)
-
- # make sure gsutil is available. Instead of a Python library,
- # gsutil binary is used that is to avoid packaging GCS PIP package
- # as part of VTS HC (Host Controller).
- gsutil_path = BuildProviderGCS.GetGsutilPath()
- if gsutil_path:
- temp_dir_path = self.CreateNewTmpDir()
- if not BuildProviderGCS.IsGcsFile(gsutil_path, path): # directory (not exist)
- copy_command = "%s cp -r %s/* %s" % (
- gsutil_path, path, temp_dir_path)
- _, _, ret_code = cmd_utils.ExecuteOneShellCommand(
- copy_command)
- if ret_code == 0:
- self.SetDeviceImagesInDirecotry(temp_dir_path)
- else:
- print("Error in copy files from GCS (code %s)." % ret_code)
- else:
- copy_command = "%s cp %s %s" % (
- gsutil_path, path, temp_dir_path)
- _, _, ret_code = cmd_utils.ExecuteOneShellCommand(
- copy_command)
- dest_file_path = os.path.join(temp_dir_path,
- os.path.basename(path))
- if ret_code == 0:
- self.SetTestSuitePackage("vts", dest_file_path)
- else:
- print("Error in copy file from GCS (code %s)." % ret_code)
- return self.GetDeviceImage(), self.GetTestSuitePackage()
diff --git a/harnesses/host_controller/build/build_provider_local_fs.py b/harnesses/host_controller/build/build_provider_local_fs.py
deleted file mode 100644
index 878b165..0000000
--- a/harnesses/host_controller/build/build_provider_local_fs.py
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import os
-import zipfile
-
-from vts.harnesses.host_controller.build import build_provider
-
-
-class BuildProviderLocalFS(build_provider.BuildProvider):
- """A build provider for local file system (fs)."""
-
- def __init__(self):
- super(BuildProviderLocalFS, self).__init__()
-
- def Fetch(self, path):
- """Fetches Android device artifact file(s) from a local directory.
-
- Args:
- path: string, the path of a directory which keeps artifacts.
-
- Returns:
- a dict containing the device image info.
- a dict containing the test suite package info.
- """
- if os.path.isdir(path):
- self.SetDeviceImagesInDirecotry(path)
- else:
- if path.endswith("android-vts.zip"):
- if os.path.isfile(path):
- dest_path = os.path.join(self.tmp_dirpath, "android-vts")
- with zipfile.ZipFile(path, 'r') as zip_ref:
- zip_ref.extractall(dest_path)
- bin_path = os.path.join(dest_path, "android-vts",
- "tools", "vts-tradefed")
- os.chmod(bin_path, 0766)
- self.SetTestSuitePackage("vts", bin_path)
- else:
- print("The specified file doesn't exist, %s" % path)
- else:
- print("unsupported zip file %s" % path)
- return self.GetDeviceImage(), self.GetTestSuitePackage()
diff --git a/harnesses/host_controller/build/pab_client.py b/harnesses/host_controller/build/pab_client.py
deleted file mode 100644
index 8eac69f..0000000
--- a/harnesses/host_controller/build/pab_client.py
+++ /dev/null
@@ -1,519 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-"""Class to fetch artifacts from Partner Android Build server
-"""
-
-import argparse
-import getpass
-import httplib2
-import json
-import logging
-import os
-import requests
-import urlparse
-import zipfile
-from posixpath import join as path_urljoin
-
-from oauth2client.client import flow_from_clientsecrets
-from oauth2client.file import Storage
-from oauth2client.tools import argparser
-from oauth2client.tools import run_flow
-
-from selenium import webdriver
-from selenium.webdriver.common.by import By
-from selenium.common.exceptions import TimeoutException
-from selenium.webdriver.support import expected_conditions as EC
-from selenium.webdriver.common.keys import Keys
-from selenium.webdriver.chrome.options import Options
-from selenium.webdriver.support.ui import WebDriverWait
-
-from vts.harnesses.host_controller.build import build_provider
-
-# constants for GET and POST endpoints
-GET = 'GET'
-POST = 'POST'
-
-
-class PartnerAndroidBuildClient(build_provider.BuildProvider):
- """Client that manages Partner Android Build downloading.
-
- Attributes:
- BAD_XSRF_CODE: int, error code for bad XSRF token error
- BASE_URL: string, path to PAB entry point
- BUILDARTIFACT_NAME_KEY: string, index in artifact containing name
- BUILD_BUILDID_KEY: string, index in build containing build_id
- BUILD_COMPLETED_STATUS: int, value of 'complete' build
- BUILD_STATUS_KEY: string, index in build object containing status.
- CHROME_DRIVER_LOCATION: string, path to chromedriver
- CHROME_LOCATION: string, path to Chrome browser
- CLIENT_STORAGE: string, path to store credentials.
- DEFAULT_CHUNK_SIZE: int, number of bytes to download at a time.
- DOWNLOAD_URL_KEY: string, index in downloadBuildArtifact containing url
- EMAIL: string, email constant for userinfo JSON
- EXPIRED_XSRF_CODE: int, error code for expired XSRF token error
- GETBUILD_ARTIFACTS_KEY, string, index in build obj containing artifacts
- GMS_DOWNLOAD_URL: string, base url for downloading artifacts.
- LISTBUILD_BUILD_KEY: string, index in listBuild containing builds
- PAB_URL: string, redirect url from Google sign-in to PAB
- PASSWORD: string, password constant for userinfo JSON
- SCOPE: string, URL for which to request access via oauth2.
- SVC_URL: string, path to buildsvc RPC
- XSRF_STORE: string, path to store xsrf token
- _credentials : oauth2client credentials object
- _userinfo_file: location of file containing email and password
- _xsrf : string, XSRF token from PAB website. expires after 7 days.
- """
- _credentials = None
- _userinfo_file = None
- _xsrf = None
- BAD_XSRF_CODE = -32000
- BASE_URL = 'https://partner.android.com'
- BUILDARTIFACT_NAME_KEY = '1'
- BUILD_BUILDID_KEY = '1'
- BUILD_COMPLETED_STATUS = 7
- BUILD_STATUS_KEY = '7'
- CHROME_DRIVER_LOCATION = '/usr/local/bin/chromedriver'
- CHROME_LOCATION = '/usr/bin/google-chrome'
- CLIENT_SECRETS = os.path.join(
- os.path.dirname(__file__), 'client_secrets.json')
- CLIENT_STORAGE = os.path.join(os.path.dirname(__file__), 'credentials')
- DEFAULT_CHUNK_SIZE = 1024
- DOWNLOAD_URL_KEY = '1'
- EMAIL = 'email'
- EXPIRED_XSRF_CODE = -32001
- GETBUILD_ARTIFACTS_KEY = '2'
- GMS_DOWNLOAD_URL = 'https://partnerdash.google.com/build/gmsdownload'
- LISTBUILD_BUILD_KEY = '1'
- PAB_URL = ('https://www.google.com/accounts/Login?&continue='
- 'https://partner.android.com/build/')
- PASSWORD = 'password'
- # need both of these scopes to access PAB downloader
- scopes = ('https://www.googleapis.com/auth/partnerdash',
- 'https://www.googleapis.com/auth/alkali-base')
- SCOPE = ' '.join(scopes)
- SVC_URL = urlparse.urljoin(BASE_URL, 'build/u/0/_gwt/_rpc/buildsvc')
- XSRF_STORE = os.path.join(os.path.dirname(__file__), 'xsrf')
-
- def __init__(self):
- """Creates a temp dir."""
- super(PartnerAndroidBuildClient, self).__init__()
-
- def Authenticate(self, userinfo_file=None):
- """Authenticate using OAuth2."""
- # this should be a JSON file with "email" and "password" string fields
- self._userinfo_file = userinfo_file
- logging.info('Parsing flags, use --noauth_local_webserver'
- ' if running on remote machine')
-
- parser = argparse.ArgumentParser(parents=[argparser])
- flags, unknown = parser.parse_known_args()
- logging.info('Preparing OAuth token')
- flow = flow_from_clientsecrets(self.CLIENT_SECRETS, scope=self.SCOPE)
- storage = Storage(self.CLIENT_STORAGE)
- if self._credentials is None:
- self._credentials = storage.get()
- if self._credentials is None or self._credentials.invalid:
- logging.info('Credentials not found, authenticating.')
- self._credentials = run_flow(flow, storage, flags)
-
- if self._credentials.access_token_expired:
- logging.info('Access token expired, refreshing.')
- self._credentials.refresh(http=httplib2.Http())
-
- if self.XSRF_STORE is not None and os.path.isfile(self.XSRF_STORE):
- with open(self.XSRF_STORE, 'r') as handle:
- self._xsrf = handle.read()
-
- def GetXSRFToken(self, email=None, password=None):
- """Get XSRF token. Prompt if email/password not provided.
-
- Args:
- email: string, optional. Gmail account of user logging in
- password: string, optional. Password of user logging in
-
- Returns:
- boolean, whether the token was accessed and stored
- """
- if self._userinfo_file is not None:
- with open(self._userinfo_file, 'r') as handle:
- userinfo = json.load(handle)
-
- if self.EMAIL not in userinfo or self.PASSWORD not in userinfo:
- raise ValueError(
- 'Malformed userinfo file: needs email and password')
-
- email = userinfo[self.EMAIL]
- password = userinfo[self.PASSWORD]
-
- chrome_options = Options()
- chrome_options.add_argument("--headless")
- chrome_options.binary_location = self.CHROME_LOCATION
-
- driver = webdriver.Chrome(
- executable_path=os.path.abspath(self.CHROME_DRIVER_LOCATION),
- chrome_options=chrome_options)
-
- driver.set_window_size(1080, 800)
- wait = WebDriverWait(driver, 10)
-
- driver.get(self.PAB_URL)
-
- query = driver.find_element_by_id("identifierId")
- if email is None:
- email = raw_input("Email: ")
- query.send_keys(email)
- driver.find_element_by_id("identifierNext").click()
-
- pw = wait.until(EC.element_to_be_clickable((By.NAME, "password")))
- pw.clear()
-
- if password is None:
- pw.send_keys(getpass.getpass("Password: "))
- else:
- pw.send_keys(password)
-
- driver.find_element_by_id("passwordNext").click()
-
- try:
- wait.until(EC.title_contains("Partner Android Build"))
- except TimeoutException as e:
- logging.exception(e)
- raise ValueError('Wrong password or non-standard login flow')
-
- self._xsrf = driver.execute_script("return clientConfig.XSRF_TOKEN;")
- with open(self.XSRF_STORE, 'w') as handle:
- handle.write(self._xsrf)
-
- return True
-
- def CallBuildsvc(self, method, params, account_id):
- """Call the buildsvc RPC with given parameters.
-
- Args:
- method: string, name of method to be called in buildsvc
- params: dict, parameters to RPC call
- account_id: int, ID associated with the PAB account.
-
- Returns:
- dict, result from RPC call
- """
- if self._xsrf is None:
- self.GetXSRFToken()
- params = json.dumps(params)
-
- data = {"method": method, "params": params, "xsrf": self._xsrf}
- data = json.dumps(data)
- headers = {}
- self._credentials.apply(headers)
- headers['Content-Type'] = 'application/json'
- headers['x-alkali-account'] = account_id
-
- response = requests.post(self.SVC_URL, data=data, headers=headers)
-
- responseJSON = {}
-
- try:
- responseJSON = response.json()
- except ValueError:
- raise ValueError("Backend error -- check your account ID")
-
- if 'result' in responseJSON:
- return responseJSON['result']
-
- if 'error' in responseJSON and 'code' in responseJSON['error']:
- if responseJSON['error']['code'] == self.BAD_XSRF_CODE:
- raise ValueError(
- "Bad XSRF token -- must be for the same account as your credentials")
- if responseJSON['error']['code'] == self.EXPIRED_XSRF_CODE:
- raise ValueError("Expired XSRF token -- please refresh")
-
- raise ValueError("Unknown response from server -- %s" %
- json.dumps(responseJSON))
-
- def GetBuildList(self,
- account_id,
- branch,
- target,
- page_token="",
- max_results=10,
- internal=True,
- method=GET):
- """Get the list of builds for a given account, branch and target
- Args:
- account_id: int, ID associated with the PAB account.
- branch: string, branch to pull resource from.
- target: string, "latest" or a specific version.
- page_token: string, token used for pagination
- max_results: maximum build results the build list contains, e.g. 25
- internal: bool, whether to query internal build
- method: 'GET' or 'POST', which endpoint to query
-
- Returns:
- list of dicts representing the builds, descending in time
- """
- if method == POST:
- params = {
- "1": branch,
- "2": target,
- "3": page_token,
- "4": max_results,
- "7": int(internal)
- }
-
- result = self.CallBuildsvc("listBuild", params, account_id)
- # in listBuild response, index '1' contains builds
- if self.LISTBUILD_BUILD_KEY in result:
- return result[self.LISTBUILD_BUILD_KEY]
- raise ValueError("Build list not found -- %s" % params)
- elif method == GET:
- headers = {}
- self._credentials.apply(headers)
-
- action = 'list-internal' if internal else 'list'
- # PAB URL format expects something (anything) to be given as buildid
- # and resource, even for action list
- dummy = 'DUMMY'
- url = path_urljoin(self.BASE_URL, 'build', 'builds', action,
- branch, target, dummy,
- dummy) + '?a=' + str(account_id)
-
- response = requests.get(url, headers=headers)
- try:
- responseJSON = response.json()
- return responseJSON['build']
- except ValueError as e:
- logging.exception(e)
- raise ValueError("Backend error -- check your account ID")
-
- def GetLatestBuildId(self, account_id, branch, target, method=GET):
- """Get the most recent build_id for a given account, branch and target
- Args:
- account_id: int, ID associated with the PAB account.
- branch: string, branch to pull resource from.
- target: string, "latest" or a specific version.
- method: 'GET' or 'POST', which endpoint to query
-
- Returns:
- string, most recent build id
- """
- # TODO: support pagination, maybe?
- build_list = self.GetBuildList(account_id=account_id,
- branch=branch,
- target=target,
- method=method)
- if len(build_list) == 0:
- raise ValueError(
- 'No builds found for account_id=%s, branch=%s, target=%s' %
- (account_id, branch, target))
- for build in build_list:
- if method == POST:
- # get build status: 7 = completed build
- if build.get(self.BUILD_STATUS_KEY,
- None) == self.BUILD_COMPLETED_STATUS:
- # return build id (index '1')
- return build[self.BUILD_BUILDID_KEY]
- elif method == GET:
- if build['build_attempt_status'] == "COMPLETE" and build[
- "successful"]:
- return build['build_id']
- raise ValueError(
- 'No complete builds found: %s failed or incomplete builds found' %
- len(build_list))
-
- def GetBuildArtifacts(
- self, account_id, build_id, branch, target, method=POST):
- """Get the list of build artifacts.
-
- For an account, build, target, branch.
-
- Args:
- account_id: int, ID associated with the PAB account.
- build_id: string, ID of the build
- branch: string, branch to pull resource from.
- target: string, "latest" or a specific version.
- method: 'GET' or 'POST', which endpoint to query
-
- Returns:
- list of build artifact objects
- """
- if method == GET:
- raise NotImplementedError(
- "GetBuildArtifacts not supported with GET")
- params = {"1": build_id, "2": target, "3": branch}
-
- result = self.CallBuildsvc("getBuild", params, account_id)
- # in getBuild response, index '2' contains the artifacts
- if self.GETBUILD_ARTIFACTS_KEY in result:
- return result[self.GETBUILD_ARTIFACTS_KEY]
- if len(result) == 0:
- raise ValueError("Build artifacts not found -- %s" % params)
-
- def GetArtifactURL(self,
- account_id,
- build_id,
- target,
- artifact_name,
- branch,
- internal,
- method=GET):
- """Get the URL for an artifact on the PAB server, using buildsvc.
-
- Args:
- account_id: int, ID associated with the PAB account.
- build_id: string/int, id of the build.
- target: string, "latest" or a specific version.
- artifact_name: string, simple file name (no parent dir or path).
- branch: string, branch to pull resource from.
- internal: int, whether the request is for an internal build artifact
- method: 'GET' or 'POST', which endpoint to query
-
- Returns:
- string, The URL for the resource specified by the parameters
- """
- if method == POST:
- params = {
- "1": str(build_id),
- "2": target,
- "3": artifact_name,
- "4": branch,
- "5": "", # release_candidate_name
- "6": internal
- }
-
- result = self.CallBuildsvc(method='downloadBuildArtifact',
- params=params,
- account_id=account_id)
-
- # in downloadBuildArtifact response, index '1' contains the url
- if self.DOWNLOAD_URL_KEY in result:
- return result[self.DOWNLOAD_URL_KEY]
- if len(result) == 0:
- raise ValueError("Resource not found -- %s" % params)
- elif method == GET:
- headers = {}
- self._credentials.apply(headers)
-
- action = 'get-internal' if internal else 'get'
- get_url = path_urljoin(self.BASE_URL, 'build', 'builds', action,
- branch, target, build_id,
- artifact_name) + '?a=' + str(account_id)
-
- response = requests.get(get_url, headers=headers)
- try:
- responseJSON = response.json()
- return responseJSON['url']
- except ValueError:
- raise ValueError("Backend error -- check your account ID")
-
- def DownloadArtifact(self, download_url, filename):
- """Get artifact from Partner Android Build server.
-
- Args:
- download_url: location of resource that we want to download
- filename: where the artifact gets downloaded locally.
-
- Returns:
- boolean, whether the file was successfully downloaded
- """
-
- headers = {}
- self._credentials.apply(headers)
-
- response = requests.get(download_url, headers=headers, stream=True)
- response.raise_for_status()
-
- logging.info('%s now downloading...', download_url)
- with open(filename, 'wb') as handle:
- for block in response.iter_content(self.DEFAULT_CHUNK_SIZE):
- handle.write(block)
-
- return True
-
- def GetArtifact(self,
- account_id,
- branch,
- target,
- artifact_name,
- build_id='latest',
- method=GET,
- unzip=True):
- """Get an artifact for an account, branch, target and name and build id.
-
- If build_id not given, get latest.
-
- Args:
- account_id: int, ID associated with the PAB account.
- branch: string, branch to pull resource from.
- target: string, "latest" or a specific version.
- artifact_name: name of artifact, e.g. aosp_arm64_ab-img-4353141.zip
- ({id} will automatically get replaced with build ID)
- build_id: string, build ID of an artifact to fetch (or 'latest').
- method: 'GET' or 'POST', which endpoint to query
- unzip: boolean, True to unzip the artifact if that's a zip file.
-
- Returns:
- a dict containing the device image info.
- """
- if build_id == 'latest':
- build_id = self.GetLatestBuildId(account_id=account_id,
- branch=branch,
- target=target,
- method=method)
- print("latest build ID = %s" % build_id)
-
- if "build_id" in artifact_name:
- artifact_name = artifact_name.format(build_id=build_id)
-
- if method == POST:
- artifacts = self.GetBuildArtifacts(account_id=account_id,
- build_id=build_id,
- branch=branch,
- target=target,
- method=method)
-
- if len(artifacts) == 0:
- raise ValueError(
- "No artifacts found for build_id=%s, branch=%s, target=%s"
- % (build_id, branch, target))
-
- # in build artifact response, index '1' contains the name
- artifact_names = [
- artifact[self.BUILDARTIFACT_NAME_KEY] for artifact in artifacts
- ]
- if artifact_name not in artifact_names:
- raise ValueError("%s not found in artifact list" %
- artifact_name)
-
- url = self.GetArtifactURL(account_id=account_id,
- build_id=build_id,
- target=target,
- artifact_name=artifact_name,
- branch=branch,
- internal=False,
- method=method)
-
- if self.tmp_dirpath:
- artifact_path = os.path.join(self.tmp_dirpath, artifact_name)
- else:
- artifact_path = artifact_name
- self.DownloadArtifact(url, artifact_path)
- dirname = os.path.dirname(artifact_path)
- if unzip and artifact_path.endswith(".zip"):
- if artifact_path.endswith("android-vts.zip"):
- self.SetTestSuitePackage("vts", artifact_path)
- else:
- self.SetDeviceImageZip(artifact_path)
- return self.GetDeviceImage(), self.GetTestSuitePackage()
diff --git a/harnesses/host_controller/build/pab_client_test.py b/harnesses/host_controller/build/pab_client_test.py
deleted file mode 100644
index ee9d8ab..0000000
--- a/harnesses/host_controller/build/pab_client_test.py
+++ /dev/null
@@ -1,295 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 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.
-#
-
-import unittest
-from vts.harnesses.host_controller.build import pab_client
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
-from requests.models import Response
-
-
-class PartnerAndroidBuildClientTest(unittest.TestCase):
- """Tests for Partner Android Build client."""
-
- def setUp(self):
- self.client = pab_client.PartnerAndroidBuildClient()
- self.client.XSRF_STORE = None
-
- @mock.patch("pab_client.flow_from_clientsecrets")
- @mock.patch("pab_client.run_flow")
- @mock.patch("pab_client.Storage")
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- def testAuthenticationNew(self, mock_creds, mock_storage, mock_rf,
- mock_ffc):
- mock_creds.invalid = True
- self.client.Authenticate()
- mock_ffc.assert_called_once()
- mock_storage.assert_called_once()
- mock_rf.assert_called_once()
-
- @mock.patch("pab_client.flow_from_clientsecrets")
- @mock.patch("pab_client.run_flow")
- @mock.patch("pab_client.Storage")
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- def testAuthenticationStale(self, mock_creds, mock_storage, mock_rf,
- mock_ffc):
- mock_creds.invalid = False
- mock_creds.access_token_expired = True
- self.client.Authenticate()
- mock_ffc.assert_called_once()
- mock_storage.assert_called_once()
- mock_rf.assert_not_called()
- mock_creds.refresh.assert_called_once()
-
- @mock.patch("pab_client.flow_from_clientsecrets")
- @mock.patch("pab_client.run_flow")
- @mock.patch("pab_client.Storage")
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- def testAuthenticationFresh(self, mock_creds, mock_storage, mock_rf,
- mock_ffc):
- mock_creds.invalid = False
- mock_creds.access_token_expired = False
- self.client.Authenticate()
- mock_ffc.assert_called_once()
- mock_storage.assert_called_once()
- mock_rf.assert_not_called()
- mock_creds.refresh.assert_not_called()
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.requests')
- @mock.patch('pab_client.open')
- def testDownloadArtifact(self, mock_open, mock_requests, mock_creds):
- artifact_url = (
- "https://partnerdash.google.com/build/gmsdownload/"
- "f_companion/label/clockwork.companion_20170906_211311_RC00/"
- "ClockworkCompanionGoogleWithGmsRelease_signed.apk?a=100621237")
- self.client.DownloadArtifact(
- artifact_url, 'ClockworkCompanionGoogleWithGmsRelease_signed.apk')
- mock_creds.apply.assert_called_with({})
- mock_requests.get.assert_called_with(
- artifact_url, headers={}, stream=True)
- mock_open.assert_called_with(
- 'ClockworkCompanionGoogleWithGmsRelease_signed.apk', 'wb')
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.requests')
- def testGetArtifactURL(self, mock_requests, mock_creds):
- self.client._xsrf = 'disable'
- response = Response()
- response.status_code = 200
- response._content = b'{ "result" : {"1": "this_url"}}'
- mock_requests.post.return_value = response
- url = self.client.GetArtifactURL(
- 100621237,
- "4331445",
- "darwin_mac",
- "android-ndk-43345-darwin-x86_64.tar.bz2",
- "aosp-master-ndk",
- 0,
- method='POST')
-
- mock_requests.post.assert_called_with(
- 'https://partner.android.com/build/u/0/_gwt/_rpc/buildsvc',
- data=mock.ANY,
- headers={
- 'Content-Type': 'application/json',
- 'x-alkali-account': 100621237
- })
- self.assertEqual(url, "this_url")
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.requests')
- def testGetArtifactURLBackendError(self, mock_requests, mock_creds):
- self.client._xsrf = 'disable'
- response = Response()
- response.status_code = 200
- response._content = b'not JSON'
- mock_requests.post.return_value = response
- with self.assertRaises(ValueError) as cm:
- self.client.GetArtifactURL(
- 100621237,
- "4331445",
- "darwin_mac",
- "android-ndk-43345-darwin-x86_64.tar.bz2",
- "aosp-master-ndk",
- 0,
- method='POST')
- expected = "Backend error -- check your account ID"
- self.assertEqual(str(cm.exception), expected)
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.requests')
- def testGetArtifactURLMissingResultError(self, mock_requests, mock_creds):
- self.client._xsrf = 'disable'
- response = Response()
- response.status_code = 200
- response._content = b'{"result": {}}'
- mock_requests.post.return_value = response
- with self.assertRaises(ValueError) as cm:
- self.client.GetArtifactURL(
- 100621237,
- "4331445",
- "darwin_mac",
- "android-ndk-43345-darwin-x86_64.tar.bz2",
- "aosp-master-ndk",
- 0,
- method='POST')
- expected = "Resource not found"
- self.assertIn(expected, str(cm.exception))
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.requests')
- def testGetArtifactURLInvalidXSRFError(self, mock_requests, mock_creds):
- self.client._xsrf = 'disable'
- response = Response()
- response.status_code = 200
- response._content = b'{"error": {"code": -32000, "message":"Invalid"}}'
- mock_requests.post.return_value = response
- with self.assertRaises(ValueError) as cm:
- self.client.GetArtifactURL(
- 100621237,
- "4331445",
- "darwin_mac",
- "android-ndk-43345-darwin-x86_64.tar.bz2",
- "aosp-master-ndk",
- 0,
- method='POST')
- self.assertIn('Bad XSRF token', str(cm.exception))
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.requests')
- def testGetArtifactURLExpiredXSRFError(self, mock_requests, mock_creds):
- self.client._xsrf = 'disable'
- response = Response()
- response.status_code = 200
- response._content = b'{"error": {"code": -32001, "message":"Expired"}}'
- mock_requests.post.return_value = response
- with self.assertRaises(ValueError) as cm:
- self.client.GetArtifactURL(
- 100621237,
- "4331445",
- "darwin_mac",
- "android-ndk-43345-darwin-x86_64.tar.bz2",
- "aosp-master-ndk",
- 0,
- method='POST')
- self.assertIn('Expired XSRF token', str(cm.exception))
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.requests')
- def testGetArtifactURLUnknownError(self, mock_requests, mock_creds):
- self.client._xsrf = 'disable'
- response = Response()
- response.status_code = 200
- response._content = b'{"some_other_json": "foo"}'
- mock_requests.post.return_value = response
- with self.assertRaises(ValueError) as cm:
- self.client.GetArtifactURL(
- 100621237,
- "4331445",
- "darwin_mac",
- "android-ndk-43345-darwin-x86_64.tar.bz2",
- "aosp-master-ndk",
- 0,
- method='POST')
- self.assertIn('Unknown response from server', str(cm.exception))
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.requests')
- def testGetBuildListSuccess(self, mock_requests, mock_creds):
- self.client._xsrf = 'disable'
- response = Response()
- response.status_code = 200
- response._content = b'{"result": {"1": "foo"}}'
- mock_requests.post.return_value = response
- result = self.client.GetBuildList(
- 100621237,
- "git_oc-treble-dev",
- "aosp_arm64_ab-userdebug",
- method='POST')
- self.assertEqual(result, "foo")
- mock_requests.post.assert_called_with(
- 'https://partner.android.com/build/u/0/_gwt/_rpc/buildsvc',
- data=mock.ANY,
- headers={
- 'Content-Type': 'application/json',
- 'x-alkali-account': 100621237
- })
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.requests')
- def testGetBuildListError(self, mock_requests, mock_creds):
- self.client._xsrf = 'disable'
- response = Response()
- response.status_code = 200
- response._content = b'{"result": {"3": "foo"}}'
- mock_requests.post.return_value = response
- with self.assertRaises(ValueError) as cm:
- self.client.GetBuildList(
- 100621237,
- "git_oc-treble-dev",
- "aosp_arm64_ab-userdebug",
- method='POST')
- self.assertIn('Build list not found', str(cm.exception))
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.PartnerAndroidBuildClient.GetBuildList')
- def testGetLatestBuildIdSuccess(self, mock_gbl, mock_creds):
- self.client._xsrf = 'disable'
- mock_gbl.return_value = [{'7': 5, '1': 'bad'}, {'7': 7, '1': 'good'}]
- result = self.client.GetLatestBuildId(
- 100621237,
- "git_oc-treble-dev",
- "aosp_arm64_ab-userdebug",
- method='POST')
- self.assertEqual(result, 'good')
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.PartnerAndroidBuildClient.GetBuildList')
- def testGetLatestBuildIdEmpty(self, mock_gbl, mock_creds):
- self.client._xsrf = 'disable'
- mock_gbl.return_value = []
- with self.assertRaises(ValueError) as cm:
- result = self.client.GetLatestBuildId(
- 100621237,
- "git_oc-treble-dev",
- "aosp_arm64_ab-userdebug",
- method='POST')
- self.assertIn("No builds found for", str(cm.exception))
-
- @mock.patch('pab_client.PartnerAndroidBuildClient._credentials')
- @mock.patch('pab_client.PartnerAndroidBuildClient.GetBuildList')
- def testGetLatestBuildIdAllBad(self, mock_gbl, mock_creds):
- self.client._xsrf = 'disable'
- mock_gbl.return_value = [{'7': 0}, {'7': 0}]
- with self.assertRaises(ValueError) as cm:
- result = self.client.GetLatestBuildId(
- 100621237,
- "git_oc-treble-dev",
- "aosp_arm64_ab-userdebug",
- method='POST')
- self.assertEqual(
- "No complete builds found: 2 failed or incomplete builds found",
- str(cm.exception))
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/harnesses/host_controller/console.py b/harnesses/host_controller/console.py
deleted file mode 100644
index 6d5c283..0000000
--- a/harnesses/host_controller/console.py
+++ /dev/null
@@ -1,747 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import argparse
-import cmd
-import imp # Python v2 compatibility
-import logging
-import os
-import shutil
-import socket
-import subprocess
-import sys
-import threading
-import time
-
-import httplib2
-from apiclient import errors
-import urlparse
-
-from vts.harnesses.host_controller.tfc import request
-from vts.harnesses.host_controller.build import build_flasher
-from vts.harnesses.host_controller.build import build_provider
-from vts.harnesses.host_controller.build import build_provider_ab
-from vts.harnesses.host_controller.build import build_provider_gcs
-from vts.harnesses.host_controller.build import build_provider_local_fs
-from vts.harnesses.host_controller.tradefed import remote_operation
-
-# The default Partner Android Build (PAB) public account.
-# To obtain access permission, please reach out to Android partner engineering
-# department of Google LLC.
-_DEFAULT_ACCOUNT_ID = '543365459'
-
-# The default value for "flash --current".
-_DEFAULT_FLASH_IMAGES = [
- build_provider.FULL_ZIPFILE, "boot.img", "cache.img", "system.img",
- "userdata.img", "vbmeta.img", "vendor.img",
-]
-
-# The environment variable for default serial numbers.
-_ANDROID_SERIAL = "ANDROID_SERIAL"
-
-
-class ConsoleArgumentError(Exception):
- """Raised when the console fails to parse commands."""
- pass
-
-
-class ConsoleArgumentParser(argparse.ArgumentParser):
- """The argument parser for a console command."""
-
- def __init__(self, command_name, description):
- """Initializes the ArgumentParser without --help option.
-
- Args:
- command_name: A string, the first argument of the command.
- description: The help message about the command.
- """
- super(ConsoleArgumentParser, self).__init__(
- prog=command_name, description=description, add_help=False)
-
- def ParseLine(self, line):
- """Parses a command line.
-
- Args:
- line: A string, the command line.
-
- Returns:
- An argparse.Namespace object.
- """
- return self.parse_args(line.split())
-
- # @Override
- def error(self, message):
- """Raises an exception when failing to parse the command.
-
- Args:
- message: The error message.
-
- Raises:
- ConsoleArgumentError.
- """
- raise ConsoleArgumentError(message)
-
-
-class Console(cmd.Cmd):
- """The console for host controllers.
-
- Attributes:
- device_image_info: dict containing info about device image files.
- prompt: The prompt string at the beginning of each command line.
- test_suite_info: dict containing info about test suite package files.
- update_thread: threading.Thread that updates device state regularly
- _pab_client: The PartnerAndroidBuildClient used to download artifacts
- _tfc_client: The TfcClient that the host controllers connect to.
- _hosts: A list of HostController objects.
- _in_file: The input file object.
- _out_file: The output file object.
- _serials: A list of string where each string is a device serial.
- _copy_parser: The parser for copy command.
- _device_parser: The parser for device command.
- _fetch_parser: The parser for fetch command.
- _flash_parser: The parser for flash command.
- _lease_parser: The parser for lease command.
- _list_parser: The parser for list command.
- _request_parser: The parser for request command.
- """
-
- def __init__(self,
- tfc,
- pab,
- host_controllers,
- in_file=sys.stdin,
- out_file=sys.stdout):
- """Initializes the attributes and the parsers."""
- # cmd.Cmd is old-style class.
- cmd.Cmd.__init__(self, stdin=in_file, stdout=out_file)
- self._build_provider = {}
- self._build_provider["pab"] = pab
- self._build_provider[
- "local_fs"] = build_provider_local_fs.BuildProviderLocalFS()
- self._build_provider["gcs"] = build_provider_gcs.BuildProviderGCS()
- self._build_provider["ab"] = build_provider_ab.BuildProviderAB()
- self._tfc_client = tfc
- self._hosts = host_controllers
- self._in_file = in_file
- self._out_file = out_file
- self.prompt = "> "
- self.device_image_info = {}
- self.test_suite_info = {}
- self.update_thread = None
-
- self._InitCopyParser()
- self._InitDeviceParser()
- self._InitFetchParser()
- self._InitFlashParser()
- self._InitLeaseParser()
- self._InitListParser()
- self._InitRequestParser()
- self._InitTestParser()
-
- def _InitRequestParser(self):
- """Initializes the parser for request command."""
- self._request_parser = ConsoleArgumentParser(
- "request", "Send TFC a request to execute a command.")
- self._request_parser.add_argument(
- "--cluster",
- required=True,
- help="The cluster to which the request is submitted.")
- self._request_parser.add_argument(
- "--run-target",
- required=True,
- help="The target device to run the command.")
- self._request_parser.add_argument(
- "--user",
- required=True,
- help="The name of the user submitting the request.")
- self._request_parser.add_argument(
- "command",
- metavar="COMMAND",
- nargs="+",
- help='The command to be executed. If the command contains '
- 'arguments starting with "-", place the command after '
- '"--" at end of line.')
-
- def ProcessScript(self, script_file_path):
- """Processes a .py script file.
-
- A script file implements a function which emits a list of console
- commands to execute. That function emits an empty list or None if
- no more command needs to be processed.
-
- Args:
- script_file_path: string, the path of a script file (.py file).
-
- Returns:
- True if successful; False otherwise
- """
- if not script_file_path.endswith(".py"):
- print("Script file is not .py file: %s" % script_file_path)
- return False
-
- script_module = imp.load_source('script_module', script_file_path)
-
- if _ANDROID_SERIAL in os.environ:
- serial = os.environ[_ANDROID_SERIAL]
- else:
- serial = None
-
- if serial:
- self.onecmd("device --set_serial=%s" % serial)
-
- commands = script_module.EmitConsoleCommands()
- if commands:
- for command in commands:
- self.onecmd(command)
- return True
-
- def do_request(self, line):
- """Sends TFC a request to execute a command."""
- args = self._request_parser.ParseLine(line)
- req = request.Request(
- cluster=args.cluster,
- command_line=" ".join(args.command),
- run_target=args.run_target,
- user=args.user)
- self._tfc_client.NewRequest(req)
-
- def help_request(self):
- """Prints help message for request command."""
- self._request_parser.print_help(self._out_file)
-
- def _InitListParser(self):
- """Initializes the parser for list command."""
- self._list_parser = ConsoleArgumentParser(
- "list", "Show information about the hosts.")
- self._list_parser.add_argument(
- "--host", type=int, help="The index of the host.")
- self._list_parser.add_argument(
- "type",
- choices=("hosts", "devices"),
- help="The type of the shown objects.")
-
- def _Print(self, string):
- """Prints a string and a new line character.
-
- Args:
- string: The string to be printed.
- """
- self._out_file.write(string + "\n")
-
- def do_list(self, line):
- """Shows information about the hosts."""
- args = self._list_parser.ParseLine(line)
- if args.host is None:
- hosts = enumerate(self._hosts)
- else:
- hosts = [(args.host, self._hosts[args.host])]
- if args.type == "hosts":
- self._PrintHosts(self._hosts)
- elif args.type == "devices":
- for ind, host in hosts:
- devices = host.ListDevices()
- self._Print("[%3d] %s" % (ind, host.hostname))
- self._PrintDevices(devices)
-
- def help_list(self):
- """Prints help message for list command."""
- self._list_parser.print_help(self._out_file)
-
- def _PrintHosts(self, hosts):
- """Shows a list of host controllers.
-
- Args:
- hosts: A list of HostController objects.
- """
- self._Print("index name")
- for ind, host in enumerate(hosts):
- self._Print("[%3d] %s" % (ind, host.hostname))
-
- def _PrintDevices(self, devices):
- """Shows a list of devices.
-
- Args:
- devices: A list of DeviceInfo objects.
- """
- attr_names = ("device_serial", "state", "run_target", "build_id",
- "sdk_version", "stub")
- self._PrintObjects(devices, attr_names)
-
- def _PrintObjects(self, objects, attr_names):
- """Shows objects as a table.
-
- Args:
- object: The objects to be shown, one object in a row.
- attr_names: The attributes to be shown, one attribute in a column.
- """
- width = [len(name) for name in attr_names]
- rows = [attr_names]
- for dev_info in objects:
- attrs = [
- _ToPrintString(getattr(dev_info, name, ""))
- for name in attr_names
- ]
- rows.append(attrs)
- for index, attr in enumerate(attrs):
- width[index] = max(width[index], len(attr))
-
- for row in rows:
- self._Print(" ".join(
- attr.ljust(width[index]) for index, attr in enumerate(row)))
-
- def _InitLeaseParser(self):
- """Initializes the parser for lease command."""
- self._lease_parser = ConsoleArgumentParser(
- "lease", "Make a host lease command tasks from TFC.")
- self._lease_parser.add_argument(
- "--host", type=int, help="The index of the host.")
-
- def do_lease(self, line):
- """Makes a host lease command tasks from TFC."""
- args = self._lease_parser.ParseLine(line)
- if args.host is None:
- if len(self._hosts) > 1:
- raise ConsoleArgumentError("More than one hosts.")
- args.host = 0
- tasks = self._hosts[args.host].LeaseCommandTasks()
- self._PrintTasks(tasks)
-
- def help_lease(self):
- """Prints help message for lease command."""
- self._lease_parser.print_help(self._out_file)
-
- def _InitFetchParser(self):
- """Initializes the parser for fetch command."""
- self._fetch_parser = ConsoleArgumentParser("fetch",
- "Fetch a build artifact.")
- self._fetch_parser.add_argument(
- '--type',
- default='pab',
- choices=('local_fs', 'gcs', 'pab', 'ab'),
- help='Build provider type')
- self._fetch_parser.add_argument(
- '--method',
- default='GET',
- choices=('GET', 'POST'),
- help='Method for fetching')
- self._fetch_parser.add_argument(
- "--path", # required for local_fs
- help="The path of a local directory which keeps the artifacts.")
- self._fetch_parser.add_argument(
- "--branch", # required for pab
- help="Branch to grab the artifact from.")
- self._fetch_parser.add_argument(
- "--target", # required for pab
- help="Target product to grab the artifact from.")
- # TODO(lejonathan): find a way to not specify this?
- self._fetch_parser.add_argument(
- "--account_id",
- default=_DEFAULT_ACCOUNT_ID,
- help="Partner Android Build account_id to use.")
- self._fetch_parser.add_argument(
- '--build_id',
- default='latest',
- help='Build ID to use default latest.')
- self._fetch_parser.add_argument(
- "--artifact_name", # required for pab
- help=
- "Name of the artifact to be fetched. {id} replaced with build id.")
- self._fetch_parser.add_argument(
- "--userinfo_file",
- help=
- "Location of file containing email and password, if using POST.")
-
- def do_fetch(self, line):
- """Makes the host download a build artifact from PAB."""
- args = self._fetch_parser.ParseLine(line)
- if args.type == "pab":
- # do we want this somewhere else? No harm in doing multiple times
- self._build_provider[args.type].Authenticate(args.userinfo_file)
- device_images, test_suites = self._build_provider[
- args.type].GetArtifact(
- account_id=args.account_id,
- branch=args.branch,
- target=args.target,
- artifact_name=args.artifact_name,
- build_id=args.build_id,
- method=args.method)
- elif args.type == "local_fs" or args.type == "gcs":
- device_images, test_suites = self._build_provider[args.type].Fetch(
- args.path)
- elif args.type == "ab":
- device_images, test_suites = self._build_provider[args.type].Fetch(
- branch=args.branch,
- target=args.target,
- artifact_name=args.artifact_name,
- build_id=args.build_id)
- else:
- print("ERROR: unknown fetch type %s" % args.type)
- sys.exit(-1)
-
- self.device_image_info.update(device_images)
- self.test_suite_info.update(test_suites)
-
- if self.device_image_info:
- logging.info("device images:\n%s",
- "\n".join(image + ": " + path for image, path in
- self.device_image_info.iteritems()))
- if self.test_suite_info:
- logging.info("test suites:\n%s",
- "\n".join(suite + ": " + path for suite, path in
- self.test_suite_info.iteritems()))
-
- def help_fetch(self):
- """Prints help message for fetch command."""
- self._fetch_parser.print_help(self._out_file)
-
- def DownloadTestResources(self, request_id):
- """Download all of the test resources for a TFC request id.
-
- Args:
- request_id: int, TFC request id
- """
- resources = self._tfc_client.TestResourceList(request_id)
- for resource in resources:
- self.DownloadTestResource(resource['url'])
-
- def DownloadTestResource(self, url):
- """Download a test resource with build provider, given a url.
-
- Args:
- url: a resource locator (not necessarily HTTP[s])
- with the scheme specifying the build provider.
- """
- parsed = urlparse.urlparse(url)
- path = (parsed.netloc + parsed.path).split('/')
- # pab://5346564/oc-release/marlin-userdebug/4329875/artifact.img
- if parsed.scheme == "pab":
- if len(path) != 5:
- print("Invalid pab resource locator: %s" % url)
- return
- account_id, branch, target, build_id, artifact_name = path
- cmd = ("fetch"
- " --type=pab"
- " --account_id=%s"
- " --branch=%s"
- " --target=%s"
- " --build_id=%s"
- " --artifact_name=%s") % (account_id, branch, target,
- build_id, artifact_name)
- self.onecmd(cmd)
- # ab://oc-release/marlin-userdebug/4329875/artifact.img
- elif parsed.scheme == "ab":
- if len(path) != 4:
- print("Invalid ab resource locator: %s" % url)
- return
- branch, target, build_id, artifact_name = path
- cmd = ("fetch"
- "--type=ab"
- " --branch=%s"
- " --target=%s"
- " --build_id=%s"
- " --artifact_name=%s") % (branch, target, build_id,
- artifact_name)
- self.onecmd(cmd)
- elif parsed.scheme == gcs:
- cmd = "fetch --type=gcs --path=%s" % url
- self.onecmd(cmd)
- else:
- print "Invalid URL: %s" % url
-
- def _InitFlashParser(self):
- """Initializes the parser for flash command."""
- self._flash_parser = ConsoleArgumentParser("flash",
- "Flash images to a device.")
- self._flash_parser.add_argument(
- "--current",
- metavar="PARTITION_IMAGE",
- nargs="*",
- type=lambda x: x.split("="),
- help="The partitions and images to be flashed. The format is "
- "<partition>=<image>. If PARTITION_IMAGE list is empty, "
- "currently fetched " + ", ".join(_DEFAULT_FLASH_IMAGES) +
- " will be flashed.")
- self._flash_parser.add_argument(
- "--serial", default="", help="Serial number for device.")
- self._flash_parser.add_argument(
- "--build_dir",
- help="Directory containing build images to be flashed.")
- self._flash_parser.add_argument(
- "--gsi", help="Path to generic system image")
- self._flash_parser.add_argument(
- "--vbmeta", help="Path to vbmeta image")
-
- def do_flash(self, line):
- """Flash GSI or build images to a device connected with ADB."""
- args = self._flash_parser.ParseLine(line)
-
- flashers = []
- if args.serial:
- flasher = build_flasher.BuildFlasher(args.serial)
- flashers.append(flasher)
- elif self._serials:
- for serial in self._serials:
- flasher = build_flasher.BuildFlasher(serial)
- flashers.append(flasher)
- else:
- flasher = build_flasher.BuildFlasher()
- flashers.append(flasher)
-
- if args.current:
- partition_image = dict(
- (partition, self.device_image_info[image])
- for partition, image in args.current)
- else:
- partition_image = dict(
- (image.rsplit(".img", 1)[0], self.device_image_info[image])
- for image in _DEFAULT_FLASH_IMAGES
- if image in self.device_image_info)
-
- if flashers:
- # Can be parallelized as long as that's proven reliable.
- for flasher in flashers:
- if args.current is not None:
- flasher.Flash(partition_image)
- else:
- if args.gsi is None and args.build_dir is None:
- self._flash_parser.error(
- "Nothing requested: specify --gsi or --build_dir")
- if args.build_dir is not None:
- flasher.Flashall(args.build_dir)
- if args.gsi is not None:
- flasher.FlashGSI(args.gsi, args.vbmeta)
- for flasher in flashers:
- flasher.WaitForDevice()
-
- def help_flash(self):
- """Prints help message for flash command."""
- self._flash_parser.print_help(self._out_file)
-
- def _InitCopyParser(self):
- """Initializes the parser for copy command."""
- self._copy_parser = ConsoleArgumentParser("copy", "Copy a file.")
-
- def do_copy(self, line):
- """Copy a file from source to destination path."""
- src, dst = line.split()
- if dst == "{vts_tf_home}":
- dst = os.path.dirname(self.test_suite_info["vts"])
- elif "{" in dst:
- print("unknown dst %s" % dst)
- return
- shutil.copy(src, dst)
-
- def help_copy(self):
- """Prints help message for copy command."""
- self._copy_parser.print_help(self._out_file)
-
- def _InitDeviceParser(self):
- """Initializes the parser for device command."""
- self._device_parser = ConsoleArgumentParser(
- "device", "Selects device(s) under test.")
- self._device_parser.add_argument(
- "--set_serial",
- default="",
- help="Serial number for device. Can be a comma-separated list.")
- self._device_parser.add_argument(
- "--update",
- choices=("single", "start", "stop"),
- default="",
- help="Update device info on TradeFed cluster")
- self._device_parser.add_argument(
- "--interval",
- type=int,
- default=30,
- help="Interval (seconds) to repeat device update.")
- self._device_parser.add_argument(
- "--host", type=int, help="The index of the host.")
- self._serials = []
-
- def UpdateDevice(self, host):
- """Updates the device state of all devices on a given host.
-
- Args:
- host: HostController object
- """
- devices = host.ListDevices()
- for device in devices:
- device.Extend(['sim_state', 'sim_operator', 'mac_address'])
- snapshots = self._tfc_client.CreateDeviceSnapshot(
- host._cluster_ids[0], host.hostname, devices)
- self._tfc_client.SubmitHostEvents([snapshots])
-
- def UpdateDeviceRepeat(self, host, update_interval):
- """Regularly updates the device state of devices on a given host.
-
- Args:
- host: HostController object
- update_internval: int, number of seconds before repeating
- """
- thread = threading.currentThread()
- while getattr(thread, 'keep_running', True):
- try:
- self.UpdateDevice(host)
- except (socket.error, remote_operation.RemoteOperationException,
- httplib2.HttpLib2Error, errors.HttpError) as e:
- logging.exception(e)
- time.sleep(update_interval)
-
- def do_device(self, line):
- """Sets device info such as serial number."""
- args = self._device_parser.ParseLine(line)
- if args.set_serial:
- self._serials = args.set_serial.split(",")
- print("serials: %s" % self._serials)
- if args.update:
- if args.host is None:
- if len(self._hosts) > 1:
- raise ConsoleArgumentError("More than one host.")
- args.host = 0
- host = self._hosts[args.host]
- if args.update == "single":
- self.UpdateDevice(host)
- elif args.update == "start":
- if args.interval <= 0:
- raise ConsoleArgumentError(
- "update interval must be positive")
- # do not allow user to create new
- # thread if one is currently running
- if self.update_thread is not None and not hasattr(
- self.update_thread, 'keep_running'):
- print(
- 'device update already running. '
- 'run device --update stop first.'
- )
- return
- self.update_thread = threading.Thread(
- target=self.UpdateDeviceRepeat,
- args=(
- host,
- args.interval, ))
- self.update_thread.daemon = True
- self.update_thread.start()
- elif args.update == "stop":
- self.update_thread.keep_running = False
-
- def help_device(self):
- """Prints help message for device command."""
- self._device_parser.print_help(self._out_file)
-
- def _InitTestParser(self):
- """Initializes the parser for test command."""
- self._test_parser = ConsoleArgumentParser("test",
- "Executes a command on TF.")
- self._test_parser.add_argument(
- "--serial",
- default=None,
- help="The target device serial to run the command.")
- self._test_parser.add_argument(
- "--test_exec_mode",
- default="subprocess",
- help="The target exec model.")
- self._test_parser.add_argument(
- "command",
- metavar="COMMAND",
- nargs="+",
- help='The command to be executed. If the command contains '
- 'arguments starting with "-", place the command after '
- '"--" at end of line. format: plan -m module -t testcase')
-
- def do_test(self, line):
- """Executes a command using a VTS-TF instance."""
- args = self._test_parser.ParseLine(line)
- if args.serial:
- serial = args.serial
- elif self._serials:
- serial = self._serials[0]
- else:
- serial = ""
-
- if args.test_exec_mode == "subprocess":
- bin_path = self.test_suite_info["vts"]
- cmd = [bin_path, "run"]
- cmd.extend(args.command)
- if serial:
- cmd.extend(["-s", serial])
- print("Command: %s" % cmd)
- result = subprocess.check_output(cmd)
- logging.debug("result: %s", result)
- else:
- print("unsupported exec mode: %s", args.test_exec_mode)
-
- def help_test(self):
- """Prints help message for test command."""
- self._test_parser.print_help(self._out_file)
-
- def _PrintTasks(self, tasks):
- """Shows a list of command tasks.
-
- Args:
- devices: A list of DeviceInfo objects.
- """
- attr_names = ("request_id", "command_id", "task_id", "device_serials",
- "command_line")
- self._PrintObjects(tasks, attr_names)
-
- def do_exit(self, line):
- """Terminates the console.
-
- Returns:
- True, which stops the cmdloop.
- """
- return True
-
- def help_exit(self):
- """Prints help message for exit command."""
- self._Print("Terminate the console.")
-
- # @Override
- def onecmd(self, line):
- """Executes a command and prints any exception."""
- if line:
- print("Command: %s" % line)
- try:
- return cmd.Cmd.onecmd(self, line)
- except Exception as e:
- self._Print("%s: %s" % (type(e).__name__, e))
- return None
-
- # @Override
- def emptyline(self):
- """Ignores empty lines."""
- pass
-
- # @Override
- def default(self, line):
- """Handles unrecognized commands.
-
- Returns:
- True if receives EOF; otherwise delegates to default handler.
- """
- if line == "EOF":
- return self.do_exit(line)
- return cmd.Cmd.default(self, line)
-
-
-def _ToPrintString(obj):
- """Converts an object to printable string on console.
-
- Args:
- obj: The object to be printed.
- """
- if isinstance(obj, (list, tuple, set)):
- return ",".join(str(x) for x in obj)
- return str(obj)
diff --git a/harnesses/host_controller/console_test.py b/harnesses/host_controller/console_test.py
deleted file mode 100644
index ef3b3ec..0000000
--- a/harnesses/host_controller/console_test.py
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 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.
-#
-
-import unittest
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
-try:
- import StringIO as string_io_module
-except ImportError:
- import io as string_io_module
-
-from vts.harnesses.host_controller.tfc import command_task
-from vts.harnesses.host_controller.tfc import device_info
-from vts.harnesses.host_controller import console
-
-
-class ConsoleTest(unittest.TestCase):
- """A test for console.Console.
-
- Attribute:
- _out_file: The console output buffer.
- _host_controller: A mock host_controller.HostController.
- _pab_client: A mock pab_client.PartnerAndroidBuildClient.
- _tfc_client: A mock tfc_client.TfcClient.
- _console: The console being tested.
- """
- _DEVICES = [device_info.DeviceInfo(device_serial="ABC001",
- run_target="sailfish",
- state="Available",
- build_id="111111",
- sdk_version="27")]
- _TASKS = [command_task.CommandTask(request_id="1",
- task_id="1-0",
- command_id="2",
- command_line="vts -m SampleShellTest",
- device_serials=["ABC001"])]
-
- def setUp(self):
- """Creates the console."""
- self._out_file = string_io_module.StringIO()
- self._host_controller = mock.Mock()
- self._pab_client = mock.Mock()
- self._tfc_client = mock.Mock()
- self._console = console.Console(self._tfc_client,
- self._pab_client,
- [self._host_controller],
- None,
- self._out_file)
-
- def tearDown(self):
- """Closes the output file."""
- self._out_file.close()
-
- def _IssueCommand(self, command_line):
- """Issues a command in the console.
-
- Args:
- command_line: A string, the input to the console.
-
- Returns:
- A string, the output of the console.
- """
- out_position = self._out_file.tell()
- self._console.onecmd(command_line)
- self._out_file.seek(out_position)
- return self._out_file.read()
-
- def testLease(self):
- """Tests the lease command."""
- self._host_controller.LeaseCommandTasks.return_value = self._TASKS
- output = self._IssueCommand("lease")
- expected = ("request_id command_id task_id device_serials command_line \n"
- "1 2 1-0 ABC001 vts -m SampleShellTest\n")
- self.assertEqual(expected, output)
- output = self._IssueCommand("lease --host 0")
- self.assertEqual(expected, output)
-
- def testRequest(self):
- """Tests the request command."""
- user = "user0"
- cluster = "cluster0"
- run_target = "sailfish"
- command_line = "vts -m SampleShellTest"
- self._IssueCommand("request --user %s --cluster %s --run-target %s "
- "-- %s" % (user, cluster, run_target, command_line))
- req = self._tfc_client.NewRequest.call_args[0][0]
- self.assertEqual(user, req.user)
- self.assertEqual(cluster, req.cluster)
- self.assertEqual(run_target, req.run_target)
- self.assertEqual(command_line, req.command_line)
-
- def testListHosts(self):
- """Tests the list command."""
- self._host_controller.hostname = "host0"
- output = self._IssueCommand("list hosts")
- self.assertEqual("index name\n"
- "[ 0] host0\n",
- output)
-
- def testListDevices(self):
- """Tests the list command."""
- self._host_controller.ListDevices.return_value = self._DEVICES
- self._host_controller.hostname = "host0"
- output = self._IssueCommand("list devices")
- expected = ("[ 0] host0\n"
- "device_serial state run_target build_id sdk_version stub\n"
- "ABC001 Available sailfish 111111 27 \n")
- self.assertEqual(expected, output)
- output = self._IssueCommand("list devices --host 0")
- self.assertEqual(expected, output)
-
- def testWrongHostIndex(self):
- """Tests host index out of range."""
- output = self._IssueCommand("list devices --host 1")
- expected = "IndexError: "
- self.assertTrue(output.startswith(expected))
- output = self._IssueCommand("lease --host 1")
- self.assertTrue(output.startswith(expected))
-
- @mock.patch('vts.harnesses.host_controller.'
- 'console.build_flasher.BuildFlasher')
- def testFetchPOSTAndFlash(self, mock_class):
- """Tests fetching from pab and flashing."""
- self._pab_client.GetArtifact.return_value = (
- {"system.img": "/mock/system.img", "odm.img": "/mock/odm.img"},
- None)
- self._IssueCommand(
- "fetch --branch=aosp-master-ndk --target=darwin_mac "
- "--account_id=100621237 "
- "--artifact_name=foo-{id}.tar.bz2 --method=POST"
- )
- self._pab_client.GetArtifact.assert_called_with(
- account_id='100621237',
- branch='aosp-master-ndk',
- target='darwin_mac',
- artifact_name='foo-{id}.tar.bz2',
- build_id='latest',
- method='POST')
-
- flasher = mock.Mock()
- mock_class.return_value = flasher
- self._IssueCommand("flash --current system=system.img odm=odm.img")
- flasher.Flash.assert_called_with(
- {"system": "/mock/system.img", "odm": "/mock/odm.img"})
-
- @mock.patch('vts.harnesses.host_controller.'
- 'console.build_flasher.BuildFlasher')
- def testFlashGSI(self, mock_class):
- flasher = mock.Mock()
- mock_class.return_value = flasher
- self._IssueCommand("flash --gsi=system.img")
- flasher.FlashGSI.assert_called_with('system.img', None)
-
- @mock.patch('vts.harnesses.host_controller.'
- 'console.build_flasher.BuildFlasher')
- def testFlashGSIWithVbmeta(self, mock_class):
- flasher = mock.Mock()
- mock_class.return_value = flasher
- self._IssueCommand("flash --gsi=system.img --vbmeta=vbmeta.img")
- flasher.FlashGSI.assert_called_with('system.img', 'vbmeta.img')
-
- @mock.patch('vts.harnesses.host_controller.'
- 'console.build_flasher.BuildFlasher')
- def testFlashall(self, mock_class):
- flasher = mock.Mock()
- mock_class.return_value = flasher
- self._IssueCommand("flash --build_dir=path/to/dir/")
- flasher.Flashall.assert_called_with('path/to/dir/')
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/harnesses/host_controller/host_controller.py b/harnesses/host_controller/host_controller.py
deleted file mode 100644
index d04e65d..0000000
--- a/harnesses/host_controller/host_controller.py
+++ /dev/null
@@ -1,140 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import logging
-import socket
-import time
-import uuid
-
-import httplib2
-from apiclient import errors
-
-from vts.harnesses.host_controller import invocation_thread
-from vts.harnesses.host_controller.tradefed import remote_operation
-from vts.harnesses.host_controller.tfc import command_attempt
-
-
-class HostController(object):
- """The class that relays commands between a TradeFed host and clusters.
-
- Attributes:
- _remote_client: The RemoteClient which runs commands.
- _tfc_client: The TfcClient from which the command tasks are leased.
- _hostname: A string, the name of the TradeFed host.
- _cluster_ids: A list of strings, the cluster IDs for leasing tasks.
- _invocation_threads: The list of running InvocationThread.
- """
-
- def __init__(self, remote_client, tfc_client, hostname, cluster_ids):
- """Initializes the attributes."""
- self._remote_client = remote_client
- self._tfc_client = tfc_client
- self._hostname = hostname
- self._cluster_ids = cluster_ids
- self._invocation_threads = []
-
- @property
- def hostname(self):
- """Returns the name of the host."""
- return self._hostname
-
- def _JoinInvocationThreads(self):
- """Removes terminated threads from _invocation_threads."""
- alive_threads = []
- for inv_thread in self._invocation_threads:
- inv_thread.join(0)
- if inv_thread.is_alive():
- alive_threads.append(inv_thread)
- self._invocation_threads = alive_threads
-
- def _CreateInvocationThread(self, task):
- """Creates an invocation thread from a command task.
-
- Args:
- task: The CommandTask object.
-
- Returns:
- An InvocationThread.
- """
- attempt_id = uuid.uuid4()
- attempt = command_attempt.CommandAttempt(
- task.task_id, attempt_id,
- self._hostname, task.device_serials[0])
- inv_thread = invocation_thread.InvocationThread(
- self._remote_client, self._tfc_client, attempt,
- task.command_line.split(), task.device_serials)
- return inv_thread
-
- def ListDevices(self):
- """Lists present devices on the host.
-
- Returns:
- A list of DeviceInfo.
- """
- devices = self._remote_client.ListDevices()
- return [dev for dev in devices if not dev.IsStub()]
-
- def ListAvailableDevices(self):
- """Lists available devices for command tasks.
-
- Returns:
- A list of DeviceInfo.
- """
- self._JoinInvocationThreads()
- allocated_serials = set()
- for inv_thread in self._invocation_threads:
- allocated_serials.update(inv_thread.device_serials)
-
- present_devices = self.ListDevices()
- return [dev for dev in present_devices if
- dev.IsAvailable() and
- dev.device_serial not in allocated_serials]
-
- def LeaseCommandTasks(self):
- """Leases command tasks and creates threads to execute them.
-
- Returns:
- A list of CommandTask. The leased command tasks.
- """
- available_devices = self.ListAvailableDevices()
- if not available_devices:
- return []
-
- tasks = self._tfc_client.LeaseHostTasks(
- self._cluster_ids[0], self._cluster_ids[1:],
- self._hostname, available_devices)
- for task in tasks:
- inv_thread = self._CreateInvocationThread(task)
- inv_thread.daemon = True
- inv_thread.start()
- self._invocation_threads.append(inv_thread)
- return tasks
-
- def Run(self, poll_interval):
- """Starts polling TFC for tasks.
-
- Args:
- poll_interval: The poll interval in seconds.
- """
- while True:
- try:
- self.LeaseCommandTasks()
- except (socket.error,
- remote_operation.RemoteOperationException,
- httplib2.HttpLib2Error,
- errors.HttpError) as e:
- logging.exception(e)
- time.sleep(poll_interval)
diff --git a/harnesses/host_controller/host_controller_test.py b/harnesses/host_controller/host_controller_test.py
deleted file mode 100644
index 5eef588..0000000
--- a/harnesses/host_controller/host_controller_test.py
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 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.
-#
-
-import threading
-import unittest
-import time
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
-from vts.harnesses.host_controller import host_controller
-from vts.harnesses.host_controller.tfc import command_task
-from vts.harnesses.host_controller.tfc import device_info
-
-
-class HostControllerTest(unittest.TestCase):
- """A test for host_controller.HostController.
-
- Args:
- _remote_client: A mock remote_client.RemoteClient.
- _tfc_client: A mock tfc_client.TfcClient.
- _host_controller: The HostController being tested.
- """
- _AVAILABLE_DEVICE = device_info.DeviceInfo(
- device_serial="ABC001",
- run_target="sailfish",
- state="Available")
- _ALLOCATED_DEVICE = device_info.DeviceInfo(
- device_serial="ABC002",
- run_target="sailfish",
- state="Allocated")
- _STUB_DEVICE = device_info.DeviceInfo(
- device_serial="emulator-5554",
- run_target="unknown",
- state="Available",
- stub=True)
- _DEVICES = [_AVAILABLE_DEVICE, _ALLOCATED_DEVICE, _STUB_DEVICE]
- _TASKS = [command_task.CommandTask(task_id="1-0",
- command_line="vts -m SampleShellTest",
- device_serials=["ABC001"])]
-
- def setUp(self):
- """Creates the HostController."""
- self._remote_client = mock.Mock()
- self._tfc_client = mock.Mock()
- self._host_controller = host_controller.HostController(
- self._remote_client, self._tfc_client, "host1", ["cluster1"])
-
- @mock.patch("vts.harnesses.host_controller.invocation_thread."
- "InvocationThread.run")
- def testDeviceStateDuringInvocation(self, mock_run):
- """Tests LeaseHostTasks and ListAvailableDevices."""
- self._remote_client.ListDevices.return_value = self._DEVICES
- self._tfc_client.LeaseHostTasks.return_value = self._TASKS
- run_event = threading.Event()
- mock_run.side_effect = lambda: run_event.wait()
-
- self._host_controller.LeaseCommandTasks()
- devices = self._host_controller.ListAvailableDevices()
- self.assertEqual([], devices)
- run_event.set()
- # Wait for thread termination
- time.sleep(0.2)
- devices = self._host_controller.ListAvailableDevices()
- self.assertEqual([self._AVAILABLE_DEVICE], devices)
-
- def testListDevices(self):
- """Tests ListDevices."""
- self._remote_client.ListDevices.return_value = self._DEVICES
- devices = self._host_controller.ListDevices()
- self.assertEqual([self._AVAILABLE_DEVICE, self._ALLOCATED_DEVICE],
- devices)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/harnesses/host_controller/invocation_thread.py b/harnesses/host_controller/invocation_thread.py
deleted file mode 100644
index 9673862..0000000
--- a/harnesses/host_controller/invocation_thread.py
+++ /dev/null
@@ -1,169 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import logging
-import socket
-import threading
-
-import httplib2
-from apiclient import errors
-
-from vts.harnesses.host_controller.tfc import command_attempt
-from vts.harnesses.host_controller.tradefed import remote_operation
-
-
-class InvocationThread(threading.Thread):
- """The thread that remotely executes a command task.
-
- Attributes:
- _remote_client: The RemoteClient which executes the command.
- _tfc_client: The TfcClient to which the command events are sent.
- _attempt: The CommandAttempt whose events are sent to TFC.
- _command: A list of strings, the command and arguments.
- device_serials: A list of strings, the serial numbers of the devices
- which need to be allocated to the task.
- _allocated_serials: A list of strings, the serial numbers of the devices
- which are successfully allocated.
- _tfc_heartbeat_interval: The interval of TestRunInProgress events in
- seconds.
- """
-
- def __init__(self,
- remote_client,
- tfc_client,
- attempt,
- command,
- device_serials,
- tfc_heartbeat_interval=5 * 60):
- """Initializes the attributes."""
- super(InvocationThread, self).__init__()
- self._remote_client = remote_client
- self._tfc_client = tfc_client
- self._attempt = attempt
- self._command = command
- self.device_serials = device_serials
- self._allocated_serials = None
- # The value in Java implementation is 5 minutes.
- self._tfc_heartbeat_interval = tfc_heartbeat_interval
-
- def _AllocateDevices(self):
- """Allocates all of device_serial."""
- for serial in self.device_serials:
- self._remote_client.SendOperation(
- remote_operation.AllocateDevice(serial))
- self._allocated_serials.append(serial)
-
- def _StartInvocation(self):
- """Starts executing command and sends the event to TFC."""
- self._remote_client.SendOperation(
- remote_operation.ExecuteCommand(self.device_serials[0],
- *self._command))
- event = self._attempt.CreateCommandEvent(
- command_attempt.EventType.INVOCATION_STARTED)
- self._tfc_client.SubmitCommandEvents([event])
-
- def _WaitForCommandResult(self):
- """Waits for command result and keeps sending heartbeat to TFC
-
- Returns:
- A JSON object returned from TradeFed remote manager.
- """
- while True:
- result = self._remote_client.WaitForCommandResult(
- self.device_serials[0], self._tfc_heartbeat_interval)
- if result:
- return result
- event = self._attempt.CreateCommandEvent(
- command_attempt.EventType.TEST_RUN_IN_PROGRESS)
- self._tfc_client.SubmitCommandEvents([event])
-
- def _CompleteInvocation(self, result):
- """Sends InvocationCompleted event according to the result.
-
- Args:
- result: A JSON object returned from TradeFed remote manager.
- """
- if result["status"] == "INVOCATION_SUCCESS":
- event = self._attempt.CreateInvocationCompletedEvent(
- str(result), 1, 0)
- else:
- event = self._attempt.CreateInvocationCompletedEvent(
- str(result), 1, 1, error=str(result))
- self._tfc_client.SubmitCommandEvents([event])
-
- def _FreeAllocatedDevices(self):
- """Frees allocated devices and tolerates RemoteOperationException."""
- for serial in self._allocated_serials:
- try:
- self._remote_client.SendOperation(
- remote_operation.FreeDevice(serial))
- except remote_operation.RemoteOperationException as e:
- logging.exception(e)
- except socket.error as e:
- logging.exception(e)
- break
- self._allocated_serials = []
-
- def _SubmitErrorEvent(self, event_type, error_msg):
- """Submits an error event and tolerates http exceptions.
-
- Args:
- event_type: A string, the type of the command event.
- error_msg: A string, the error message.
- """
- try:
- self._tfc_client.SubmitCommandEvents(
- [self._attempt.CreateCommandEvent(event_type, error_msg)])
- except (httplib2.HttpLib2Error, errors.HttpError) as e:
- logging.exception(e)
-
- # @Override
- def run(self):
- """Executes a command task with exception handling."""
- self._allocated_serials = []
- last_error = None
- error_event = command_attempt.EventType.ALLOCATION_FAILED
- try:
- self._AllocateDevices()
- error_event = command_attempt.EventType.EXECUTE_FAILED
- self._StartInvocation()
- result = self._WaitForCommandResult()
- self._CompleteInvocation(result)
- error_event = None
- except errors.HttpError as e:
- logging.exception(e)
- last_error = e
- except remote_operation.RemoteOperationException as e:
- logging.exception(e)
- last_error = e
- # ConfigurationException on TradeFed remote manager.
- if str(e).startswith("Config error: "):
- error_event = command_attempt.EventType.CONFIGURATION_ERROR
- except httplib2.HttpLib2Error as e:
- logging.exception("Cannot communicate with TradeFed cluster: %s\n"
- "Skip submitting event %s.", e, error_event)
- last_error = e
- error_event = None
- except socket.error as e:
- logging.exception("Cannot communicate with TradeFed remote "
- "manager: %s\nSkip freeing devices %s.",
- e, self._allocated_serials)
- last_error = e
- self._allocated_serials = []
- finally:
- if error_event:
- self._SubmitErrorEvent(error_event, str(last_error))
- self._FreeAllocatedDevices()
diff --git a/harnesses/host_controller/invocation_thread_test.py b/harnesses/host_controller/invocation_thread_test.py
deleted file mode 100644
index c940329..0000000
--- a/harnesses/host_controller/invocation_thread_test.py
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 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.
-#
-
-import unittest
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
-from vts.harnesses.host_controller import invocation_thread
-from vts.harnesses.host_controller.tfc import command_attempt
-from vts.harnesses.host_controller.tradefed import remote_operation
-
-
-class InvocationThreadTest(unittest.TestCase):
- """A test for invocation_thread.InvocationThread.
-
- Attributes:
- _remote_client: A mock remote_client.RemoteClient.
- _tfc_client: A mock tfc_client.TfcClient.
- _inv_thread: The InvocationThread being tested.
- """
-
- def setUp(self):
- """Creates the InvocationThread."""
- self._remote_client = mock.Mock()
- self._tfc_client = mock.Mock()
- attempt = command_attempt.CommandAttempt(
- task_id="321-0",
- attempt_id="abcd-1234",
- hostname="host0",
- device_serial="ABCDEF")
- command = ["vts", "-m", "SampleShellTest"]
- serials = ["serial123", "serial456"]
- self._inv_thread = invocation_thread.InvocationThread(
- self._remote_client, self._tfc_client,
- attempt, command, serials)
-
- def _GetSubmittedEventTypes(self):
- """Gets the types of the events submitted by the mock TfcClient.
-
- Returns:
- A list of strings, the event types.
- """
- event_types = []
- for args, kwargs in self._tfc_client.SubmitCommandEvents.call_args_list:
- event_types.extend(event["type"] for event in args[0])
- return event_types
-
- def _GetSentOperationTypes(self):
- """Gets the types of the operations sent by the mock RemoteClient.
-
- Returns:
- A list of strings, the operation types.
- """
- operation_types = [args[0].type for args, kwargs in
- self._remote_client.SendOperation.call_args_list]
- return operation_types
-
- def testAllocationFailed(self):
- """Tests AllocationFailed event."""
- self._remote_client.SendOperation.side_effect = (
- lambda op: _RaiseExceptionForOperation(op, "ALLOCATE_DEVICE"))
- self._inv_thread.run()
- self.assertEqual([command_attempt.EventType.ALLOCATION_FAILED],
- self._GetSubmittedEventTypes())
- self.assertEqual(["ALLOCATE_DEVICE"],
- self._GetSentOperationTypes())
-
- def testExecuteFailed(self):
- """Tests ExecuteFailed event."""
- self._remote_client.SendOperation.side_effect = (
- lambda op: _RaiseExceptionForOperation(op, "EXEC_COMMAND"))
- self._inv_thread.run()
- self.assertEqual([command_attempt.EventType.EXECUTE_FAILED],
- self._GetSubmittedEventTypes())
- self.assertEqual(["ALLOCATE_DEVICE",
- "ALLOCATE_DEVICE",
- "EXEC_COMMAND",
- "FREE_DEVICE",
- "FREE_DEVICE"],
- self._GetSentOperationTypes())
-
- def testConfigurationError(self):
- """Tests ConfigurationError event."""
- self._remote_client.SendOperation.side_effect = (
- lambda op: _RaiseExceptionForOperation(op, "EXEC_COMMAND",
- "Config error: test"))
- self._inv_thread.run()
- self.assertEqual([command_attempt.EventType.CONFIGURATION_ERROR],
- self._GetSubmittedEventTypes())
- self.assertEqual(["ALLOCATE_DEVICE",
- "ALLOCATE_DEVICE",
- "EXEC_COMMAND",
- "FREE_DEVICE",
- "FREE_DEVICE"],
- self._GetSentOperationTypes())
-
- def testInvocationCompleted(self):
- """Tests InvocationCompleted event."""
- self._remote_client.WaitForCommandResult.side_effect = (
- None, {"status": "INVOCATION_SUCCESS"})
- self._inv_thread.run()
- self.assertEqual([command_attempt.EventType.INVOCATION_STARTED,
- command_attempt.EventType.TEST_RUN_IN_PROGRESS,
- command_attempt.EventType.INVOCATION_COMPLETED],
- self._GetSubmittedEventTypes())
- # GET_LAST_COMMAND_RESULT isn't called in mock WaitForCommandResult.
- self.assertEqual(["ALLOCATE_DEVICE",
- "ALLOCATE_DEVICE",
- "EXEC_COMMAND",
- "FREE_DEVICE",
- "FREE_DEVICE"],
- self._GetSentOperationTypes())
-
-
-def _RaiseExceptionForOperation(operation, op_type, error_msg="unit test"):
- """Raises exception for specific operation type.
-
- Args:
- operation: A remote_operation.RemoteOperation object.
- op_type: A string, the expected type.
- error_msg: The message in the exception.
-
- Raises:
- RemoteOperationException if the operation's type matches op_type.
- """
- if operation.type == op_type:
- raise remote_operation.RemoteOperationException(error_msg)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/harnesses/host_controller/main.py b/harnesses/host_controller/main.py
deleted file mode 100644
index 07daba7..0000000
--- a/harnesses/host_controller/main.py
+++ /dev/null
@@ -1,178 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 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.
-#
-
-import argparse
-import json
-import logging
-import socket
-import time
-import threading
-import sys
-
-from vts.harnesses.host_controller import console
-from vts.harnesses.host_controller import host_controller
-from vts.harnesses.host_controller.build import pab_client
-from vts.harnesses.host_controller.tfc import tfc_client
-from vts.harnesses.host_controller.tradefed import remote_client
-from vts.utils.python.os import env_utils
-
-_ANDROID_BUILD_TOP = "ANDROID_BUILD_TOP"
-_SECONDS_PER_UNIT = {
- "m": 60,
- "h": 60 * 60,
- "d": 60 * 60 * 24
-}
-
-
-def _ParseInterval(interval_str):
- """Parses string to time interval.
-
- Args:
- interval_str: string, a floating-point number followed by time unit.
-
- Returns:
- float, the interval in seconds.
-
- Raises:
- ValueError if the argument format is wrong.
- """
- if not interval_str:
- raise ValueError("Argument is empty.")
-
- unit = interval_str[-1]
- if unit not in _SECONDS_PER_UNIT:
- raise ValueError("Unknown unit: %s" % unit)
-
- interval = float(interval_str[:-1])
- if interval < 0:
- raise ValueError("Invalid time interval: %s" % interval)
-
- return interval * _SECONDS_PER_UNIT[unit]
-
-
-def main():
- """Parses arguments and starts console."""
- parser = argparse.ArgumentParser()
- parser.add_argument("--config-file",
- default=None,
- type=argparse.FileType('r'),
- help="The configuration file in JSON format")
- parser.add_argument("--poll", action="store_true",
- help="Disable console and start host controller "
- "threads polling TFC.")
- parser.add_argument("--use-tfc", action="store_true",
- help="Enable TFC (TradeFed Cluster).")
- parser.add_argument("--script",
- default=None,
- help="The path to a script file in .py format")
- parser.add_argument("--loop",
- default=None,
- metavar="INTERVAL",
- type=_ParseInterval,
- help="The interval of repeating the script. "
- "The format is a float followed by unit which is "
- "one of 'm' (minute), 'h' (hour), and 'd' (day). "
- "If this option is unspecified, the script will "
- "be processed once.")
- parser.add_argument("--console", action="store_true",
- help="Whether to start a console after processing "
- "a script.")
- args = parser.parse_args()
- if args.config_file:
- config_json = json.load(args.config_file)
- else:
- config_json = {}
- config_json["log_level"] = "DEBUG"
- config_json["hosts"] = []
- host_config = {}
- host_config["cluster_ids"] = ["local-cluster-1",
- "local-cluster-2"]
- host_config["lease_interval_sec"] = 30
- config_json["hosts"].append(host_config)
-
- env_vars = env_utils.SaveAndClearEnvVars([_ANDROID_BUILD_TOP])
-
- root_logger = logging.getLogger()
- root_logger.setLevel(getattr(logging, config_json["log_level"]))
-
- tfc = None
- if args.use_tfc:
- if args.config_file:
- tfc = tfc_client.CreateTfcClient(
- config_json["tfc_api_root"],
- config_json["service_key_json_path"],
- api_name=config_json["tfc_api_name"],
- api_version=config_json["tfc_api_version"],
- scopes=config_json["tfc_scopes"])
- else:
- print("WARN: If --use_tfc is set, --config_file argument value "
- "must be provided. Starting without TFC.")
-
- pab = pab_client.PartnerAndroidBuildClient()
-
- hosts = []
- for host_config in config_json["hosts"]:
- cluster_ids = host_config["cluster_ids"]
- # If host name is not specified, use local host.
- hostname = host_config.get("hostname", socket.gethostname())
- port = host_config.get("port", remote_client.DEFAULT_PORT)
- cluster_ids = host_config["cluster_ids"]
- remote = remote_client.RemoteClient(hostname, port)
- host = host_controller.HostController(remote, tfc, hostname,
- cluster_ids)
- hosts.append(host)
- if args.poll:
- lease_interval_sec = host_config["lease_interval_sec"]
- host_thread = threading.Thread(target=host.Run,
- args=(lease_interval_sec,))
- host_thread.daemon = True
- host_thread.start()
-
- if args.poll:
- while True:
- sys.stdin.readline()
- else:
- main_console = console.Console(tfc, pab, hosts)
- if args.script:
- next_start_time = time.time()
- while main_console.ProcessScript(args.script):
- if args.loop is None:
- break
- if args.loop == 0:
- continue
- current_time = time.time()
- skip_cnt = (current_time - next_start_time) // args.loop
- if skip_cnt >= 1:
- logging.warning("Script execution time is longer than "
- "loop interval. Skip %d iteration(s).",
- skip_cnt)
- next_start_time += (skip_cnt + 1) * args.loop
- if next_start_time - current_time >= 0:
- time.sleep(next_start_time - current_time)
- else:
- logging.error("Unexpected timestamps: current=%f, next=%f",
- current_time, next_start_time)
- if args.console:
- main_console.cmdloop()
- else: # if not script, the default is console mode.
- main_console.cmdloop()
-
- env_utils.RestoreEnvVars(env_vars)
-
-
-if __name__ == "__main__":
- main()
diff --git a/harnesses/host_controller/tfc/__init__.py b/harnesses/host_controller/tfc/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/harnesses/host_controller/tfc/__init__.py
+++ /dev/null
diff --git a/harnesses/host_controller/tfc/api_message.py b/harnesses/host_controller/tfc/api_message.py
deleted file mode 100644
index d1b618e..0000000
--- a/harnesses/host_controller/tfc/api_message.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-
-class ApiMessage(object):
- """The class for the messages defined by TFC API."""
-
- def __init__(self, all_keys, **kwargs):
- """Initializes the attributes.
-
- Args:
- all_keys: A collection of attribute names.
- **kwargs: The names and values of the attributes. The names must be
- in all_keys.
-
- Raises:
- KeyError if any key in kwargs is not in all_keys.
- """
- for key, value in kwargs.iteritems():
- if key not in all_keys:
- raise KeyError(key)
- setattr(self, key, value)
-
- def ToJson(self, keys):
- """Creates a JSON object containing the specified keys.
-
- Args:
- keys: The attributes to be included in the object.
-
- Returns:
- A JSON object.
- """
- return dict((x, getattr(self, x)) for x in keys if hasattr(self, x))
diff --git a/harnesses/host_controller/tfc/command_attempt.py b/harnesses/host_controller/tfc/command_attempt.py
deleted file mode 100644
index 91b7551..0000000
--- a/harnesses/host_controller/tfc/command_attempt.py
+++ /dev/null
@@ -1,137 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import time
-
-from vts.harnesses.host_controller.tfc import api_message
-
-
-class EventType(object):
- """The types of command events."""
- ALLOCATION_FAILED = "AllocationFailed"
- CONFIGURATION_ERROR = "ConfigurationError"
- EXECUTE_FAILED = "ExecuteFailed"
- FETCH_FAILED = "FetchFailed"
- INVOCATION_COMPLETED = "InvocationCompleted"
- INVOCATION_STARTED = "InvocationStarted"
- TEST_RUN_IN_PROGRESS = "TestRunInProgress"
-
-
-class CommandAttempt(api_message.ApiMessage):
- """The command attempt defined by TFC API.
-
- Attributes:
- _COMMAND_EVENT: The parameters of command_events.submit.
- _COMMAND_EVENT_DATA: The fields in "data" parameter of command_events.
- _LIST_ATTEMPT: The fields returned by commandAttempts.list.
- """
- _COMMAND_EVENT = {
- "attempt_id",
- "data",
- "device_serial",
- "hostname",
- "task_id",
- "time",
- "type"}
- _COMMAND_EVENT_DATA = {
- "error",
- "failed_test_count",
- "summary",
- "test_run_name",
- "total_test_count"}
- _LIST_ATTEMPT = {
- "attempt_id",
- "command_id",
- "create_time",
- "end_time",
- "error",
- "device_serial",
- "failed_test_count",
- "hostname",
- "request_id",
- "start_time",
- "state",
- "status",
- "summary",
- "task_id",
- "total_test_count",
- "update_time"}
-
- def __init__(self, task_id, attempt_id, hostname, device_serial, **kwargs):
- """Initializes the attributes.
-
- Args:
- task_id: A string, the task id assigned by the server.
- attempt_id: A string or UUID, the attempt id generated by the host.
- hostname: The name of the TradeFed host.
- device_serial: The serial number of the device.
- **kwargs: The optional attributes.
- """
- super(CommandAttempt, self).__init__(self._LIST_ATTEMPT,
- task_id=task_id,
- attempt_id=str(attempt_id),
- hostname=hostname,
- device_serial=device_serial,
- **kwargs)
-
- def CreateCommandEvent(self, event_type, error=None, event_time=None):
- """Creates an event defined by command_events.submit.
-
- Args:
- event_type: A string in EventType.
- error: A string, the error message for *Failed, *Error, and
- *Completed events.
- event_time: A float, Unix timestamp of the event in seconds.
-
- Returns:
- A JSON object.
- """
- obj = self.ToJson(self._COMMAND_EVENT)
- obj["type"] = event_type
- obj["time"] = int(event_time if event_time is not None else time.time())
- data_obj = self.ToJson(self._COMMAND_EVENT_DATA)
- if error is not None:
- data_obj["error"] = error
- if data_obj:
- obj["data"] = data_obj
- return obj
-
- def CreateInvocationCompletedEvent(self,
- summary,
- total_test_count,
- failed_test_count,
- error=None,
- event_time=None):
- """Creates an InvocationCompleted event.
-
- Args:
- summary: A string, the result of the command.
- total_test_count: Number of test cases.
- failed_test_count: Number of failed test cases.
- error: A string, the error message.
- event_time: A float, Unix timestamp of the event in seconds.
-
- Returns:
- A JSON object.
- """
- obj = self.CreateCommandEvent(EventType.INVOCATION_COMPLETED,
- error, event_time)
- if "data" not in obj:
- obj["data"] = dict()
- obj["data"].update({"summary": summary,
- "total_test_count": total_test_count,
- "failed_test_count": failed_test_count})
- return obj
diff --git a/harnesses/host_controller/tfc/command_task.py b/harnesses/host_controller/tfc/command_task.py
deleted file mode 100644
index 4c2b4c9..0000000
--- a/harnesses/host_controller/tfc/command_task.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-from vts.harnesses.host_controller.tfc import api_message
-
-
-class CommandTask(api_message.ApiMessage):
- """The task of executing a command defined by TFC API.
-
- Attributes:
- _LEASE_HOST_TASK: The fields returned by commandAttempts.list.
- """
- _LEASE_HOST_TASK = {
- "request_id",
- "command_id",
- "task_id",
- "command_line",
- "request_type",
- "device_serials"}
-
- def __init__(self, task_id, command_line, device_serials, **kwargs):
- super(CommandTask, self).__init__(self._LEASE_HOST_TASK,
- task_id=task_id,
- command_line=command_line,
- device_serials=device_serials,
- **kwargs)
diff --git a/harnesses/host_controller/tfc/device_info.py b/harnesses/host_controller/tfc/device_info.py
deleted file mode 100644
index 12a3b06..0000000
--- a/harnesses/host_controller/tfc/device_info.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-from vts.harnesses.host_controller.tfc import api_message
-from vts.utils.python.controllers import android_device
-
-
-class DeviceInfo(api_message.ApiMessage):
- """The device information defined by TFC API.
-
- Attributes:
- _DEVICE_SNAPSHOT: The parameters of host_events.
- _LEASE_HOST_TASKS: The parameters of leasehosttasks.
- _OTHER: The data retrieved from TradeFed host but not used by the API.
- _ALL_KEYS: Union of above.
- """
- _DEVICE_SNAPSHOT = {
- "battery_level",
- "build_id",
- "device_serial",
- "group_name",
- "mac_address",
- "product",
- "product_variant",
- "run_target",
- "sim_operator",
- "sim_state",
- "sdk_version",
- "state"}
- _LEASE_HOST_TASKS = {
- "device_serial",
- "group_name",
- "run_target",
- "state"}
- _OTHER = {"stub"}
- _ALL_KEYS = (_DEVICE_SNAPSHOT | _LEASE_HOST_TASKS | _OTHER)
-
- def __init__(self, device_serial, **kwargs):
- """Initializes the attributes.
-
- Args:
- device_serial: The serial number of the device.
- **kwargs: The optional attributes.
- """
- super(DeviceInfo, self).__init__(self._ALL_KEYS,
- device_serial=device_serial, **kwargs)
-
- def IsAvailable(self):
- """Returns whether the device is available for running commands.
-
- Returns:
- A boolean.
- """
- return getattr(self, "state", None) == "Available"
-
- def IsStub(self):
- """Returns whether the device is a stub.
-
- Returns:
- A boolean.
- """
- return getattr(self, "stub", False)
-
- def ToDeviceSnapshotJson(self):
- """Converts to the parameter of host_events.
-
- Returns:
- A JSON object.
- """
- return self.ToJson(self._DEVICE_SNAPSHOT)
-
- def ToLeaseHostTasksJson(self):
- """Converts to the parameter of leasehosttasks.
-
- Returns:
- A JSON object.
- """
- return self.ToJson(self._LEASE_HOST_TASKS)
-
- def Extend(self, properties):
- """Adds properties to a DeviceInfo object, using AndroidDevice
-
- Args:
- properties: list of strings, list of properties to update
- """
- serial = getattr(self, "device_serial", None)
- ad = android_device.AndroidDevice(serial)
- for prop in properties:
- val = getattr(ad, prop, None)
- if val is None:
- continue
- setattr(self, prop, val)
diff --git a/harnesses/host_controller/tfc/request.py b/harnesses/host_controller/tfc/request.py
deleted file mode 100644
index 6a5b3a3..0000000
--- a/harnesses/host_controller/tfc/request.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-from vts.harnesses.host_controller.tfc import api_message
-
-
-class Request(api_message.ApiMessage):
- """The requests defined by TFC API.
-
- Attributes:
- _BODY: The requests.new parameters that are put into http message body.
- _PARAMETERS: The requests.new parameters put into http parameters.
- _ALL_KEYS: Union of above.
- """
- _BODY = {
- "command_line",
- "user"}
- _PARAMETERS = {
- "branch",
- "build_flavor",
- "build_id",
- "build_os",
- "cluster",
- "no_build_args",
- "run_target",
- "shard_count"
- "run_count"}
- _ALL_KEYS = (_BODY | _PARAMETERS)
-
- def __init__(self, cluster, command_line, run_target, user, **kwargs):
- """Initializes the attributes.
-
- Args:
- cluster: The ID of the cluster to send this request to.
- command_line: The command to execute on a host.
- run_target: The target device to run the command.
- user: The name of the user sending this request.
- **kwargs: The optional attributes.
- """
- super(Request, self).__init__(self._ALL_KEYS,
- cluster=cluster,
- command_line=command_line,
- run_target=run_target,
- user=user,
- **kwargs)
-
- def GetBody(self):
- """Returns the http message body.
-
- Returns:
- A JSON object.
- """
- return self.ToJson(self._BODY)
-
- def GetParameters(self):
- """Returns the http parameters.
-
- Returns:
- A dict of strings.
- """
- return self.ToJson(self._PARAMETERS)
diff --git a/harnesses/host_controller/tfc/tfc_client.py b/harnesses/host_controller/tfc/tfc_client.py
deleted file mode 100644
index 39a0656..0000000
--- a/harnesses/host_controller/tfc/tfc_client.py
+++ /dev/null
@@ -1,176 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import httplib2
-import logging
-import threading
-import time
-
-from apiclient import discovery
-from apiclient import http
-from oauth2client.service_account import ServiceAccountCredentials
-
-from vts.harnesses.host_controller.tfc import command_task
-
-API_NAME = "tradefed_cluster"
-API_VERSION = "v1"
-SCOPES = ['https://www.googleapis.com/auth/userinfo.email']
-
-
-class TfcClient(object):
- """The class for accessing TFC API.
-
- Attributes:
- _service: The TFC service.
- """
-
- def __init__(self, service):
- self._service = service
-
- def LeaseHostTasks(self, cluster_id, next_cluster_ids, hostname, device_infos):
- """Calls leasehosttasks.
-
- Args:
- cluster_id: A string, the primary cluster to lease tasks from.
- next_cluster_ids: A list of Strings, the secondary clusters to lease
- tasks from.
- hostname: A string, the name of the TradeFed host.
- device_infos: A list of DeviceInfo, the information about the
- devices connected to the host.
-
- Returns:
- A list of command_task.CommandTask, the leased tasks.
- """
- lease = {"hostname": hostname,
- "cluster": cluster_id,
- "next_cluster_ids": next_cluster_ids,
- "device_infos": [x.ToLeaseHostTasksJson()
- for x in device_infos]}
- logging.info("tasks.leasehosttasks body=%s", lease)
- tasks = self._service.tasks().leasehosttasks(body=lease).execute()
- logging.info("tasks.leasehosttasks response=%s", tasks)
- if "tasks" not in tasks:
- return []
- return [command_task.CommandTask(**task) for task in tasks["tasks"]]
-
- def TestResourceList(self, request_id):
- """Calls testResource.list.
-
- Args:
- request_id: int, id of request to grab resources for
-
- Returns:
- A list of TestResources
- """
- logging.info("request.testResource.list request_id=%s", request_id)
- test_resources = self._service.requests().testResource().list(request_id=request_id).execute()
- logging.info("request.testResource.list response=%s", test_resources)
- if 'test_resources' not in test_resources:
- return {}
- return test_resources['test_resources']
-
- @staticmethod
- def CreateDeviceSnapshot(cluster_id, hostname, dev_infos):
- """Creates a DeviceSnapshot which can be uploaded as host event.
-
- Args:
- cluster_id: A string, the cluster to upload snapshot to.
- hostname: A string, the name of the TradeFed host.
- dev_infos: A list of DeviceInfo.
-
- Returns:
- A JSON object.
- """
- obj = {"time": int(time.time()),
- "data": {},
- "cluster": cluster_id,
- "hostname": hostname,
- "tf_version": "(unknown)",
- "type": "DeviceSnapshot",
- "device_infos": [x.ToDeviceSnapshotJson() for x in dev_infos]}
- return obj
-
- def SubmitHostEvents(self, host_events):
- """Calls host_events.submit.
-
- Args:
- host_events: A list of JSON objects. Currently DeviceSnapshot is
- the only type of host events.
- """
- json_obj = {"host_events": host_events}
- logging.info("host_events.submit body=%s", json_obj)
- self._service.host_events().submit(body=json_obj).execute()
-
- def SubmitCommandEvents(self, command_events):
- """Calls command_events.submit.
-
- Args:
- command_events: A list of JSON objects converted from CommandAttempt.
- """
- json_obj = {"command_events": command_events}
- logging.info("command_events.submit body=%s", json_obj)
- self._service.command_events().submit(body=json_obj).execute()
-
- def NewRequest(self, request):
- """Calls requests.new.
-
- Args:
- request: An instance of Request.
-
- Returns:
- A JSON object, the new request queued in the cluster.
-
- Sample
- {'state': 'UNKNOWN',
- 'command_line': 'vts-codelab --run-target sailfish',
- 'id': '2',
- 'user': 'testuser'}
- """
- body = request.GetBody()
- params = request.GetParameters()
- logging.info("requests.new parameters=%s body=%s", params, body)
- return self._service.requests().new(body=body, **params).execute()
-
-
-def CreateTfcClient(api_root, oauth2_service_json,
- api_name=API_NAME, api_version=API_VERSION, scopes=SCOPES):
- """Builds an object of TFC service from a given URL.
-
- Args:
- api_root: The URL to the service.
- oauth2_service_json: The path to service account key file.
-
- Returns:
- A TfcClient object.
- """
- discovery_url = "%s/discovery/v1/apis/%s/%s/rest" % (
- api_root, api_name, api_version)
- logging.info("Build service from: %s", discovery_url)
- credentials = ServiceAccountCredentials.from_json_keyfile_name(
- oauth2_service_json, scopes=scopes)
- # httplib2.Http is not thread-safe. Use thread local object.
- thread_local = threading.local()
- thread_local.http = credentials.authorize(httplib2.Http())
- def BuildHttpRequest(unused_http, *args, **kwargs):
- if not hasattr(thread_local, "http"):
- thread_local.http = credentials.authorize(httplib2.Http())
- return http.HttpRequest(thread_local.http, *args, **kwargs)
-
- service = discovery.build(
- api_name, api_version, http=thread_local.http,
- discoveryServiceUrl=discovery_url,
- requestBuilder=BuildHttpRequest)
- return TfcClient(service)
diff --git a/harnesses/host_controller/tfc/tfc_client_test.py b/harnesses/host_controller/tfc/tfc_client_test.py
deleted file mode 100644
index 411d039..0000000
--- a/harnesses/host_controller/tfc/tfc_client_test.py
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 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.
-#
-
-import unittest
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
-from vts.harnesses.host_controller.tfc import tfc_client
-from vts.harnesses.host_controller.tfc import command_attempt
-from vts.harnesses.host_controller.tfc import device_info
-from vts.harnesses.host_controller.tfc import request
-
-
-class TfcClientTest(unittest.TestCase):
- """A test for tfc_client.TfcClient.
-
- Attributes:
- _client: The tfc_client.TfcClient being tested.
- _service: The mock service that _client connects to.
- """
- _DEVICE_INFOS = [device_info.DeviceInfo(
- device_serial="ABCDEF", group_name="group0",
- run_target="sailfish", state="Available")]
-
- def setUp(self):
- """Creates a TFC client connecting to a mock service."""
- self._service = mock.Mock()
- self._client = tfc_client.TfcClient(self._service)
-
- def testNewRequest(self):
- """Tests requests.new."""
- req = request.Request(cluster="cluster0",
- command_line="vts-codelab",
- run_target="sailfish",
- user="user0")
- self._client.NewRequest(req)
- self._service.assert_has_calls([
- mock.call.requests().new().execute()])
-
- def testLeaseHostTasks(self):
- """Tests tasks.leasehosttasks."""
- tasks = {"tasks": [{"request_id": "2",
- "command_line": "vts-codelab --serial ABCDEF",
- "task_id": "1-0",
- "device_serials": ["ABCDEF"],
- "command_id": "1"}]}
- self._service.tasks().leasehosttasks().execute.return_value = tasks
- self._client.LeaseHostTasks("cluster0", ["cluster1", "cluster2"],
- "host0", self._DEVICE_INFOS)
- self._service.assert_has_calls([
- mock.call.tasks().leasehosttasks().execute()])
-
- def testHostEvents(self):
- """Tests host_events.submit."""
- device_snapshots = [
- self._client.CreateDeviceSnapshot("vts-staging", "host0",
- self._DEVICE_INFOS),
- self._client.CreateDeviceSnapshot("vts-presubmit", "host0",
- self._DEVICE_INFOS)]
- self._client.SubmitHostEvents(device_snapshots)
- self._service.assert_has_calls([
- mock.call.host_events().submit().execute()])
-
- def testCommandEvents(self):
- """Tests command_events.submit."""
- cmd = command_attempt.CommandAttempt(
- task_id="321-0",
- attempt_id="abcd-1234",
- hostname="host0",
- device_serial="ABCDEF")
- expected_event = {
- "task_id": "321-0",
- "attempt_id": "abcd-1234",
- "hostname": "host0",
- "device_serial": "ABCDEF",
- "time": 1}
-
- normal_event = cmd.CreateCommandEvent(
- command_attempt.EventType.INVOCATION_STARTED,
- event_time=1)
- expected_event["type"] = command_attempt.EventType.INVOCATION_STARTED
- self.assertDictEqual(expected_event, normal_event)
-
- error_event = cmd.CreateCommandEvent(
- command_attempt.EventType.EXECUTE_FAILED,
- error="unit test", event_time=1.1)
- expected_event["type"] = command_attempt.EventType.EXECUTE_FAILED
- expected_event["data"] = {"error":"unit test"}
- self.assertDictEqual(expected_event, error_event)
-
- complete_event = cmd.CreateInvocationCompletedEvent(
- summary="complete", total_test_count=2, failed_test_count=1,
- error="unit test")
- expected_event["type"] = command_attempt.EventType.INVOCATION_COMPLETED
- expected_event["data"] = {"summary": "complete", "error": "unit test",
- "total_test_count": 2, "failed_test_count": 1}
- del expected_event["time"]
- self.assertDictContainsSubset(expected_event, complete_event)
- self.assertIn("time", complete_event)
-
- self._client.SubmitCommandEvents([
- normal_event, error_event, complete_event])
- self._service.assert_has_calls([
- mock.call.command_events().submit().execute()])
-
- def testWrongParameter(self):
- """Tests raising exception for wrong parameter name."""
- self.assertRaisesRegexp(KeyError, "sdk", device_info.DeviceInfo,
- device_serial="123", sdk="25")
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/harnesses/host_controller/tradefed/__init__.py b/harnesses/host_controller/tradefed/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/harnesses/host_controller/tradefed/__init__.py
+++ /dev/null
diff --git a/harnesses/host_controller/tradefed/remote_client.py b/harnesses/host_controller/tradefed/remote_client.py
deleted file mode 100644
index 6427676..0000000
--- a/harnesses/host_controller/tradefed/remote_client.py
+++ /dev/null
@@ -1,135 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import logging
-import socket
-import time
-
-from vts.harnesses.host_controller.tradefed import remote_operation
-
-LOCALHOST = "localhost"
-DEFAULT_PORT = 30103
-
-
-class RemoteClient(object):
- """The class for sending remote operations to TradeFed."""
-
- def __init__(self, host=LOCALHOST, port=DEFAULT_PORT, timeout=None):
- """Initializes the client of TradeFed remote manager.
-
- Args:
- _host: The host name of the remote manager.
- _port: The port of the remote manager.
- _timeout: The connect and receive timeout in seconds
- """
- self._host = host
- self._port = port
- self._timeout = timeout if timeout else socket.getdefaulttimeout()
-
- def SendOperations(self, *operations):
- """Sends a list of operations and waits for each response.
-
- Args:
- *operations: A list of remote_operation.RemoteOperation objects.
-
- Returns:
- A list of JSON objects.
-
- Raises:
- socket.error if fails to communicate with remote manager.
- remote_operation.RemoteOperationException if any operation fails or
- has no response.
- """
- op_socket = socket.create_connection((self._host, self._port),
- self._timeout)
- logging.info("Connect to %s:%d", self._host, self._port)
- try:
- if self._timeout is not None:
- op_socket.settimeout(self._timeout)
- ops_str = "\n".join(str(op) for op in operations)
- logging.info("Send: %s", ops_str)
- op_socket.send(ops_str)
- op_socket.shutdown(socket.SHUT_WR)
- resp_str = ""
- while True:
- buf = op_socket.recv(4096)
- if not buf:
- break
- resp_str += buf
- finally:
- op_socket.close()
- logging.info("Receive: %s", resp_str)
- resp_lines = [x for x in resp_str.split("\n") if x]
- if len(resp_lines) != len(operations):
- raise remote_operation.RemoteOperationException(
- "Unexpected number of responses: %d" % len(resp_lines))
- return [operations[i].ParseResponse(resp_lines[i])
- for i in range(len(resp_lines))]
-
- def SendOperation(self, operation):
- """Sends one operation and waits for its response.
-
- Args:
- operation: A remote_operation.RemoteOperation object.
-
- Returns:
- A JSON object.
-
- Raises:
- socket.error if fails to communicate with remote manager.
- remote_operation.RemoteOperationException if the operation fails or
- has no response.
- """
- return self.SendOperations(operation)[0]
-
- def ListDevices(self):
- """Sends ListDevices operation.
-
- Returns:
- A list of device_info.DeviceInfo which are the devices connected to
- the host.
- """
- json_obj = self.SendOperation(remote_operation.ListDevices())
- return remote_operation.ParseListDevicesResponse(json_obj)
-
- def WaitForCommandResult(self, serial, timeout, poll_interval=5):
- """Sends a series of operations to wait until a command finishes.
-
- Args:
- serial: The serial number of the device.
- timeout: A float, the timeout in seconds.
- poll_interval: A float, the interval of each GetLastCommandResult
- operation in seconds.
-
- Returns:
- A JSON object which is the result of the command.
- None if timeout.
-
- Sample
- {'status': 'INVOCATION_SUCCESS',
- 'free_device_state': 'AVAILABLE'}
- """
- deadline = time.time() + timeout
- get_result_op = remote_operation.GetLastCommandResult(serial)
- while True:
- result = self.SendOperation(get_result_op)
- if result["status"] != "EXECUTING":
- return result
- if time.time() > deadline:
- return None
- time.sleep(poll_interval)
- if time.time() > deadline:
- return None
diff --git a/harnesses/host_controller/tradefed/remote_client_test.py b/harnesses/host_controller/tradefed/remote_client_test.py
deleted file mode 100644
index c4d2e5d..0000000
--- a/harnesses/host_controller/tradefed/remote_client_test.py
+++ /dev/null
@@ -1,179 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2017 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.
-#
-
-import queue
-import socket
-import threading
-import unittest
-
-from vts.harnesses.host_controller.tradefed import remote_client
-from vts.harnesses.host_controller.tradefed import remote_operation
-
-
-class MockRemoteManagerThread(threading.Thread):
- """A thread which mocks remote manager.
-
- Attributes:
- HOST: Local host name.
- PORT: The port that the remote manager listens to.
- _remote_mgr_socket: The remote manager socket.
- _response_queue: A queue.Queue object containing the response strings.
- _timeout: Socket timeout in seconds.
- last_error: The exception which caused this thread to terminate.
- """
- HOST = remote_client.LOCALHOST
- PORT = 32123
-
- def __init__(self, timeout):
- """Creates and listens to remote manager socket."""
- super(MockRemoteManagerThread, self).__init__()
- self._response_queue = queue.Queue()
- self._timeout = timeout
- self.last_error = None
- self._remote_mgr_socket = socket.socket()
- try:
- self._remote_mgr_socket.settimeout(self._timeout)
- self._remote_mgr_socket.bind((self.HOST, self.PORT))
- self._remote_mgr_socket.listen(1)
- except socket.error:
- self._remote_mgr_socket.close()
-
- def _Respond(self, response_str):
- """Accepts a client connection and responds.
-
- Args:
- response_str: The response string.
- """
- (server_socket, client_address) = self._remote_mgr_socket.accept()
- try:
- server_socket.settimeout(self._timeout)
- # Receive until connection is closed
- while not server_socket.recv(4096):
- pass
- server_socket.send(response_str)
- finally:
- server_socket.close()
-
- def AddResponse(self, response_str):
- """Add a response string to the queue.
-
- Args:
- response_str: The response string.
- """
- self._response_queue.put_nowait(response_str)
-
- def CloseSocket(self):
- """Closes the remote manager socket."""
- if self._remote_mgr_socket:
- self._remote_mgr_socket.close()
- self._remote_mgr_socket = None
-
- # @Override
- def run(self):
- """Sends the queued responses to the clients."""
- try:
- while True:
- response_str = self._response_queue.get()
- self._response_queue.task_done()
- if response_str is None:
- break
- self._Respond(response_str)
- except socket.error as e:
- self.last_error = e
- finally:
- self.CloseSocket()
-
-
-class RemoteClientTest(unittest.TestCase):
- """A test for remote_client.RemoteClient.
-
- Attributes:
- _remote_mgr_thread: An instance of MockRemoteManagerThread.
- _client: The remote_client.RemoteClient being tested.
- """
-
- def setUp(self):
- """Creates remote manager thread."""
- self._remote_mgr_thread = MockRemoteManagerThread(5)
- self._remote_mgr_thread.daemon = True
- self._remote_mgr_thread.start()
- self._client = remote_client.RemoteClient(self._remote_mgr_thread.HOST,
- self._remote_mgr_thread.PORT,
- 5)
-
- def tearDown(self):
- """Terminates remote manager thread."""
- self._remote_mgr_thread.AddResponse(None)
- self._remote_mgr_thread.join(15)
- self._remote_mgr_thread.CloseSocket()
- self.assertFalse(self._remote_mgr_thread.is_alive(),
- "Cannot stop remote manager thread.")
- if self._remote_mgr_thread.last_error:
- raise self._remote_mgr_thread.last_error
-
- def testListDevice(self):
- """Tests ListDevices operation."""
- self._remote_mgr_thread.AddResponse('{"serials": []}')
- self._client.ListDevices()
-
- def testAddCommand(self):
- """Tests AddCommand operation."""
- self._remote_mgr_thread.AddResponse('{}')
- self._client.SendOperation(remote_operation.AddCommand(0, "COMMAND"))
-
- def testMultipleOperations(self):
- """Tests sending multiple operations via one connection."""
- self._remote_mgr_thread.AddResponse('{}\n{}')
- self._client.SendOperations(remote_operation.ListDevices(),
- remote_operation.ListDevices())
-
- def testExecuteCommand(self):
- """Tests executing a command and waiting for result."""
- self._remote_mgr_thread.AddResponse('{}')
- self._client.SendOperation(remote_operation.AllocateDevice("serial123"))
- self._remote_mgr_thread.AddResponse('{}')
- self._client.SendOperation(remote_operation.ExecuteCommand(
- "serial123", "vts", "-m", "SampleShellTest"))
-
- self._remote_mgr_thread.AddResponse('{"status": "EXECUTING"}')
- result = self._client.WaitForCommandResult("serial123",
- timeout=0.5, poll_interval=1)
- self.assertIsNone(result, "Client returns result before command finishes.")
-
- self._remote_mgr_thread.AddResponse('{"status": "EXECUTING"}')
- self._remote_mgr_thread.AddResponse('{"status": "INVOCATION_SUCCESS"}')
- result = self._client.WaitForCommandResult("serial123",
- timeout=5, poll_interval=1)
- self._remote_mgr_thread.AddResponse('{}')
- self._client.SendOperation(remote_operation.FreeDevice("serial123"))
- self.assertIsNotNone(result, "Client doesn't return command result.")
-
- def testSocketError(self):
- """Tests raising exception when socket error occurs."""
- self.assertRaises(socket.timeout, self._client.ListDevices)
- self._remote_mgr_thread.AddResponse(None)
- self.assertRaises(socket.error, self._client.ListDevices)
-
- def testRemoteOperationException(self):
- """Tests raising exception when response is an error."""
- self._remote_mgr_thread.AddResponse('{"error": "unit test"}')
- self.assertRaises(remote_operation.RemoteOperationException,
- self._client.ListDevices)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/harnesses/host_controller/tradefed/remote_operation.py b/harnesses/host_controller/tradefed/remote_operation.py
deleted file mode 100644
index a398954..0000000
--- a/harnesses/host_controller/tradefed/remote_operation.py
+++ /dev/null
@@ -1,172 +0,0 @@
-#
-# Copyright (C) 2017 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.
-#
-
-import json
-
-from vts.harnesses.host_controller.tfc import device_info
-
-
-class RemoteOperationException(Exception):
- """Raised when remote operation fails."""
- pass
-
-
-class RemoteOperation(object):
- """The operation sent to TradeFed remote manager.
-
- Args:
- _obj: A JSON object with at least 2 entries, "type" and "version".
- """
- CURRENT_PROTOCOL_VERSION = 8
-
- def __init__(self, type, **kwargs):
- """Initializes a remote operation.
-
- Args:
- type: A string, the type of the operation.
- **kwargs: The arguments which are specific to the operation type.
- """
- self._obj = kwargs
- self._obj["type"] = type
- if "version" not in self._obj:
- self._obj["version"] = self.CURRENT_PROTOCOL_VERSION
-
- def ParseResponse(self, response_str):
- """Parses the response to the operation.
-
- Args:
- response_str: A JSON string.
-
- Returns:
- A JSON object.
-
- Raises:
- RemoteOperationException if the response is an error.
- """
- response = json.loads(response_str)
- if "error" in response:
- raise RemoteOperationException(response["error"])
- return response
-
- @property
- def type(self):
- """Returns the type of this operation."""
- return self._obj["type"]
-
- def __str__(self):
- """Converts the JSON object to string."""
- return json.dumps(self._obj)
-
-
-def ListDevices():
- """Creates an operation of listing devices."""
- return RemoteOperation("LIST_DEVICES")
-
-
-def ParseListDevicesResponse(json_obj):
- """Parses ListDevices response to a list of DeviceInfo.
-
- Sample response:
- {"serials": [
- {"product": "unknown", "battery": "0", "variant": "unknown",
- "stub": True, "state": "Available", "build": "unknown",
- "serial": "emulator-5554", "sdk": "unknown"},
- ]}
-
- Args:
- json_obj: A JSON object, the response to ListDevices.
-
- Returns:
- A list of DeviceInfo object.
- """
- dev_infos = []
- for dev_obj in json_obj["serials"]:
- if dev_obj["product"] == dev_obj["variant"]:
- run_target = dev_obj["product"]
- else:
- run_target = dev_obj["product"] + ":" + dev_obj["variant"]
- dev_info = device_info.DeviceInfo(
- battery_level=dev_obj["battery"],
- build_id=dev_obj["build"],
- device_serial=dev_obj["serial"],
- product=dev_obj["product"],
- product_variant=dev_obj["variant"],
- run_target=run_target,
- sdk_version=dev_obj["sdk"],
- state=dev_obj["state"],
- stub=dev_obj["stub"])
- dev_infos.append(dev_info)
- return dev_infos
-
-
-def AllocateDevice(serial):
- """Creates an operation of allocating a device.
-
- Args:
- serial: The serial number of the device.
- """
- return RemoteOperation("ALLOCATE_DEVICE", serial=serial)
-
-
-def FreeDevice(serial):
- """Creates an operation of freeing a device.
-
- Args:
- serial: The serial number of the device.
- """
- return RemoteOperation("FREE_DEVICE", serial=serial)
-
-
-def Close():
- """Creates an operation of stopping the remote manager."""
- return RemoteOperation("CLOSE")
-
-
-def AddCommand(time, *command_args):
- """Creates an operation of adding a command to the queue.
-
- Args:
- time: The time in ms that the command has been executing for. The value
- is non-zero in handover situation.
- command_args: The command to execute.
- """
- return RemoteOperation("ADD_COMMAND", time=time, commandArgs=command_args)
-
-
-def ExecuteCommand(serial, *command_args):
- """Creates an operation of executing a command on a device.
-
- Args:
- serial: The serial number of the device.
- command_args: The command to execute.
- """
- return RemoteOperation(
- "EXEC_COMMAND", serial=serial, commandArgs=command_args)
-
-
-def GetLastCommandResult(serial):
- """Creates an operation of getting last EXEC_COMMAND result on a device.
-
- Sample response:
- {"status": "INVOCATION_ERROR",
- "invocation_error": "java.lang.NullPointerException",
- "free_device_state": "AVAILABLE"
- }
-
- Args:
- serial: The serial number of the device.
- """
- return RemoteOperation("GET_LAST_COMMAND_RESULT", serial=serial)
diff --git a/harnesses/tradefed/src/com/android/compatibility/common/tradefed/build/VtsCompatibilityInvocationHelper.java b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/build/VtsCompatibilityInvocationHelper.java
index 6cbf889..0f06866 100644
--- a/harnesses/tradefed/src/com/android/compatibility/common/tradefed/build/VtsCompatibilityInvocationHelper.java
+++ b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/build/VtsCompatibilityInvocationHelper.java
@@ -15,6 +15,8 @@
*/
package com.android.compatibility.common.tradefed.build;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.suite.TestSuiteInfo;
import java.io.File;
@@ -31,23 +33,30 @@
*/
public File getTestsDir() throws FileNotFoundException {
if (mTestCasesDir == null) {
- String rootDirPath = null;
-
- rootDirPath = System.getProperty(String.format("%s_ROOT",
- TestSuiteInfo.getInstance().getName()), rootDirPath);
- if (rootDirPath == null || rootDirPath.trim().equals("")) {
- throw new IllegalArgumentException(
- String.format("Missing install path property %s_ROOT",
- TestSuiteInfo.getInstance().getName()));
+ String testCasesRootDirPath;
+ testCasesRootDirPath = System.getenv(
+ String.format("%s_TESTCASES", TestSuiteInfo.getInstance().getName()));
+ File testCaseDir;
+ if (testCasesRootDirPath != null && !testCasesRootDirPath.trim().equals("")) {
+ testCaseDir = new File(testCasesRootDirPath);
+ } else {
+ String rootDirPath;
+ rootDirPath = System.getProperty(
+ String.format("%s_ROOT", TestSuiteInfo.getInstance().getName()));
+ if (rootDirPath == null || rootDirPath.trim().equals("")) {
+ throw new IllegalArgumentException(
+ String.format("Missing install path property %s_ROOT",
+ TestSuiteInfo.getInstance().getName()));
+ }
+ testCaseDir = new File(rootDirPath, "android-vts/testcases");
}
-
- File testCaseDir = new File(rootDirPath, "android-vts/testcases");
if (!testCaseDir.exists()) {
throw new FileNotFoundException(String.format(
"Root directory doesn't exist %s", testCaseDir.getAbsolutePath()));
}
-
mTestCasesDir = testCaseDir.getAbsoluteFile();
+ CLog.d(String.format(
+ "%s TEST CASES DIR: %s", TestSuiteInfo.getInstance().getName(), mTestCasesDir));
}
return mTestCasesDir;
diff --git a/harnesses/tradefed/src/com/android/compatibility/common/tradefed/targetprep/VtsFilePusher.java b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/targetprep/VtsFilePusher.java
index a9ceb89..e22c058 100644
--- a/harnesses/tradefed/src/com/android/compatibility/common/tradefed/targetprep/VtsFilePusher.java
+++ b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/targetprep/VtsFilePusher.java
@@ -228,13 +228,15 @@
*/
@Override
public File resolveRelativeFilePath(IBuildInfo buildInfo, String fileName) {
+ File f = null;
try {
- File f = new File(mInvocationHelper.getTestsDir(),
+ f = new File(mInvocationHelper.getTestsDir(),
String.format("%s%s", fileName, mAppendBitness ? mAbi.getBitness() : ""));
- CLog.logAndDisplay(LogLevel.INFO, "Copying from %s", f.getAbsolutePath());
+ CLog.d("Copying from %s", f.getAbsolutePath());
return f;
} catch (FileNotFoundException e) {
- e.printStackTrace();
+ CLog.e(e);
+ CLog.e("File not found: %s", f);
}
return null;
}
diff --git a/harnesses/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestMultiDevice.java b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestMultiDevice.java
new file mode 100644
index 0000000..99edfec
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestMultiDevice.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.compatibility.common.tradefed.util.RetryFilterHelper;
+import com.android.compatibility.common.tradefed.util.VtsRetryFilterHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.config.OptionCopier;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.IMultiDeviceTest;
+import com.android.tradefed.testtype.IInvocationContextReceiver;
+import com.android.tradefed.testtype.IRemoteTest;
+
+import java.io.FileNotFoundException;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * A Test for running Compatibility Suites
+ */
+@OptionClass(alias = "compatibility")
+public class CompatibilityTestMultiDevice extends CompatibilityTest implements IMultiDeviceTest {
+ private Map<ITestDevice, IBuildInfo> mDeviceInfos = null;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setDeviceInfos(Map<ITestDevice, IBuildInfo> deviceInfos) {
+ mDeviceInfos = deviceInfos;
+ }
+
+ /**
+ * Create a new {@link CompatibilityTest} that will run a sublist of
+ * modules.
+ */
+ public CompatibilityTestMultiDevice(
+ int totalShards, IModuleRepo moduleRepo, Integer shardIndex) {
+ super(totalShards, moduleRepo, shardIndex);
+ }
+
+ /**
+ * Create a new {@link CompatibilityTestMultiDevice} that will run the default list of
+ * modules.
+ */
+ public CompatibilityTestMultiDevice() {
+ super(1 /* totalShards */, new ModuleRepoMultiDevice(), 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected synchronized LinkedList<IModuleDef> initializeModuleRepo()
+ throws DeviceNotAvailableException, FileNotFoundException {
+ ((ModuleRepoMultiDevice) getModuleRepo()).setInvocationContext(getInvocationContext());
+ ((ModuleRepoMultiDevice) getModuleRepo()).setDeviceInfos(mDeviceInfos);
+
+ LinkedList<IModuleDef> modules = super.initializeModuleRepo();
+
+ for (IModuleDef module : modules) {
+ if (module instanceof IMultiDeviceTest) {
+ ((IMultiDeviceTest) module).setDeviceInfos(mDeviceInfos);
+ }
+
+ if (module instanceof IInvocationContextReceiver) {
+ ((IInvocationContextReceiver) module).setInvocationContext(getInvocationContext());
+ }
+ }
+
+ return modules;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IRemoteTest getTestShard(int shardCount, int shardIndex) {
+ CompatibilityTestMultiDevice test =
+ new CompatibilityTestMultiDevice(shardCount, getModuleRepo(), shardIndex);
+ OptionCopier.copyOptionsNoThrow(this, test);
+ // Set the shard count because the copy option on the previous line
+ // copies over the mShard value
+ try {
+ OptionSetter setter = new OptionSetter(test);
+ setter.setOptionValue("shards", "0");
+ } catch (ConfigurationException e) {
+ CLog.e(e);
+ }
+ return test;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected RetryFilterHelper createRetryFilterHelper(Integer retrySessionId) {
+ return new VtsRetryFilterHelper(getBuildHelper(), retrySessionId, getSubPlan(),
+ getIncludeFilters(), getExcludeFilters(), getAbiName(), getModuleName(),
+ getTestName(), getRetryType());
+ }
+}
\ No newline at end of file
diff --git a/harnesses/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDefMultiDevice.java b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDefMultiDevice.java
new file mode 100644
index 0000000..22907d2
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDefMultiDevice.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.ConfigurationDescriptor;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.multi.IMultiTargetPreparer;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IInvocationContextReceiver;
+import com.android.tradefed.testtype.IMultiDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Container for Compatibility test module info.
+ */
+public class ModuleDefMultiDevice
+ extends ModuleDef implements IMultiDeviceTest, IInvocationContextReceiver {
+ private Map<ITestDevice, IBuildInfo> mDeviceInfos = null;
+ private IInvocationContext mInvocationContext = null;
+ private List<IMultiTargetPreparer> mMultiPreparers = new ArrayList<>();
+
+ public ModuleDefMultiDevice(String name, IAbi abi, IRemoteTest test,
+ List<ITargetPreparer> preparersSingleDevice, List<IMultiTargetPreparer> preparers,
+ ConfigurationDescriptor configurationDescriptor) {
+ super(name, abi, test, preparersSingleDevice, configurationDescriptor);
+
+ boolean hasAbiReceiver = false;
+ for (IMultiTargetPreparer preparer : preparers) {
+ if (preparer instanceof IAbiReceiver) {
+ hasAbiReceiver = true;
+ break;
+ }
+ }
+ for (ITargetPreparer preparer : preparersSingleDevice) {
+ if (preparer instanceof IAbiReceiver) {
+ hasAbiReceiver = true;
+ break;
+ }
+ }
+
+ mMultiPreparers = preparers;
+
+ // Required interfaces:
+ super.checkRequiredInterfaces(hasAbiReceiver);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setDeviceInfos(Map<ITestDevice, IBuildInfo> deviceInfos) {
+ mDeviceInfos = deviceInfos;
+ }
+
+ /**
+ * Getter method for mDeviceInfos.
+ */
+ public Map<ITestDevice, IBuildInfo> getDeviceInfos() {
+ return mDeviceInfos;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setInvocationContext(IInvocationContext invocationContext) {
+ mInvocationContext = invocationContext;
+ }
+
+ /**
+ * Getter method for mInvocationContext.
+ */
+ public IInvocationContext getInvocationContext() {
+ return mInvocationContext;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void prepareTestClass() {
+ super.prepareTestClass();
+
+ IRemoteTest test = getTest();
+ if (test instanceof IMultiDeviceTest) {
+ ((IMultiDeviceTest) test).setDeviceInfos(mDeviceInfos);
+ }
+
+ if (test instanceof IInvocationContextReceiver) {
+ ((IInvocationContextReceiver) test).setInvocationContext(mInvocationContext);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void runPreparerSetups() throws DeviceNotAvailableException {
+ super.runPreparerSetups();
+
+ for (IMultiTargetPreparer preparer : mMultiPreparers) {
+ String preparerName = preparer.getClass().getCanonicalName();
+ if (!getPreparerWhitelist().isEmpty()
+ && !getPreparerWhitelist().contains(preparerName)) {
+ CLog.w("Skipping Preparer: %s since it is not in the whitelist %s", preparerName,
+ getPreparerWhitelist());
+ return;
+ }
+
+ CLog.d("MultiDevicePreparer: %s", preparer.getClass().getSimpleName());
+
+ if (preparer instanceof IAbiReceiver) {
+ ((IAbiReceiver) preparer).setAbi(getAbi());
+ }
+
+ try {
+ preparer.setUp(mInvocationContext);
+ } catch (BuildError e) {
+ // This should only happen for flashing new build
+ CLog.e("Unexpected BuildError from multi-device preparer: %s",
+ preparer.getClass().getCanonicalName());
+ throw new RuntimeException(e);
+ } catch (TargetSetupError e) {
+ // log preparer class then rethrow & let caller handle
+ CLog.e("TargetSetupError in multi-device preparer: %s",
+ preparer.getClass().getCanonicalName());
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+ super.run(listener);
+
+ // Tear down
+ for (int i = mMultiPreparers.size() - 1; i >= 0; i--) {
+ IMultiTargetPreparer cleaner = mMultiPreparers.get(i);
+ CLog.d("MultiDeviceCleaner: %s", cleaner.getClass().getSimpleName());
+ cleaner.tearDown(mInvocationContext, null);
+ }
+ }
+}
diff --git a/harnesses/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoMultiDevice.java b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoMultiDevice.java
new file mode 100644
index 0000000..f1f4bde
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoMultiDevice.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IInvocationContextReceiver;
+import com.android.tradefed.testtype.IMultiDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Retrieves Compatibility multi-device test module definitions from the repository.
+ */
+public class ModuleRepoMultiDevice
+ extends ModuleRepo implements IMultiDeviceTest, IInvocationContextReceiver {
+ private Map<ITestDevice, IBuildInfo> mDeviceInfos = null;
+ private IInvocationContext mInvocationContext = null;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setDeviceInfos(Map<ITestDevice, IBuildInfo> deviceInfos) {
+ mDeviceInfos = deviceInfos;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setInvocationContext(IInvocationContext invocationContext) {
+ mInvocationContext = invocationContext;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addModuleDef(String name, IAbi abi, IRemoteTest test, String[] configPaths)
+ throws ConfigurationException {
+ // Invokes parser to process the test module config file
+ IConfiguration config = getConfigFactory().createConfigurationFromArgs(configPaths);
+
+ List<ITargetPreparer> preparers = new ArrayList<ITargetPreparer>();
+
+ if (mDeviceInfos.size() <= 1) {
+ preparers = config.getTargetPreparers();
+ }
+
+ addModuleDef(new ModuleDefMultiDevice(name, abi, test, preparers,
+ config.getMultiTargetPreparers(), config.getConfigurationDescription()));
+ }
+}
diff --git a/harnesses/tradefed/src/com/android/compatibility/common/tradefed/util/VtsRetryFilterHelper.java b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/util/VtsRetryFilterHelper.java
new file mode 100644
index 0000000..c573b1c
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/compatibility/common/tradefed/util/VtsRetryFilterHelper.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.compatibility.common.tradefed.util;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.util.RetryFilterHelper;
+import com.android.compatibility.common.tradefed.util.RetryType;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import java.util.Set;
+
+/**
+ * Helper for generating --include-filter and --exclude-filter values on compatibility retry.
+ */
+public class VtsRetryFilterHelper extends RetryFilterHelper {
+ /* Instance variables for retrieving results to be retried. */
+ private int mSessionId;
+
+ /**
+ * Constructor for a {@link VtsRetryFilterHelper}.
+ *
+ * @param build a {@link CompatibilityBuildHelper} describing the build.
+ * @param sessionId The ID of the session to retry.
+ * @param subPlan The name of a subPlan to be used. Can be null.
+ * @param includeFilters The include module filters to apply
+ * @param excludeFilters The exclude module filters to apply
+ * @param abiName The name of abi to use. Can be null.
+ * @param moduleName The name of the module to run. Can be null.
+ * @param testName The name of the test to run. Can be null.
+ * @param retryType The type of results to retry. Can be null.
+ */
+ public VtsRetryFilterHelper(CompatibilityBuildHelper build, int sessionId, String subPlan,
+ Set<String> includeFilters, Set<String> excludeFilters, String abiName,
+ String moduleName, String testName, RetryType retryType) {
+ super(build, sessionId, subPlan, includeFilters, excludeFilters, abiName, moduleName,
+ testName, retryType);
+ mSessionId = sessionId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void validateBuildFingerprint(ITestDevice device) throws DeviceNotAvailableException {
+ IInvocationResult result = getResult();
+ String oldVendorFingerprint = result.getBuildFingerprint();
+ String currentVendorFingerprint = device.getProperty("ro.vendor.build.fingerprint");
+ if (!oldVendorFingerprint.equals(currentVendorFingerprint)) {
+ throw new IllegalArgumentException(
+ String.format("Device vendor fingerprint must match %s to retry session %d",
+ oldVendorFingerprint, mSessionId));
+ }
+ }
+}
diff --git a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsCoveragePreparer.java b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsCoveragePreparer.java
index 0ae0019..1137500 100644
--- a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsCoveragePreparer.java
+++ b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsCoveragePreparer.java
@@ -16,22 +16,25 @@
package com.android.tradefed.targetprep;
-import com.android.compatibility.common.tradefed.build.VtsCompatibilityInvocationHelper;
+import com.android.annotations.VisibleForTesting;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.TargetSetupError;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.IRunUtil;
import com.android.tradefed.util.RunUtil;
import com.android.tradefed.util.VtsVendorConfigFileUtil;
-import java.io.File;
-import java.io.IOException;
-import java.util.NoSuchElementException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
/**
* Preparer class for sanitizer and gcov coverage.
*
@@ -42,38 +45,61 @@
*/
@OptionClass(alias = "vts-coverage-preparer")
public class VtsCoveragePreparer implements ITargetPreparer, ITargetCleaner {
- private static final long BASE_TIMEOUT = 1000 * 60 * 20; // timeout for fetching artifacts
- private static final String BUILD_INFO_ARTIFACT = "BUILD_INFO"; // name of build info artifact
- private static final String GCOV_PROPERTY = "ro.vts.coverage"; // indicates gcov when val is 1
- private static final String GCOV_ARTIFACT = "%s-coverage-%s.zip"; // gcov coverage artifact
- private static final String GCOV_FILE_NAME = "gcov.zip"; // gcov zip file to pass to VTS
+ static final long BASE_TIMEOUT = 1000 * 60 * 20; // timeout for fetching artifacts
+ static final String BUILD_INFO_ARTIFACT = "BUILD_INFO"; // name of build info artifact
+ static final String GCOV_PROPERTY = "ro.vts.coverage"; // indicates gcov when val is 1
+ static final String GCOV_ARTIFACT = "%s-coverage-%s.zip"; // gcov coverage artifact
+ static final String GCOV_FILE_NAME = "gcov.zip"; // gcov zip file to pass to VTS
- private static final String SELINUX_DISABLED = "Disabled"; // selinux disabled
- private static final String SELINUX_ENFORCING = "Enforcing"; // selinux enforcing mode
- private static final String SELINUX_PERMISSIVE = "Permissive"; // selinux permissive mode
+ static final String SELINUX_DISABLED = "Disabled"; // selinux disabled
+ static final String SELINUX_ENFORCING = "Enforcing"; // selinux enforcing mode
+ static final String SELINUX_PERMISSIVE = "Permissive"; // selinux permissive mode
- private static final String SYMBOLS_ARTIFACT = "%s-symbols-%s.zip"; // symbolized binary zip
- private static final String SYMBOLS_FILE_NAME = "symbols.zip"; // sancov zip to pass to VTS
- private static final String SANCOV_FLAVOR = "_asan_coverage"; // sancov device build flavor
+ static final String SYMBOLS_ARTIFACT = "%s-symbols-%s.zip"; // symbolized binary zip
+ static final String SYMBOLS_FILE_NAME = "symbols.zip"; // sancov zip to pass to VTS
+ static final String SANCOV_FLAVOR = "_asan_coverage"; // sancov device build flavor
+
+ // Path to store coverage data on the target.
+ static final String COVERAGE_DATA_PATH = "/data/misc/trace/";
+ // Path to store coverage report.
+ static final String COVERAGE_REPORT_PATH = "coverage_report_path";
// Build key for gcov resources
- private static final String GCOV_RESOURCES_KEY = "gcov-resources-path-%s";
+ static final String GCOV_RESOURCES_KEY = "gcov-resources-path-%s";
// Buid key for sancov resources
- private static final String SANCOV_RESOURCES_KEY = "sancov-resources-path-%s";
+ static final String SANCOV_RESOURCES_KEY = "sancov-resources-path-%s";
// Relative path to coverage configure binary in VTS package
- private static final String COVERAGE_CONFIGURE_SRC = "DATA/bin/vts_coverage_configure";
+ static final String COVERAGE_CONFIGURE_SRC = "DATA/bin/vts_coverage_configure";
// Target path for coverage configure binary, will be removed in teardown
- private static final String COVERAGE_CONFIGURE_DST = "/data/local/tmp/vts_coverage_configure";
+ static final String COVERAGE_CONFIGURE_DST = "/data/local/tmp/vts_coverage_configure";
- private File mDeviceInfoPath = null; // host path where gcov device artifacts are stored
+ // Default path to store coverage reports.
+ static final String DEFAULT_COVRAGE_REPORT_PATH = "/tmp/vts-coverage-report/";
+
+ // Default path to store coverage resource files locally.
+ static final String DEFAULT_LOCAL_COVERAGE_RESOURCE_PATH = "/tmp/coverage/";
+
+ private File mDeviceInfoPath = null; // host path where coverage device artifacts are stored
private String mEnforcingState = null; // start state for selinux enforcement
+ private IRunUtil mRunUtil = null;
+
+ @Option(name = "use-local-artifects", description = "Whether to use local artifacts.")
+ private boolean mUseLocalArtifects = false;
+
+ @Option(name = "local-coverage-resource-path",
+ description = "Path to look for local artifacts.")
+ private String mLocalCoverageResourcePath = DEFAULT_LOCAL_COVERAGE_RESOURCE_PATH;
+
+ @Option(name = "coverage-report-dir", description = "Local directory to store coverage report.")
+ private String mCoverageReportDir = null;
/** {@inheritDoc} */
@Override
- public void setUp(ITestDevice device, IBuildInfo buildInfo) throws DeviceNotAvailableException {
+ public void setUp(ITestDevice device, IBuildInfo buildInfo)
+ throws DeviceNotAvailableException, TargetSetupError {
String flavor = device.getBuildFlavor();
String buildId = device.getBuildId();
@@ -88,32 +114,37 @@
boolean gcovEnabled = (coverageProperty != null) && coverageProperty.equals("1");
if (!sancovEnabled && !gcovEnabled) {
+ CLog.d("Coverage disabled.");
return;
}
if (sancovEnabled) {
- CLog.i("Sanitizer coverage processing enabled.");
+ CLog.d("Sanitizer coverage processing enabled.");
}
if (gcovEnabled) {
- CLog.i("Gcov coverage processing enabled.");
+ CLog.d("Gcov coverage processing enabled.");
}
- IRunUtil runUtil = new RunUtil();
- VtsCompatibilityInvocationHelper invocationHelper = new VtsCompatibilityInvocationHelper();
+ if (mRunUtil == null) {
+ mRunUtil = new RunUtil();
+ }
- try {
+ CompatibilityBuildHelper buildHelper = createBuildHelper(buildInfo);
+ if (!mUseLocalArtifects) {
// Load the vendor configuration
- String artifactFetcher = null;
- VtsVendorConfigFileUtil configFileUtil = new VtsVendorConfigFileUtil();
- if (configFileUtil.LoadVendorConfig(buildInfo)) {
- artifactFetcher = configFileUtil.GetVendorConfigVariable("build_artifact_fetcher");
- }
+ String artifactFetcher = getArtifactFetcher(buildInfo);
if (artifactFetcher == null) {
- CLog.e("Vendor configuration with build_artifact_fetcher required.");
- return;
+ throw new TargetSetupError(
+ "Vendor configuration with build_artifact_fetcher required.");
}
- // Create a temporary coverage directory
- mDeviceInfoPath = FileUtil.createTempDir(device.getSerialNumber());
+ try {
+ // Create a temporary coverage directory
+ mDeviceInfoPath = createTempDir(device);
+ } catch (IOException e) {
+ cleanupCoverageData(device);
+ throw new TargetSetupError(
+ "Failed to create temp dir to store coverage resource files.");
+ }
if (sancovEnabled) {
// Fetch the symbolized binaries
@@ -124,11 +155,11 @@
String cmdString = String.format(artifactFetcher, buildId, flavor, artifactName,
artifactFile.getAbsolutePath().toString());
String[] cmd = cmdString.split("\\s+");
- CommandResult commandResult = runUtil.runTimedCmd(BASE_TIMEOUT, cmd);
+ CommandResult commandResult = mRunUtil.runTimedCmd(BASE_TIMEOUT, cmd);
if (commandResult == null || commandResult.getStatus() != CommandStatus.SUCCESS
|| !artifactFile.exists()) {
- CLog.e("Could not fetch unstripped binaries.");
- return;
+ cleanupCoverageData(device);
+ throw new TargetSetupError("Could not fetch unstripped binaries.");
}
}
@@ -141,11 +172,11 @@
String cmdString = String.format(artifactFetcher, buildId, flavor, artifactName,
artifactFile.getAbsolutePath().toString());
String[] cmd = cmdString.split("\\s+");
- CommandResult commandResult = runUtil.runTimedCmd(BASE_TIMEOUT, cmd);
+ CommandResult commandResult = mRunUtil.runTimedCmd(BASE_TIMEOUT, cmd);
if (commandResult == null || commandResult.getStatus() != CommandStatus.SUCCESS
|| !artifactFile.exists()) {
- CLog.e("Could not fetch gcov build artifacts.");
- return;
+ cleanupCoverageData(device);
+ throw new TargetSetupError("Could not fetch gcov build artifacts.");
}
}
@@ -153,37 +184,65 @@
String cmdString = String.format(artifactFetcher, buildId, flavor, BUILD_INFO_ARTIFACT,
mDeviceInfoPath.getAbsolutePath().toString());
String[] cmd = cmdString.split("\\s+");
- CommandResult commandResult = runUtil.runTimedCmd(BASE_TIMEOUT, cmd);
+ CommandResult commandResult = mRunUtil.runTimedCmd(BASE_TIMEOUT, cmd);
File artifactFile = new File(mDeviceInfoPath, BUILD_INFO_ARTIFACT);
if (commandResult == null || commandResult.getStatus() != CommandStatus.SUCCESS
|| !artifactFile.exists()) {
- CLog.e("Could not fetch build info.");
- mDeviceInfoPath = null;
- return;
+ cleanupCoverageData(device);
+ throw new TargetSetupError("Could not fetch build info.");
}
+ } else {
+ mDeviceInfoPath = new File(mLocalCoverageResourcePath);
+ String fileName = sancovEnabled ? SYMBOLS_FILE_NAME : GCOV_FILE_NAME;
+ File artifactFile = new File(mDeviceInfoPath, fileName);
+ if (!artifactFile.exists()) {
+ cleanupCoverageData(device);
+ throw new TargetSetupError(String.format("Could not find %s under %s.",
+ GCOV_FILE_NAME, mDeviceInfoPath.getAbsolutePath()));
+ }
+ File buildInfoArtifact = new File(mDeviceInfoPath, BUILD_INFO_ARTIFACT);
+ if (!buildInfoArtifact.exists()) {
+ cleanupCoverageData(device);
+ throw new TargetSetupError(String.format("Could not find %s under %s.",
+ BUILD_INFO_ARTIFACT, mDeviceInfoPath.getAbsolutePath()));
+ }
+ }
- // Push the sancov flushing tool
- File configureSrc = new File(invocationHelper.getTestsDir(), COVERAGE_CONFIGURE_SRC);
+ try {
+ // Push the coverage configure tool
+ File configureSrc = new File(buildHelper.getTestsDir(), COVERAGE_CONFIGURE_SRC);
device.pushFile(configureSrc, COVERAGE_CONFIGURE_DST);
- device.executeShellCommand("rm -rf /data/misc/trace/*");
- mEnforcingState = device.executeShellCommand("getenforce");
- if (!mEnforcingState.equals(SELINUX_DISABLED)
- && !mEnforcingState.equals(SELINUX_PERMISSIVE)) {
- device.executeShellCommand("setenforce " + SELINUX_PERMISSIVE);
- }
+ } catch (FileNotFoundException e) {
+ cleanupCoverageData(device);
+ throw new TargetSetupError("Failed to push the vts coverage configure tool.");
+ }
- if (sancovEnabled) {
- buildInfo.setFile(
- getSancovResourceDirKey(device), mDeviceInfoPath, buildInfo.getBuildId());
+ if (mCoverageReportDir != null) {
+ try {
+ File resultDir = buildHelper.getResultDir();
+ File coverageDir = new File(resultDir, mCoverageReportDir);
+ buildInfo.addBuildAttribute(COVERAGE_REPORT_PATH, coverageDir.getAbsolutePath());
+ } catch (FileNotFoundException e) {
+ cleanupCoverageData(device);
+ throw new TargetSetupError("Failed to get coverageDir.");
}
+ }
- if (gcovEnabled) {
- buildInfo.setFile(
- getGcovResourceDirKey(device), mDeviceInfoPath, buildInfo.getBuildId());
- }
- } catch (IOException | NoSuchElementException e) {
- CLog.e("Could not set up sanitizer coverage: " + e.toString());
- mDeviceInfoPath = null;
+ device.executeShellCommand(String.format("rm -rf %s/*", COVERAGE_DATA_PATH));
+ mEnforcingState = device.executeShellCommand("getenforce");
+ if (!mEnforcingState.equals(SELINUX_DISABLED)
+ && !mEnforcingState.equals(SELINUX_PERMISSIVE)) {
+ device.executeShellCommand("setenforce " + SELINUX_PERMISSIVE);
+ }
+
+ if (sancovEnabled) {
+ buildInfo.setFile(
+ getSancovResourceDirKey(device), mDeviceInfoPath, buildInfo.getBuildId());
+ }
+
+ if (gcovEnabled) {
+ buildInfo.setFile(
+ getGcovResourceDirKey(device), mDeviceInfoPath, buildInfo.getBuildId());
}
}
@@ -191,15 +250,10 @@
@Override
public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
throws DeviceNotAvailableException {
- // Clear the temporary directories.
if (mEnforcingState != null && !mEnforcingState.equals(SELINUX_DISABLED)) {
device.executeShellCommand("setenforce " + mEnforcingState);
}
- if (mDeviceInfoPath != null) {
- FileUtil.recursiveDelete(mDeviceInfoPath);
- device.executeShellCommand("rm -r " + COVERAGE_CONFIGURE_DST);
- }
- device.executeShellCommand("rm -rf /data/misc/trace/*");
+ cleanupCoverageData(device);
}
/**
@@ -221,4 +275,39 @@
public static String getGcovResourceDirKey(ITestDevice device) {
return String.format(GCOV_RESOURCES_KEY, device.getSerialNumber());
}
+
+ /**
+ * Cleanup the coverage data on target and host.
+ *
+ * @param device the target device.
+ */
+ private void cleanupCoverageData(ITestDevice device) throws DeviceNotAvailableException {
+ if (mDeviceInfoPath != null) {
+ FileUtil.recursiveDelete(mDeviceInfoPath);
+ }
+ device.executeShellCommand("rm -r " + COVERAGE_CONFIGURE_DST);
+ device.executeShellCommand(String.format("rm -rf %s/*", COVERAGE_DATA_PATH));
+ }
+
+ @VisibleForTesting
+ File createTempDir(ITestDevice device) throws IOException {
+ return FileUtil.createTempDir(device.getSerialNumber());
+ }
+
+ @VisibleForTesting
+ String getArtifactFetcher(IBuildInfo buildInfo) {
+ VtsVendorConfigFileUtil configFileUtil = new VtsVendorConfigFileUtil();
+ if (configFileUtil.LoadVendorConfig(buildInfo)) {
+ return configFileUtil.GetVendorConfigVariable("build_artifact_fetcher");
+ }
+ return null;
+ }
+
+ /**
+ * Create and return a {@link CompatibilityBuildHelper} to use during the preparer.
+ */
+ @VisibleForTesting
+ CompatibilityBuildHelper createBuildHelper(IBuildInfo buildInfo) {
+ return new CompatibilityBuildHelper(buildInfo);
+ }
}
diff --git a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsDeviceInfoCollector.java b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsDeviceInfoCollector.java
index 8369a2d..49994fb 100644
--- a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsDeviceInfoCollector.java
+++ b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsDeviceInfoCollector.java
@@ -17,26 +17,27 @@
package com.android.tradefed.targetprep;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.targetprep.BuildError;
-import com.android.tradefed.targetprep.TargetSetupError;
import com.android.tradefed.util.ArrayUtil;
-
-import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
- * Collects device info.
- * This's a fork of DeviceInfoCollector and is forked in order to simplify the change
- * deployment process and reduce the deployment time, which are critical for VTS services.
+ * Collects device info. This's a fork of DeviceInfoCollector and is forked in order to simplify the
+ * change deployment process and reduce the deployment time, which are critical for VTS services.
*/
-public class VtsDeviceInfoCollector implements ITargetPreparer {
-
+public class VtsDeviceInfoCollector implements ITargetPreparer, ITargetCleaner {
// TODO(trong): remove "cts:" prefix, will need a custom ResultReporter.
private static final Map<String, String> BUILD_KEYS = new HashMap<>();
+ private static final Map<String, String> BUILD_LEGACY_PROPERTIES = new HashMap<>();
+ private static final long REBOOT_TIMEOUT = 1000 * 60 * 2; // 2 minutes.
+
+ @Option(name = "disable-framework", description = "Initialize device by stopping framework.")
+ private boolean mDisableFramework = false;
+
static {
BUILD_KEYS.put("cts:build_id", "ro.build.id");
BUILD_KEYS.put("cts:build_product", "ro.product.name");
@@ -61,16 +62,46 @@
BUILD_KEYS.put("cts:build_reference_fingerprint", "ro.build.reference.fingerprint");
BUILD_KEYS.put("cts:build_system_fingerprint", "ro.build.fingerprint");
BUILD_KEYS.put("cts:build_vendor_fingerprint", "ro.vendor.build.fingerprint");
- BUILD_KEYS.put("cts:build_vendor_manufacturer", "ro.vendor.product.manufacturer");
- BUILD_KEYS.put("cts:build_vendor_model", "ro.vendor.product.model");
+ BUILD_KEYS.put("cts:build_vendor_manufacturer", "ro.product.vendor.manufacturer");
+ BUILD_KEYS.put("cts:build_vendor_model", "ro.product.vendor.model");
+
+ BUILD_LEGACY_PROPERTIES.put(
+ "ro.product.vendor.manufacturer", "ro.vendor.product.manufacturer");
+ BUILD_LEGACY_PROPERTIES.put("ro.product.vendor.model", "ro.vendor.product.model");
}
@Override
- public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
- BuildError, DeviceNotAvailableException {
+ public void setUp(ITestDevice device, IBuildInfo buildInfo)
+ throws TargetSetupError, BuildError, DeviceNotAvailableException {
for (Entry<String, String> entry : BUILD_KEYS.entrySet()) {
- buildInfo.addBuildAttribute(entry.getKey(),
- ArrayUtil.join(",", device.getProperty(entry.getValue())));
+ String propertyValue = device.getProperty(entry.getValue());
+ if ((propertyValue == null || propertyValue.length() == 0)
+ && BUILD_LEGACY_PROPERTIES.containsKey(entry.getValue())) {
+ propertyValue = device.getProperty(BUILD_LEGACY_PROPERTIES.get(entry.getValue()));
+ }
+ buildInfo.addBuildAttribute(entry.getKey(), ArrayUtil.join(",", propertyValue));
+ }
+
+ if (mDisableFramework) {
+ // Set the default device runtime state to stopped.
+ device.executeShellCommand("stop");
+ device.executeShellCommand("setprop sys.boot_completed 0");
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
+ throws DeviceNotAvailableException {
+ if (mDisableFramework) {
+ // Restore the framework at test run completion.
+ long startTime = System.currentTimeMillis();
+ device.waitForDeviceOnline(REBOOT_TIMEOUT);
+ device.executeShellCommand("start");
+ if (!device.waitForBootComplete(
+ REBOOT_TIMEOUT + startTime - System.currentTimeMillis())) {
+ throw new DeviceNotAvailableException("Framework irrecoverable after testing.");
+ }
}
}
}
diff --git a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsHalAdapterPreparer.java b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsHalAdapterPreparer.java
new file mode 100644
index 0000000..9dfa63c
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsHalAdapterPreparer.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.tradefed.targetprep;
+
+import com.android.compatibility.common.tradefed.build.VtsCompatibilityInvocationHelper;
+import com.android.annotations.VisibleForTesting;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.targetprep.multi.IMultiTargetPreparer;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.util.CmdUtil;
+import com.android.tradefed.util.FileUtil;
+
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.NoSuchElementException;
+import java.util.Vector;
+import java.util.function.Predicate;
+
+/**
+ * Starts and stops a HAL (Hardware Abstraction Layer) adapter.
+ */
+@OptionClass(alias = "vts-hal-adapter-preparer")
+public class VtsHalAdapterPreparer
+ implements ITargetPreparer, ITargetCleaner, IMultiTargetPreparer, IAbiReceiver {
+ static final int THREAD_COUNT_DEFAULT = 1;
+
+ static final String HAL_INTERFACE_SEP = "::";
+ static final String HAL_INSTANCE_SEP = "/";
+ // Relative path to vts native tests directory.
+ static final String VTS_NATIVE_TEST_DIR = "DATA/nativetest%s/";
+ // Path of native tests directory on target device.
+ static final String TARGET_NATIVE_TEST_DIR = "/data/nativetest%s/";
+ // Sysprop to stop HIDL adapaters. Currently, there's one global flag for all adapters.
+ static final String ADAPTER_SYSPROP = "test.hidl.adapters.deactivated";
+ // The wrapper script to start an adapter binary in the background.
+ static final String SCRIPT_PATH = "/data/local/tmp/vts_adapter.sh";
+ // Command to list the registered instance for the given hal@version.
+ static final String LIST_HAL_CMD =
+ "lshal -ti --neat | grep -E '^hwbinder' | awk '{print $2}' | grep %s";
+
+ @Option(name = "adapter-binary-name",
+ description = "Adapter binary file name (typically under /data/nativetest*/)")
+ private String mAdapterBinaryName = null;
+
+ @Option(name = "hal-package-name", description = "Target hal to adapter")
+ private String mPackageName = null;
+
+ @Option(name = "thread-count", description = "HAL adapter's thread count")
+ private int mThreadCount = THREAD_COUNT_DEFAULT;
+
+ // Application Binary Interface (ABI) info of the current test run.
+ private IAbi mAbi = null;
+
+ // CmdUtil help to verify the cmd results.
+ private CmdUtil mCmdUtil = null;
+ // Predicates to stop retrying cmd.
+ private Predicate<String> mCheckEmpty = (String str) -> {
+ return str.isEmpty();
+ };
+ private Predicate<String> mCheckNonEmpty = (String str) -> {
+ return !str.isEmpty();
+ };
+ private Vector<String> mCommands = new Vector<String>();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo)
+ throws TargetSetupError, BuildError, DeviceNotAvailableException, RuntimeException {
+ String bitness =
+ (mAbi != null) ? ((mAbi.getBitness() == "32") ? "" : mAbi.getBitness()) : "";
+ try {
+ pushAdapter(device, bitness);
+ } catch (IOException | NoSuchElementException e) {
+ CLog.e("Could not push adapter: " + e.toString());
+ throw new TargetSetupError("Could not push adapter.");
+ }
+
+ mCmdUtil = mCmdUtil != null ? mCmdUtil : new CmdUtil();
+ mCmdUtil.setSystemProperty(device, ADAPTER_SYSPROP, "false");
+
+ String out = device.executeShellCommand(String.format(LIST_HAL_CMD, mPackageName));
+ for (String line : out.split("\n")) {
+ if (!line.isEmpty()) {
+ if (!line.contains(HAL_INTERFACE_SEP)) {
+ throw new RuntimeException("HAL instance with wrong format.");
+ }
+ String interfaceInstance = line.split(HAL_INTERFACE_SEP, 2)[1];
+ if (!interfaceInstance.contains(HAL_INSTANCE_SEP)) {
+ throw new RuntimeException("HAL instance with wrong format.");
+ }
+ String interfaceName = interfaceInstance.split(HAL_INSTANCE_SEP, 2)[0];
+ String instanceName = interfaceInstance.split(HAL_INSTANCE_SEP, 2)[1];
+ // starts adapter
+ String command = String.format("%s /data/nativetest%s/%s %s %s %d", SCRIPT_PATH,
+ bitness, mAdapterBinaryName, interfaceName, instanceName, mThreadCount);
+ CLog.d("Trying to adapter for %s",
+ mPackageName + "::" + interfaceName + "/" + instanceName);
+ mCommands.add(command);
+ }
+ }
+ if (mCommands.isEmpty()) {
+ CLog.w("The specific HAL service is not running.");
+ return;
+ }
+ if (!mCmdUtil.retry(
+ device, mCommands, String.format(LIST_HAL_CMD, mPackageName), mCheckEmpty)) {
+ throw new TargetSetupError("HAL adapter setup failed.");
+ }
+
+ mCmdUtil.restartFramework(device);
+ if (!mCmdUtil.waitCmdResultWithDelay(
+ device, "service list | grep IPackageManager", mCheckNonEmpty)) {
+ throw new TargetSetupError("Failed to start package service");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setUp(IInvocationContext context)
+ throws TargetSetupError, BuildError, DeviceNotAvailableException {
+ setUp(context.getDevices().get(0), context.getBuildInfos().get(0));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
+ throws DeviceNotAvailableException {
+ if (!mCommands.isEmpty()) {
+ // stops adapter(s)
+ String command = String.format("setprop %s %s", ADAPTER_SYSPROP, "true");
+ mCmdUtil = mCmdUtil != null ? mCmdUtil : new CmdUtil();
+ Assert.assertTrue("HAL restore failed.",
+ mCmdUtil.retry(device, command, String.format(LIST_HAL_CMD, mPackageName),
+ mCheckNonEmpty, mCommands.size() + mCmdUtil.MAX_RETRY_COUNT));
+
+ // TODO: cleanup the pushed adapter files.
+ mCmdUtil.restartFramework(device);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void tearDown(IInvocationContext context, Throwable e)
+ throws DeviceNotAvailableException {
+ tearDown(context.getDevices().get(0), context.getBuildInfos().get(0), e);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setAbi(IAbi abi) {
+ mAbi = abi;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IAbi getAbi() {
+ return mAbi;
+ }
+
+ /**
+ * Push the required adapter binary to device.
+ *
+ * @param device device object.
+ * @param bitness ABI bitness.
+ * @throws DeviceNotAvailableException.
+ * @throws IOException.
+ * @throws NoSuchElementException.
+ */
+ private void pushAdapter(ITestDevice device, String bitness)
+ throws DeviceNotAvailableException, IOException, NoSuchElementException {
+ VtsCompatibilityInvocationHelper invocationHelper = createVtsHelper();
+ File adapterDir = new File(
+ invocationHelper.getTestsDir(), String.format(VTS_NATIVE_TEST_DIR, bitness));
+ File adapter = FileUtil.findFile(adapterDir, mAdapterBinaryName);
+ if (adapter != null) {
+ CLog.d("Pushing %s", mAdapterBinaryName);
+ device.pushFile(
+ adapter, String.format(TARGET_NATIVE_TEST_DIR, bitness) + mAdapterBinaryName);
+ } else {
+ throw new NoSuchElementException("Could not find adapter: " + mAdapterBinaryName);
+ }
+ }
+
+ /**
+ * Create and return a {@link VtsCompatibilityInvocationHelper} to use during the preparer.
+ */
+ @VisibleForTesting
+ VtsCompatibilityInvocationHelper createVtsHelper() {
+ return new VtsCompatibilityInvocationHelper();
+ }
+
+ @VisibleForTesting
+ void setCmdUtil(CmdUtil cmdUtil) {
+ mCmdUtil = cmdUtil;
+ }
+
+ @VisibleForTesting
+ void addCommand(String command) {
+ mCommands.add(command);
+ }
+}
diff --git a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsPythonVirtualenvPreparer.java b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsPythonVirtualenvPreparer.java
index fc425c9..e269435 100644
--- a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsPythonVirtualenvPreparer.java
+++ b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsPythonVirtualenvPreparer.java
@@ -16,33 +16,33 @@
package com.android.tradefed.targetprep;
+import com.android.annotations.VisibleForTesting;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.command.remote.DeviceDescriptor;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.multi.IMultiTargetPreparer;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.EnvUtil;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.IRunUtil;
import com.android.tradefed.util.RunUtil;
-import com.android.tradefed.util.StreamUtil;
+import com.android.tradefed.util.VtsFileUtil;
+import com.android.tradefed.util.VtsPythonRunnerHelper;
import com.android.tradefed.util.VtsVendorConfigFileUtil;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import java.io.File;
-import java.io.InputStream;
+import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
-import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collection;
import java.util.NoSuchElementException;
@@ -57,22 +57,15 @@
* That means changes here will be upstreamed gradually.
*/
@OptionClass(alias = "python-venv")
-public class VtsPythonVirtualenvPreparer implements ITargetPreparer, ITargetCleaner {
-
- private static final String PIP = "pip";
- private static final String PATH = "PATH";
- private static final String OS_NAME = "os.name";
- private static final String WINDOWS = "Windows";
+public class VtsPythonVirtualenvPreparer implements IMultiTargetPreparer {
private static final String LOCAL_PYPI_PATH_ENV_VAR_NAME = "VTS_PYPI_PATH";
private static final String LOCAL_PYPI_PATH_KEY = "pypi_packages_path";
- protected static final String PYTHONPATH = "PYTHONPATH";
- protected static final String VIRTUAL_ENV_PATH = "VIRTUALENVPATH";
private static final int BASE_TIMEOUT = 1000 * 60;
- private static final String[] DEFAULT_DEP_MODULES = {"enum", "future", "futures",
- "google-api-python-client", "httplib2", "oauth2client", "protobuf", "requests"};
+ public static final String VIRTUAL_ENV_V3 = "VIRTUAL_ENV_V3";
+ public static final String VIRTUAL_ENV = "VIRTUAL_ENV";
@Option(name = "venv-dir", description = "path of an existing virtualenv to use")
- private File mVenvDir = null;
+ protected File mVenvDir = null;
@Option(name = "requirements-file", description = "pip-formatted requirements file")
private File mRequirementsFile = null;
@@ -81,41 +74,67 @@
private Collection<String> mScriptFiles = new TreeSet<>();
@Option(name = "dep-module", description = "modules which need to be installed by pip")
- private Collection<String> mDepModules = new TreeSet<>(Arrays.asList(DEFAULT_DEP_MODULES));
+ protected Collection<String> mDepModules = new TreeSet<>();
@Option(name = "no-dep-module", description = "modules which should not be installed by pip")
private Collection<String> mNoDepModules = new TreeSet<>(Arrays.asList());
- @Option(name = "python-version", description = "The version of a Python interpreter to use.")
- private String mPythonVersion = "";
+ @Option(name = "python-version",
+ description = "The version of a Python interpreter to use."
+ + "Currently, only major version number is fully supported."
+ + "Example: \"2\", or \"3\".")
+ private String mPythonVersion = "2";
- IBuildInfo mBuildInfo = null;
- IRunUtil mRunUtil = new RunUtil();
- String mPip = PIP;
+ private IBuildInfo mBuildInfo = null;
+ private DeviceDescriptor mDescriptor = null;
+ private IRunUtil mRunUtil = new RunUtil();
+
String mLocalPypiPath = null;
+ String mPipPath = null;
+
+ // Since we allow virtual env path to be reused during a test plan/module, only the preparer
+ // which created the directory should be the one to delete it.
+ private boolean mIsDirCreator = false;
+
+ // If the same object is used in multiple threads (in sharding mode), the class
+ // needs to know when it is safe to call the teardown method.
+ private int mNumOfInstances = 0;
/**
* {@inheritDoc}
*/
@Override
- public void setUp(ITestDevice device, IBuildInfo buildInfo)
+ public synchronized void setUp(IInvocationContext context)
throws TargetSetupError, BuildError, DeviceNotAvailableException {
- mBuildInfo = buildInfo;
- startVirtualenv(buildInfo);
- setLocalPypiPath();
- installDeps(buildInfo);
+ ++mNumOfInstances;
+ mBuildInfo = context.getBuildInfos().get(0);
+ if (mNumOfInstances == 1) {
+ CLog.i("Preparing python dependencies...");
+ ITestDevice device = context.getDevices().get(0);
+ mDescriptor = device.getDeviceDescriptor();
+ createVirtualenv(mBuildInfo);
+ VtsPythonRunnerHelper.activateVirtualenv(getRunUtil(), mVenvDir.getAbsolutePath());
+ setLocalPypiPath();
+ installDeps();
+ }
+ addPathToBuild(mBuildInfo);
}
/**
* {@inheritDoc}
*/
@Override
- public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
+ public synchronized void tearDown(IInvocationContext context, Throwable e)
throws DeviceNotAvailableException {
- if (mVenvDir != null) {
+ --mNumOfInstances;
+ if (mNumOfInstances > 0) {
+ // Since this is a host side preparer, no need to repeat
+ return;
+ }
+ if (mVenvDir != null && mIsDirCreator) {
try {
recursiveDelete(mVenvDir.toPath());
- CLog.i("Deleted the virtual env's temp working dir, %s.", mVenvDir);
+ CLog.d("Deleted the virtual env's temp working dir, %s.", mVenvDir);
} catch (IOException exception) {
CLog.e("Failed to delete %s: %s", mVenvDir, exception);
}
@@ -126,11 +145,8 @@
/**
* This method sets mLocalPypiPath, the local PyPI package directory to
* install python packages from in the installDeps method.
- *
- * @throws IOException
- * @throws JSONException
*/
- protected void setLocalPypiPath() throws RuntimeException {
+ protected void setLocalPypiPath() {
VtsVendorConfigFileUtil configReader = new VtsVendorConfigFileUtil();
if (configReader.LoadVendorConfig(mBuildInfo)) {
// First try to load local PyPI directory path from vendor config file
@@ -138,7 +154,7 @@
String pypiPath = configReader.GetVendorConfigVariable(LOCAL_PYPI_PATH_KEY);
if (pypiPath.length() > 0 && dirExistsAndHaveReadAccess(pypiPath)) {
mLocalPypiPath = pypiPath;
- CLog.i(String.format("Loaded %s: %s", LOCAL_PYPI_PATH_KEY, mLocalPypiPath));
+ CLog.d(String.format("Loaded %s: %s", LOCAL_PYPI_PATH_KEY, mLocalPypiPath));
}
} catch (NoSuchElementException e) {
/* continue */
@@ -148,19 +164,19 @@
// If loading path from vendor config file is unsuccessful,
// check local pypi path defined by LOCAL_PYPI_PATH_ENV_VAR_NAME
if (mLocalPypiPath == null) {
- CLog.i("Checking whether local pypi packages directory exists");
+ CLog.d("Checking whether local pypi packages directory exists");
String pypiPath = System.getenv(LOCAL_PYPI_PATH_ENV_VAR_NAME);
if (pypiPath == null) {
- CLog.i("Local pypi packages directory not specified by env var %s",
+ CLog.d("Local pypi packages directory not specified by env var %s",
LOCAL_PYPI_PATH_ENV_VAR_NAME);
} else if (dirExistsAndHaveReadAccess(pypiPath)) {
mLocalPypiPath = pypiPath;
- CLog.i("Set local pypi packages directory to %s", pypiPath);
+ CLog.d("Set local pypi packages directory to %s", pypiPath);
}
}
if (mLocalPypiPath == null) {
- CLog.i("Failed to set local pypi packages path. Therefore internet connection to "
+ CLog.d("Failed to set local pypi packages path. Therefore internet connection to "
+ "https://pypi.python.org/simple/ must be available to run VTS tests.");
}
}
@@ -171,14 +187,14 @@
private boolean dirExistsAndHaveReadAccess(String path) {
File pathDir = new File(path);
if (!pathDir.exists() || !pathDir.isDirectory()) {
- CLog.i("Directory %s does not exist.", pathDir);
+ CLog.d("Directory %s does not exist.", pathDir);
return false;
}
- if (!isOnWindows()) {
- CommandResult c = mRunUtil.runTimedCmd(BASE_TIMEOUT * 5, "ls", path);
+ if (!EnvUtil.isOnWindows()) {
+ CommandResult c = getRunUtil().runTimedCmd(BASE_TIMEOUT * 5, "ls", path);
if (c.getStatus() != CommandStatus.SUCCESS) {
- CLog.i(String.format("Failed to read dir: %s. Result %s. stdout: %s, stderr: %s",
+ CLog.d(String.format("Failed to read dir: %s. Result %s. stdout: %s, stderr: %s",
path, c.getStatus(), c.getStdout(), c.getStderr()));
return false;
}
@@ -187,11 +203,11 @@
try {
String[] pathDirList = pathDir.list();
if (pathDirList == null) {
- CLog.i("Failed to read dir: %s. Please check access permission.", pathDir);
+ CLog.d("Failed to read dir: %s. Please check access permission.", pathDir);
return false;
}
} catch (SecurityException e) {
- CLog.i(String.format(
+ CLog.d(String.format(
"Failed to read dir %s with SecurityException %s", pathDir, e));
return false;
}
@@ -199,25 +215,25 @@
}
}
- protected void installDeps(IBuildInfo buildInfo) throws TargetSetupError {
+ protected void installDeps() throws TargetSetupError {
boolean hasDependencies = false;
if (!mScriptFiles.isEmpty()) {
for (String scriptFile : mScriptFiles) {
- CLog.i("Attempting to execute a script, %s", scriptFile);
- CommandResult c = mRunUtil.runTimedCmd(BASE_TIMEOUT * 5, scriptFile);
+ CLog.d("Attempting to execute a script, %s", scriptFile);
+ CommandResult c = getRunUtil().runTimedCmd(BASE_TIMEOUT * 5, scriptFile);
if (c.getStatus() != CommandStatus.SUCCESS) {
CLog.e("Executing script %s failed", scriptFile);
- throw new TargetSetupError("Failed to source a script");
+ throw new TargetSetupError("Failed to source a script", mDescriptor);
}
}
}
if (mRequirementsFile != null) {
- CommandResult c = mRunUtil.runTimedCmd(BASE_TIMEOUT * 5, mPip,
- "install", "-r", mRequirementsFile.getAbsolutePath());
- if (c.getStatus() != CommandStatus.SUCCESS) {
- CLog.e("Installing dependencies from %s failed",
- mRequirementsFile.getAbsolutePath());
- throw new TargetSetupError("Failed to install dependencies with pip");
+ CommandResult c = getRunUtil().runTimedCmd(BASE_TIMEOUT * 5, getPipPath(), "install",
+ "-r", mRequirementsFile.getAbsolutePath());
+ if (!CommandStatus.SUCCESS.equals(c.getStatus())) {
+ CLog.e("Installing dependencies from %s failed with error: %s",
+ mRequirementsFile.getAbsolutePath(), c.getStderr());
+ throw new TargetSetupError("Failed to install dependencies with pip", mDescriptor);
}
hasDependencies = true;
}
@@ -228,32 +244,35 @@
}
CommandResult result = null;
if (mLocalPypiPath != null) {
- CLog.i("Attempting installation of %s from local directory", dep);
- result = mRunUtil.runTimedCmd(BASE_TIMEOUT * 5, mPip, "install", dep,
- "--no-index", "--find-links=" + mLocalPypiPath);
- CLog.i(String.format("Result %s. stdout: %s, stderr: %s", result.getStatus(),
+ CLog.d("Attempting installation of %s from local directory", dep);
+ result = getRunUtil().runTimedCmd(BASE_TIMEOUT * 5, getPipPath(), "install",
+ dep, "--no-index", "--find-links=" + mLocalPypiPath);
+ CLog.d(String.format("Result %s. stdout: %s, stderr: %s", result.getStatus(),
result.getStdout(), result.getStderr()));
if (result.getStatus() != CommandStatus.SUCCESS) {
CLog.e(String.format("Installing %s from %s failed", dep, mLocalPypiPath));
}
}
if (mLocalPypiPath == null || result.getStatus() != CommandStatus.SUCCESS) {
- CLog.i("Attempting installation of %s from PyPI", dep);
- result = mRunUtil.runTimedCmd(BASE_TIMEOUT * 5, mPip, "install", dep);
- CLog.i(String.format("Result %s. stdout: %s, stderr: %s", result.getStatus(),
- result.getStdout(), result.getStderr()));
+ CLog.d("Attempting installation of %s from PyPI", dep);
+ result = getRunUtil().runTimedCmd(
+ BASE_TIMEOUT * 5, getPipPath(), "install", dep);
+ CLog.d("Result %s. stdout: %s, stderr: %s", result.getStatus(),
+ result.getStdout(), result.getStderr());
if (result.getStatus() != CommandStatus.SUCCESS) {
CLog.e("Installing %s from PyPI failed.", dep);
- CLog.i("Attempting to upgrade %s", dep);
- result = mRunUtil.runTimedCmd(
- BASE_TIMEOUT * 5, mPip, "install", "--upgrade", dep);
+ CLog.d("Attempting to upgrade %s", dep);
+ result = getRunUtil().runTimedCmd(
+ BASE_TIMEOUT * 5, getPipPath(), "install", "--upgrade", dep);
if (result.getStatus() != CommandStatus.SUCCESS) {
- throw new TargetSetupError(String.format(
- "Failed to install dependencies with pip. "
- + "Result %s. stdout: %s, stderr: %s",
- result.getStatus(), result.getStdout(), result.getStderr()));
+ throw new TargetSetupError(
+ String.format("Failed to install dependencies with pip. "
+ + "Result %s. stdout: %s, stderr: %s",
+ result.getStatus(), result.getStdout(),
+ result.getStderr()),
+ mDescriptor);
} else {
- CLog.i(String.format("Result %s. stdout: %s, stderr: %s",
+ CLog.d(String.format("Result %s. stdout: %s, stderr: %s",
result.getStatus(), result.getStdout(), result.getStderr()));
}
}
@@ -262,69 +281,109 @@
}
}
if (!hasDependencies) {
- CLog.i("No dependencies to install");
- } else {
- // make the install directory of new packages available to other classes that
- // receive the build
- buildInfo.setFile(PYTHONPATH, new File(mVenvDir,
- "local/lib/python2.7/site-packages"),
- buildInfo.getBuildId());
- }
- }
-
- protected void startVirtualenv(IBuildInfo buildInfo) throws TargetSetupError {
- if (mVenvDir != null) {
- CLog.i("Using existing virtualenv based at %s", mVenvDir.getAbsolutePath());
- activate();
- return;
- }
- try {
- mVenvDir = buildInfo.getFile(VIRTUAL_ENV_PATH);
- if (mVenvDir == null) {
- mVenvDir = FileUtil.createTempDir(getMD5(buildInfo.getTestTag()) + "-virtualenv");
- }
- String virtualEnvPath = mVenvDir.getAbsolutePath();
- CommandResult c;
- if (mPythonVersion.length() == 0) {
- c = mRunUtil.runTimedCmd(BASE_TIMEOUT, "virtualenv", virtualEnvPath);
- } else {
- String[] cmd;
- cmd = new String[4];
- cmd[0] = "virtualenv";
- cmd[1] = "-p";
- cmd[2] = "python" + mPythonVersion;
- cmd[3] = virtualEnvPath;
- c = mRunUtil.runTimedCmd(BASE_TIMEOUT, cmd);
- }
- if (c.getStatus() != CommandStatus.SUCCESS) {
- CLog.e(String.format("Failed to create virtualenv with : %s.", virtualEnvPath));
- throw new TargetSetupError("Failed to create virtualenv");
- }
- CLog.i(VIRTUAL_ENV_PATH + " = " + virtualEnvPath + "\n");
- buildInfo.setFile(VIRTUAL_ENV_PATH, new File(virtualEnvPath),
- buildInfo.getBuildId());
- activate();
- } catch (IOException | RuntimeException e) {
- CLog.e("Failed to create temp directory for virtualenv");
- throw new TargetSetupError("Error creating virtualenv", e);
+ CLog.d("No dependencies to install");
}
}
/**
- * This method returns a MD5 hash string for the given string.
+ * This method returns absolute pip path in virtualenv.
+ *
+ * This method is needed because although PATH is set in IRunUtil, IRunUtil will still
+ * use pip from system path.
+ *
+ * @return absolute pip path in virtualenv. null if virtualenv not available.
*/
- private String getMD5(String str) throws RuntimeException {
- try {
- java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
- byte[] array = md.digest(str.getBytes());
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < array.length; ++i) {
- sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3));
- }
- return sb.toString();
- } catch (java.security.NoSuchAlgorithmException e) {
- throw new RuntimeException("Error generating MD5 hash.", e);
+ public String getPipPath() {
+ if (mPipPath != null) {
+ return mPipPath;
}
+
+ String virtualenvPath = mVenvDir.getAbsolutePath();
+ if (virtualenvPath == null) {
+ return null;
+ }
+ mPipPath = new File(VtsPythonRunnerHelper.getPythonBinDir(virtualenvPath), "pip")
+ .getAbsolutePath();
+ return mPipPath;
+ }
+
+ /**
+ * Get the major python version from option.
+ *
+ * Currently, only 2 and 3 are supported.
+ *
+ * @return major version number
+ * @throws TargetSetupError
+ */
+ protected int getConfiguredPythonVersionMajor() throws TargetSetupError {
+ if (mPythonVersion.startsWith("3.") || mPythonVersion.equals("3")) {
+ return 3;
+ } else if (mPythonVersion.startsWith("2.") || mPythonVersion.equals("2")) {
+ return 2;
+ } else {
+ throw new TargetSetupError("Unsupported python version " + mPythonVersion);
+ }
+ }
+
+ /**
+ * Add PYTHONPATH and VIRTUAL_ENV_PATH to BuildInfo.
+ * @param buildInfo
+ * @throws TargetSetupError
+ */
+ protected void addPathToBuild(IBuildInfo buildInfo) throws TargetSetupError {
+ String target = null;
+ switch (getConfiguredPythonVersionMajor()) {
+ case 2:
+ target = VtsPythonVirtualenvPreparer.VIRTUAL_ENV;
+ break;
+ case 3:
+ target = VtsPythonVirtualenvPreparer.VIRTUAL_ENV_V3;
+ break;
+ }
+
+ if (buildInfo.getFile(target) == null) {
+ buildInfo.setFile(target, new File(mVenvDir.getAbsolutePath()), buildInfo.getBuildId());
+ }
+ }
+
+ /**
+ * Create virtualenv directory by executing virtualenv command.
+ * @param buildInfo
+ * @throws TargetSetupError
+ */
+ protected void createVirtualenv(IBuildInfo buildInfo) throws TargetSetupError {
+ if (mVenvDir == null) {
+ switch (getConfiguredPythonVersionMajor()) {
+ case 2:
+ mVenvDir = buildInfo.getFile(VtsPythonVirtualenvPreparer.VIRTUAL_ENV);
+ break;
+ case 3:
+ mVenvDir = buildInfo.getFile(VtsPythonVirtualenvPreparer.VIRTUAL_ENV_V3);
+ break;
+ }
+ }
+
+ if (mVenvDir == null) {
+ CLog.d("Creating virtualenv for version " + mPythonVersion);
+ try {
+ mVenvDir = FileUtil.createTempDir("vts-virtualenv-" + mPythonVersion + "-"
+ + VtsFileUtil.normalizeFileName(buildInfo.getTestTag()) + "_");
+ mIsDirCreator = true;
+ String virtualEnvPath = mVenvDir.getAbsolutePath();
+ String[] cmd = new String[] {
+ "virtualenv", "-p", "python" + mPythonVersion, virtualEnvPath};
+ CommandResult c = getRunUtil().runTimedCmd(BASE_TIMEOUT, cmd);
+ if (c.getStatus() != CommandStatus.SUCCESS) {
+ CLog.e(String.format("Failed to create virtualenv with : %s.", virtualEnvPath));
+ throw new TargetSetupError("Failed to create virtualenv", mDescriptor);
+ }
+ } catch (IOException | RuntimeException e) {
+ CLog.e("Failed to create temp directory for virtualenv");
+ throw new TargetSetupError("Error creating virtualenv", e, mDescriptor);
+ }
+ }
+
+ CLog.d("Python virtualenv path is: " + mVenvDir);
}
protected void addDepModule(String module) {
@@ -336,6 +395,17 @@
}
/**
+ * Get an instance of {@link IRunUtil}.
+ */
+ @VisibleForTesting
+ IRunUtil getRunUtil() {
+ if (mRunUtil == null) {
+ mRunUtil = new RunUtil();
+ }
+ return mRunUtil;
+ }
+
+ /**
* This method recursively deletes a file tree without following symbolic links.
*
* @param rootPath the path to delete.
@@ -359,21 +429,4 @@
}
});
}
-
- /**
- * This method returns whether the OS is Windows.
- */
- private static boolean isOnWindows() {
- return System.getProperty(OS_NAME).contains(WINDOWS);
- }
-
- private void activate() {
- File binDir = new File(mVenvDir, isOnWindows() ? "Scripts" : "bin");
- mRunUtil.setWorkingDir(binDir);
- String path = System.getenv(PATH);
- mRunUtil.setEnvVariable(PATH, binDir + File.pathSeparator + path);
- File pipFile = new File(binDir, PIP);
- pipFile.setExecutable(true);
- mPip = pipFile.getAbsolutePath();
- }
}
diff --git a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsTestPlanResultReporter.java b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsTestPlanResultReporter.java
index ece5c13..d7fabc2 100644
--- a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsTestPlanResultReporter.java
+++ b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsTestPlanResultReporter.java
@@ -31,8 +31,11 @@
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.multi.IMultiTargetPreparer;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
import com.android.tradefed.util.FileUtil;
@@ -49,10 +52,12 @@
* an OAuth2 credential kept in a json file.
*/
@OptionClass(alias = "vts-plan-result")
-public class VtsTestPlanResultReporter implements ITargetPreparer, ITargetCleaner {
+public class VtsTestPlanResultReporter
+ implements ITargetPreparer, ITargetCleaner, IMultiTargetPreparer {
private static final String PLUS_ME = "https://www.googleapis.com/auth/plus.me";
private static final String TEST_PLAN_EXECUTION_RESULT = "vts-test-plan-execution-result";
private static final String TEST_PLAN_REPORT_FILE = "TEST_PLAN_REPORT_FILE";
+ private static final String TEST_PLAN_REPORT_FILE_NAME = "status.json";
private static VtsVendorConfigFileUtil configReader = null;
private static VtsDashboardUtil dashboardUtil = null;
private static final int BASE_TIMEOUT_MSECS = 1000 * 60;
@@ -77,7 +82,7 @@
try {
mStatusDir = FileUtil.createTempDir(TEST_PLAN_EXECUTION_RESULT);
if (mStatusDir != null) {
- File statusFile = new File(mStatusDir, "status.json");
+ File statusFile = new File(mStatusDir, TEST_PLAN_REPORT_FILE_NAME);
buildInfo.setFile(TEST_PLAN_REPORT_FILE, statusFile, buildInfo.getBuildId());
}
} catch (IOException ex) {
@@ -99,6 +104,15 @@
* {@inheritDoc}
*/
@Override
+ public void setUp(IInvocationContext context)
+ throws TargetSetupError, DeviceNotAvailableException {
+ setUp(context.getDevices().get(0), context.getBuildInfos().get(0));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) {
File reportFile = buildInfo.getFile(TEST_PLAN_REPORT_FILE);
String repotFilePath = reportFile.getAbsolutePath();
@@ -131,4 +145,12 @@
}
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void tearDown(IInvocationContext context, Throwable e)
+ throws DeviceNotAvailableException {
+ tearDown(context.getDevices().get(0), context.getBuildInfos().get(0), e);
+ }
}
diff --git a/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsTraceCollectPreparer.java b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsTraceCollectPreparer.java
new file mode 100644
index 0000000..eceae7f
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/tradefed/targetprep/VtsTraceCollectPreparer.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.tradefed.targetprep;
+
+import com.android.annotations.VisibleForTesting;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.NoSuchElementException;
+
+/**
+ * Preparer class for collect HAL traces during the test run.
+ *
+ * Currently used for collecting HAL traces for CTS tests. In test setup, pushes
+ * the profiler libs to device, sets up the permissions, and calls
+ * vts_profiling_configure to enable profiling for HAL services. In test
+ * tear down, pulls the traces to the host, resets permissions and cleans up the
+ * trace files and profiler libs on the device.
+ */
+@OptionClass(alias = "vts-trace-collect-preparer")
+public class VtsTraceCollectPreparer implements ITargetPreparer, ITargetCleaner {
+ static final String SELINUX_DISABLED = "Disabled"; // selinux disabled
+ static final String SELINUX_PERMISSIVE = "Permissive"; // selinux permissive mode
+
+ // Relative path to vts 32 bit lib directory.
+ static final String VTS_LIB_DIR_32 = "DATA/lib/";
+ // Relative path to vts 64 bit lib directory.
+ static final String VTS_LIB_DIR_64 = "DATA/lib64/";
+ // Relative path to vts binary directory.
+ static final String VTS_BINARY_DIR = "DATA/bin/";
+ // Path of 32 bit test libs on target device.
+ static final String VTS_TMP_LIB_DIR_32 = "/data/local/tmp/32/";
+ // Path of 64 bit test libs on target device.
+ static final String VTS_TMP_LIB_DIR_64 = "/data/local/tmp/64/";
+ // Path of vts test directory on target device.
+ static final String VTS_TMP_DIR = "/data/local/tmp/";
+ // Default path to store trace files locally.
+ static final String LOCAL_TRACE_DIR = "vts-profiling";
+
+ static final String VTS_PROFILER_SUFFIX = "vts.profiler.so";
+ static final String VTS_LIB_PREFIX = "libvts";
+ static final String PROFILING_CONFIGURE_BINARY = "vts_profiling_configure";
+ static final String TRACE_PATH = "trace_path";
+
+ private String mEnforcingState = null; // start state for selinux enforcement
+
+ @Option(name = "local-trace-dir", description = "Local directory to store trace.")
+ private String mLocalTraceDir = LOCAL_TRACE_DIR;
+
+ /** {@inheritDoc} */
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo)
+ throws DeviceNotAvailableException, TargetSetupError {
+ CompatibilityBuildHelper buildHelper = createBuildHelper(buildInfo);
+ try {
+ // adb root.
+ device.enableAdbRoot();
+ // Push 32 bit profiler libs.
+ pushProfilerLib(device, new File(buildHelper.getTestsDir(), VTS_LIB_DIR_32),
+ VTS_TMP_LIB_DIR_32);
+ // Push 64 bit profiler libs.
+ pushProfilerLib(device, new File(buildHelper.getTestsDir(), VTS_LIB_DIR_64),
+ VTS_TMP_LIB_DIR_64);
+ // Push vts_profiling_configure
+ device.pushFile(new File(buildHelper.getTestsDir(),
+ VTS_BINARY_DIR + PROFILING_CONFIGURE_BINARY),
+ VTS_TMP_DIR + PROFILING_CONFIGURE_BINARY);
+ } catch (IOException | NoSuchElementException e) {
+ // Cleanup profiler libs.
+ removeProfilerLib(device);
+ throw new TargetSetupError("Could not push profiler.");
+ }
+ // Create directory to store the trace files.
+ try {
+ File resultDir = buildHelper.getResultDir();
+ File traceDir = new File(resultDir, mLocalTraceDir);
+ buildInfo.addBuildAttribute(TRACE_PATH, traceDir.getAbsolutePath());
+ } catch (FileNotFoundException e) {
+ CLog.e("Failed to get traceDir: " + e.getMessage());
+ // Cleanup profiler libs.
+ removeProfilerLib(device);
+ throw new TargetSetupError("Failed to get traceDir.");
+ }
+ // Set selinux permissive mode.
+ mEnforcingState = device.executeShellCommand("getenforce");
+ if (mEnforcingState == null
+ || (!mEnforcingState.equals(SELINUX_DISABLED)
+ && !mEnforcingState.equals(SELINUX_PERMISSIVE))) {
+ device.executeShellCommand("setenforce " + SELINUX_PERMISSIVE);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
+ throws DeviceNotAvailableException {
+ // Reset selinux permission mode.
+ if (mEnforcingState != null && !mEnforcingState.equals(SELINUX_DISABLED)) {
+ device.executeShellCommand("setenforce " + mEnforcingState);
+ }
+ // Cleanup profiler libs.
+ removeProfilerLib(device);
+ }
+
+ /**
+ * Create and return a {@link CompatibilityBuildHelper} to use during the preparer.
+ */
+ @VisibleForTesting
+ CompatibilityBuildHelper createBuildHelper(IBuildInfo buildInfo) {
+ return new CompatibilityBuildHelper(buildInfo);
+ }
+
+ /**
+ * Push all the profiler libraries (with pattern *.vts-profiler.so) and VTS
+ * profiling related libraries (with pattern libvts*.so) to device.
+ *
+ * @param device device object
+ * @param profilerLibDir directory to lookup for profiler libraries.
+ * @param destDirName target directory on device to push to.
+ * @throws DeviceNotAvailableException
+ */
+ private void pushProfilerLib(ITestDevice device, File profilerLibDir, String destDirName)
+ throws DeviceNotAvailableException {
+ File[] files = profilerLibDir.listFiles();
+ if (files == null) {
+ CLog.d("No files found in %s", profilerLibDir.getAbsolutePath());
+ return;
+ }
+ for (File f : files) {
+ String fileName = f.getName();
+ if (f.isFile()
+ && (fileName.endsWith(VTS_PROFILER_SUFFIX)
+ || fileName.startsWith(VTS_LIB_PREFIX))) {
+ CLog.d("Pushing %s", fileName);
+ device.pushFile(f, destDirName + fileName);
+ }
+ }
+ }
+
+ /**
+ * Remove all profiler and VTS profiling libraries from device.
+ *
+ * @param device device object
+ * @throws DeviceNotAvailableException
+ */
+ private void removeProfilerLib(ITestDevice device) throws DeviceNotAvailableException {
+ device.executeShellCommand(String.format("rm -rf %s/*vts.profiler.so", VTS_TMP_LIB_DIR_32));
+ device.executeShellCommand(String.format("rm -rf %s/*vts.profiler.so", VTS_TMP_LIB_DIR_64));
+ device.executeShellCommand(String.format("rm -rf %s/libvts_*.so", VTS_TMP_LIB_DIR_32));
+ device.executeShellCommand(String.format("rm -rf %s/libvts_*.so", VTS_TMP_LIB_DIR_64));
+ device.executeShellCommand(String.format("rm %s/vts_profiling_configure", VTS_TMP_DIR));
+ }
+}
diff --git a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java
index 1299e28..d827087 100644
--- a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java
+++ b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java
@@ -23,28 +23,30 @@
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.targetprep.VtsCoveragePreparer;
-import com.android.tradefed.util.ArrayUtil;
+import com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.JsonUtil;
-import com.android.tradefed.util.ProcessHelper;
+import com.android.tradefed.util.OutputUtil;
import com.android.tradefed.util.RunInterruptedException;
-import com.android.tradefed.util.IRunUtil;
-import com.android.tradefed.util.RunUtil;
import com.android.tradefed.util.VtsDashboardUtil;
+import com.android.tradefed.util.VtsPythonRunnerHelper;
import com.android.tradefed.util.VtsVendorConfigFileUtil;
import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IInvocationContextReceiver;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;
import java.io.BufferedWriter;
+import java.util.Collection;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
@@ -52,9 +54,10 @@
import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.Map;
+import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Set;
-import java.util.Collection;
+import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
@@ -64,9 +67,11 @@
*/
@OptionClass(alias = "vtsmultidevicetest")
-public class VtsMultiDeviceTest implements IDeviceTest, IRemoteTest, ITestFilterReceiver,
-IRuntimeHintProvider, ITestCollector, IBuildReceiver, IAbiReceiver {
-
+public class VtsMultiDeviceTest
+ implements IDeviceTest, IRemoteTest, ITestFilterReceiver, IRuntimeHintProvider,
+ ITestCollector, IBuildReceiver, IAbiReceiver, IInvocationContextReceiver {
+ static final String ACTS_TEST_MODULE = "ACTS_TEST_MODULE";
+ static final String ADAPTER_ACTS_PATH = "vts/runners/adapters/acts/acts_adapter";
static final String ANDROIDDEVICE = "AndroidDevice";
static final String BUILD = "build";
static final String BUILD_ID = "build_id";
@@ -76,23 +81,20 @@
static final String LOG_PATH = "log_path";
static final String LOG_SEVERITY = "log_severity";
static final String NAME = "name";
- static final String OS_NAME = "os.name";
- static final String WINDOWS = "Windows";
- static final String PYTHONPATH = "PYTHONPATH";
static final String SERIAL = "serial";
static final String TESTMODULE = "TestModule";
static final String TEST_BED = "test_bed";
static final String TEST_PLAN_REPORT_FILE = "TEST_PLAN_REPORT_FILE";
static final String TEST_SUITE = "test_suite";
- static final String TEST_MAX_TIMEOUT = "test_max_timeout";
- static final String VIRTUAL_ENV_PATH = "VIRTUALENVPATH";
static final String ABI_NAME = "abi_name";
static final String ABI_BITNESS = "abi_bitness";
static final String SKIP_ON_32BIT_ABI = "skip_on_32bit_abi";
static final String SKIP_ON_64BIT_ABI = "skip_on_64bit_abi";
static final String SKIP_IF_THERMAL_THROTTLING = "skip_if_thermal_throttling";
+ static final String DISABLE_CPU_FREQUENCY_SCALING = "disable_cpu_frequency_scaling";
+ static final String DISABLE_FRAMEWORK = "DISABLE_FRAMEWORK";
+ static final String STOP_NATIVE_SERVERS = "STOP_NATIVE_SERVERS";
static final String RUN_32BIT_ON_64BIT_ABI = "run_32bit_on_64bit_abi";
- static final String VTS = "vts";
static final String CONFIG_FILE_EXTENSION = ".config";
static final String INCLUDE_FILTER = "include_filter";
static final String EXCLUDE_FILTER = "exclude_filter";
@@ -103,28 +105,39 @@
static final String BINARY_TEST_ARGS = "binary_test_args";
static final String BINARY_TEST_LD_LIBRARY_PATH = "binary_test_ld_library_path";
static final String BINARY_TEST_PROFILING_LIBRARY_PATH = "binary_test_profiling_library_path";
- static final String BINARY_TEST_DISABLE_FRAMEWORK = "binary_test_disable_framework";
+ @Deprecated static final String BINARY_TEST_DISABLE_FRAMEWORK = "binary_test_disable_framework";
+ @Deprecated
static final String BINARY_TEST_STOP_NATIVE_SERVERS = "binary_test_stop_native_servers";
static final String BINARY_TEST_TYPE_GTEST = "gtest";
static final String BINARY_TEST_TYPE_LLVMFUZZER = "llvmfuzzer";
static final String BINARY_TEST_TYPE_HAL_HIDL_GTEST = "hal_hidl_gtest";
static final String BINARY_TEST_TYPE_HAL_HIDL_REPLAY_TEST = "hal_hidl_replay_test";
static final String BINARY_TEST_TYPE_HOST_BINARY_TEST = "host_binary_test";
- static final String BUG_REPORT_ON_FAILURE = "bug_report_on_failure";
+ static final String BUG_REPORT_ON_FAILURE = "BUG_REPORT_ON_FAILURE";
+ static final String COLLECT_TESTS_ONLY = "collect_tests_only";
+ static final String CONFIG_STR = "CONFIG_STR";
+ static final String CONFIG_INT = "CONFIG_INT";
+ static final String CONFIG_BOOL = "CONFIG_BOOL";
+ static final String LOGCAT_ON_FAILURE = "LOGCAT_ON_FAILURE";
static final String ENABLE_COVERAGE = "enable_coverage";
+ static final String EXCLUDE_COVERAGE_PATH = "exclude_coverage_path";
static final String ENABLE_PROFILING = "enable_profiling";
static final String ENABLE_SANCOV = "enable_sancov";
static final String GTEST_BATCH_MODE = "gtest_batch_mode";
static final String SAVE_TRACE_FIEL_REMOTE = "save_trace_file_remote";
static final String OUTPUT_COVERAGE_REPORT = "output_coverage_report";
+ static final String COVERAGE_REPORT_PATH = "coverage_report_path";
static final String GLOBAL_COVERAGE = "global_coverage";
static final String LTP_NUMBER_OF_THREADS = "ltp_number_of_threads";
+ static final String MOBLY_TEST_MODULE = "MOBLY_TEST_MODULE";
static final String NATIVE_SERVER_PROCESS_NAME = "native_server_process_name";
static final String PASSTHROUGH_MODE = "passthrough_mode";
static final String PRECONDITION_HWBINDER_SERVICE = "precondition_hwbinder_service";
static final String PRECONDITION_FEATURE = "precondition_feature";
static final String PRECONDITION_FILE_PATH_PREFIX = "precondition_file_path_prefix";
+ static final String PRECONDITION_FIRST_API_LEVEL = "precondition_first_api_level";
static final String PRECONDITION_LSHAL = "precondition_lshal";
+ static final String PRECONDITION_SYSPROP = "precondition_sysprop";
static final String PRECONDITION_VINTF = "precondition_vintf";
static final String ENABLE_SYSTRACE = "enable_systrace";
static final String HAL_HIDL_REPLAY_TEST_TRACE_PATHS = "hal_hidl_replay_test_trace_paths";
@@ -136,22 +149,24 @@
static final String TEMPLATE_BINARY_TEST_PATH = "vts/testcases/template/binary_test/binary_test";
static final String TEMPLATE_GTEST_BINARY_TEST_PATH = "vts/testcases/template/gtest_binary_test/gtest_binary_test";
static final String TEMPLATE_LLVMFUZZER_TEST_PATH = "vts/testcases/template/llvmfuzzer_test/llvmfuzzer_test";
+ static final String TEMPLATE_MOBLY_TEST_PATH = "vts/testcases/template/mobly/mobly_test";
static final String TEMPLATE_HAL_HIDL_GTEST_PATH = "vts/testcases/template/hal_hidl_gtest/hal_hidl_gtest";
static final String TEMPLATE_HAL_HIDL_REPLAY_TEST_PATH = "vts/testcases/template/hal_hidl_replay_test/hal_hidl_replay_test";
static final String TEMPLATE_HOST_BINARY_TEST_PATH = "vts/testcases/template/host_binary_test/host_binary_test";
static final long TEST_ABORT_TIMEOUT_MSECS = 1000 * 15;
static final String TEST_RUN_SUMMARY_FILE_NAME = "test_run_summary.json";
static final float DEFAULT_TARGET_VERSION = -1;
- static final String DEFAULT_TESTCASE_CONFIG_PATH = "vts/tools/vts-tradefed/res/default/DefaultTestCase.config";
+ static final String DEFAULT_TESTCASE_CONFIG_PATH =
+ "vts/tools/vts-tradefed/res/default/DefaultTestCase.runner_conf";
private ITestDevice mDevice = null;
private IAbi mAbi = null;
@Option(name = "test-timeout",
description = "The amount of time (in milliseconds) for a test invocation. "
- + "If the test cannot finish before timeout, it should interrupt itself and "
- + "clean up in " + TEST_ABORT_TIMEOUT_MSECS + "ms. Hence the actual timeout "
- + "is the specified value + " + TEST_ABORT_TIMEOUT_MSECS + "ms.",
+ + "If the test cannot finish before timeout, it is interrupted and cleans up "
+ + "in " + TEST_ABORT_TIMEOUT_MSECS + "ms. Hence the actual timeout is the "
+ + "specified value + " + TEST_ABORT_TIMEOUT_MSECS + "ms.",
isTimeVal = true)
private long mTestTimeout = 1000 * 60 * 60 * 3;
@@ -167,9 +182,6 @@
description = "The type of test case path ('module' by default or 'file').")
private String mTestCasePathType = null;
- @Option(name = "python-version", description = "The version of a Python interpreter to use.")
- private String mPythonVersion = "";
-
@Option(name = "test-config-path",
description = "The path for test case config file.")
private String mTestConfigPath = null;
@@ -192,10 +204,19 @@
+ " <source>: absolute path of file prefix on device")
private Collection<String> mPreconditionFilePathPrefix = new ArrayList<>();
+ @Option(name = "precondition-first-api-level",
+ description = "The lowest first API level required to run the test.")
+ private int mPreconditionFirstApiLevel = 0;
+
@Option(name = "precondition-lshal",
description = "The name of a `lshal`-listable feature needed to run the test.")
private String mPreconditionLshal = null;
+ @Option(name = "precondition-sysprop",
+ description = "The name=value for a system property configuration that needs "
+ + "to be met to run the test.")
+ private String mPreconditionSysProp = null;
+
@Option(name = "precondition-vintf",
description = "The full name of a HAL specified in vendor/manifest.xml and "
+ "needed to run the test (e.g., android.hardware.graphics.mapper@2.0). "
@@ -277,6 +298,10 @@
description = "Whether to skip tests if target device suffers from thermal throttling.")
private boolean mSkipIfThermalThrottling = false;
+ @Option(name = "disable-cpu-frequency-scaling",
+ description = "Whether to disable cpu frequency scaling for test.")
+ private boolean mDisableCpuFrequencyScaling = true;
+
@Option(name = "run-32bit-on-64bit-abi",
description = "Whether to run 32bit tests on 64bit ABI.")
private boolean mRun32bBitOn64BitAbi = false;
@@ -349,19 +374,35 @@
+ "specified, default directories will be used for files with different tags.")
private Collection<String> mBinaryTestProfilingLibraryPath = new ArrayList<>();
- @Option(name = "binary-test-disable-framework", description = "Adb stop/start before/after test.")
+ @Deprecated
+ @Option(name = "binary-test-disable-framework",
+ description = "Adb stop/start before/after test.")
private boolean mBinaryTestDisableFramework = false;
+ @Deprecated
@Option(name = "binary-test-stop-native-servers",
description = "Set to stop all properly configured native servers during the testing.")
private boolean mBinaryTestStopNativeServers = false;
+ @Option(name = "disable-framework", description = "Adb stop/start before/after test.")
+ private boolean mDisableFramework = false;
+
+ @Option(name = "stop-native-servers",
+ description = "Set to stop all properly configured native servers during the testing.")
+ private boolean mStopNativeServers = false;
+
@Option(name = "bug-report-on-failure",
description = "To catch bugreport zip file at the end of failed test cases. "
- + "If set to true, a report will be caught through adh shell command at the end of each failed "
- + "test cases.")
+ + "If set to true, a report will be caught through adh shell command at the "
+ + "end of each failed test cases.")
private boolean mBugReportOnFailure = false;
+ @Option(name = "logcat-on-failure",
+ description = "To catch logcat from each buffers at the end of failed test cases. "
+ + "If set to true, a report will be caught through adh shell command at the "
+ + "end of each failed test cases.")
+ private boolean mLogcatOnFailure = true;
+
@Option(name = "native-server-process-name",
description = "Name of a native server process. The runner checks to make sure "
+ "each specified native server process is not running after the framework stop.")
@@ -382,9 +423,8 @@
private String mSystraceProcessName = null;
@Option(name = "collect-tests-only",
- description = "Only invoke the test binary to collect list of applicable test cases. "
- + "All test run callbacks will be triggered, but test execution will "
- + "not be actually carried out.")
+ description = "Only invoke setUpClass, generate*, and tearDownClass to collect list "
+ + "of applicable test cases. All collected tests pass without being executed.")
private boolean mCollectTestsOnly = false;
@Option(name = "gtest-batch-mode", description = "Run Gtest binaries in batch mode.")
@@ -393,15 +433,6 @@
@Option(name = "log-severity", description = "Set the log severity level.")
private String mLogSeverity = "INFO";
- // This variable is set in order to include the directory that contains the
- // python test cases. This is set before calling the method.
- // {@link #doRunTest(IRunUtil, String, String)}.
- public String mPythonPath = null;
-
- @Option(name = "python-binary", description = "python binary to use "
- + "(optional)")
- private String mPythonBin = null;
-
@Option(name = "run-as-vts-self-test",
description = "Run the module as vts-selftest. "
+ "When the value is set to true, only setUpClass and tearDownClass function "
@@ -409,26 +440,73 @@
+ "Note that exception in tearDownClass will not be reported as failure.")
private boolean mRunAsVtsSelfTest = false;
- private IRunUtil mRunUtil = null;
+ @Option(name = "exclude-coverage-path",
+ description = "The coverage path that should be excluded in results. "
+ + "Used only when enable-coverage is true.")
+ private Collection<String> mExcludeCoveragePath = new ArrayList<>();
+
+ @Option(name = "mobly-test-module",
+ description = "Mobly test module name. "
+ + "If this value is specified, VTS will use mobly test template "
+ + "with the configurations."
+ + "Multiple values can be added by repeatly using this option.")
+ private Collection<String> mMoblyTestModule = new ArrayList<>();
+
+ @Option(name = "acts-test-module",
+ description = "Acts test module name. "
+ + "If this value is specified, VTS will use acts test adapter "
+ + "with the configurations."
+ + "Multiple values can be added by repeatly using this option.")
+ private String mActsTestModule = null;
+
+ @Option(name = "config-str",
+ description = "Key-value map of custom config string. "
+ + "The map will be passed directly to python runner and test module. "
+ + "Only one value per key is stored."
+ + "If the value for the same key is set multiple times, only the last value is "
+ + "used.")
+ private TreeMap<String, String> mConfigStr = new TreeMap<>();
+
+ @Option(name = "config-int",
+ description = "Key-value map of custom config integer. "
+ + "The map will be passed directly to python runner and test module. "
+ + "Only one value per key is stored."
+ + "If the value for the same key is set multiple times, only the last value is "
+ + "used.")
+ private TreeMap<String, Integer> mConfigInt = new TreeMap<>();
+
+ @Option(name = "config-bool",
+ description = "Key-value map of custom config boolean. "
+ + "The map will be passed directly to python runner and test module. "
+ + "Only one value per key is stored."
+ + "If the value for the same key is set multiple times, only the last value is "
+ + "used.")
+ private TreeMap<String, Boolean> mConfigBool = new TreeMap<>();
+
private IBuildInfo mBuildInfo = null;
private String mRunName = "VtsHostDrivenTest";
// the path of a dir which contains the test data files.
private String mTestCaseDataDir = "./";
private VtsVendorConfigFileUtil configReader = null;
+ private IInvocationContext mInvocationContext = null;
+ private OutputUtil mOutputUtil = null;
/**
- * @return the mRunUtil
+ * {@inheritDoc}
*/
- public IRunUtil getRunUtil() {
- return mRunUtil;
+ @Override
+ public void setInvocationContext(IInvocationContext context) {
+ mInvocationContext = context;
+ setDevice(context.getDevices().get(0));
+ setBuild(context.getBuildInfos().get(0));
}
/**
- * @param mRunUtil the mRunUtil to set
+ * @return the mInvocationContext
*/
- public void setRunUtil(IRunUtil mRunUtil) {
- this.mRunUtil = mRunUtil;
+ public IInvocationContext getInvocationContext() {
+ return mInvocationContext;
}
/**
@@ -516,6 +594,29 @@
}
/**
+ * Generate a device json object from ITestDevice object.
+ *
+ * @param device device object
+ * @throws RuntimeException
+ * @throws JSONException
+ */
+ private JSONObject generateJsonDeviceItem(ITestDevice device) throws JSONException {
+ JSONObject deviceItemObject = new JSONObject();
+ deviceItemObject.put(SERIAL, device.getSerialNumber());
+ try {
+ deviceItemObject.put("product_type", device.getProductType());
+ deviceItemObject.put("product_variant", device.getProductVariant());
+ deviceItemObject.put("build_alias", device.getBuildAlias());
+ deviceItemObject.put("build_id", device.getBuildId());
+ deviceItemObject.put("build_flavor", device.getBuildFlavor());
+ } catch (DeviceNotAvailableException e) {
+ CLog.e("Device %s not available.", device.getSerialNumber());
+ throw new RuntimeException("Failed to get device information");
+ }
+ return deviceItemObject;
+ }
+
+ /**
* {@inheritDoc}
*/
@SuppressWarnings("deprecation")
@@ -523,7 +624,17 @@
public void run(ITestInvocationListener listener)
throws IllegalArgumentException, DeviceNotAvailableException {
if (mDevice == null) {
- throw new DeviceNotAvailableException("Device has not been set");
+ throw new DeviceNotAvailableException("Device has not been set.");
+ }
+
+ if (mBuildInfo == null) {
+ throw new RuntimeException("BuildInfo has not been set.");
+ }
+
+ mOutputUtil = new OutputUtil(listener);
+ mOutputUtil.setTestModuleName(mTestModuleName);
+ if (mAbi != null) {
+ mOutputUtil.setAbiName(mAbi.getName());
}
if (mTestCasePath == null) {
@@ -542,7 +653,7 @@
default:
template = TEMPLATE_BINARY_TEST_PATH;
}
- CLog.i("Using default test case template at %s.", template);
+ CLog.d("Using default test case template at %s.", template);
setTestCasePath(template);
if (mEnableCoverage && !mGlobalCoverage) {
CLog.e("Only global coverage is supported for test type %s.", mBinaryTestType);
@@ -553,22 +664,15 @@
} else if (mBinaryTestType.equals(BINARY_TEST_TYPE_LLVMFUZZER)) {
// Fuzz test don't need test-case-path.
setTestCasePath(TEMPLATE_LLVMFUZZER_TEST_PATH);
+ } else if (!mMoblyTestModule.isEmpty()) {
+ setTestCasePath(TEMPLATE_MOBLY_TEST_PATH);
+ } else if (mActsTestModule != null) {
+ setTestCasePath(ADAPTER_ACTS_PATH);
} else {
throw new IllegalArgumentException("test-case-path is not set.");
}
}
- setPythonPath();
-
- if (mPythonBin == null) {
- mPythonBin = getPythonBinary();
- }
-
- if (mRunUtil == null){
- mRunUtil = new RunUtil();
- mRunUtil.setEnvVariable(PYTHONPATH, mPythonPath);
- }
-
doRunTest(listener);
}
@@ -593,7 +697,7 @@
*/
private void populateDefaultJsonFields(JSONObject jsonObject, String testCaseDataDir)
throws IOException, JSONException {
- CLog.i("Populating default fields to json object from %s", DEFAULT_TESTCASE_CONFIG_PATH);
+ CLog.d("Populating default fields to json object from %s", DEFAULT_TESTCASE_CONFIG_PATH);
String content = FileUtil.readStringFromFile(new File(mTestCaseDataDir, DEFAULT_TESTCASE_CONFIG_PATH));
JSONObject defaultJsonObject = new JSONObject(content);
@@ -611,7 +715,7 @@
* @param log_path the path of a directory to store the VTS runner logs.
* @return the updated JSONObject as the new test config.
*/
- private void updateVtsRunnerTestConfig(JSONObject jsonObject)
+ protected void updateVtsRunnerTestConfig(JSONObject jsonObject)
throws IOException, JSONException, RuntimeException {
configReader = new VtsVendorConfigFileUtil();
if (configReader.LoadVendorConfig(mBuildInfo)) {
@@ -621,51 +725,61 @@
}
}
- CLog.i("Load original test config %s %s", mTestCaseDataDir, mTestConfigPath);
+ CLog.d("Load original test config %s %s", mTestCaseDataDir, mTestConfigPath);
String content = null;
if (mTestConfigPath != null) {
content = FileUtil.readStringFromFile(
new File(Paths.get(mTestCaseDataDir, mTestConfigPath).toString()));
- CLog.i("Loaded original test config %s", content);
+ CLog.d("Loaded original test config %s", content);
if (content != null) {
JsonUtil.deepMergeJsonObjects(jsonObject, new JSONObject(content));
}
}
populateDefaultJsonFields(jsonObject, mTestCaseDataDir);
- CLog.i("Built a Json object using the loaded original test config");
+ CLog.d("Built a Json object using the loaded original test config");
JSONArray deviceArray = new JSONArray();
- JSONObject deviceItemObject = new JSONObject();
- deviceItemObject.put(SERIAL, mDevice.getSerialNumber());
boolean coverageBuild = false;
boolean sancovBuild = false;
- try {
- deviceItemObject.put("product_type", mDevice.getProductType());
- deviceItemObject.put("product_variant", mDevice.getProductVariant());
- deviceItemObject.put("build_alias", mDevice.getBuildAlias());
- deviceItemObject.put("build_id", mDevice.getBuildId());
- deviceItemObject.put("build_flavor", mDevice.getBuildFlavor());
+ boolean first_device = true;
+ for (ITestDevice device : mInvocationContext.getDevices()) {
+ JSONObject deviceJson = generateJsonDeviceItem(device);
+ try {
+ String coverageProperty = device.getProperty(COVERAGE_PROPERTY);
+ boolean enable_coverage_for_device =
+ coverageProperty != null && coverageProperty.equals("1");
+ if (first_device) {
+ coverageBuild = enable_coverage_for_device;
+ first_device = false;
+ } else {
+ if (coverageBuild && (!enable_coverage_for_device)) {
+ CLog.e("Device %s is not coverage build while others are.",
+ device.getSerialNumber());
+ throw new RuntimeException("Device build not the same.");
+ }
+ }
+ } catch (DeviceNotAvailableException e) {
+ CLog.e("Device %s not available.", device.getSerialNumber());
+ throw new RuntimeException("Failed to get device information");
+ }
File sancovDir =
- mBuildInfo.getFile(VtsCoveragePreparer.getSancovResourceDirKey(mDevice));
+ mBuildInfo.getFile(VtsCoveragePreparer.getSancovResourceDirKey(device));
if (sancovDir != null) {
- deviceItemObject.put("sancov_resources_path", sancovDir.getAbsolutePath());
+ deviceJson.put("sancov_resources_path", sancovDir.getAbsolutePath());
sancovBuild = true;
}
- File gcovDir = mBuildInfo.getFile(VtsCoveragePreparer.getGcovResourceDirKey(mDevice));
+ File gcovDir = mBuildInfo.getFile(VtsCoveragePreparer.getGcovResourceDirKey(device));
if (gcovDir != null) {
- deviceItemObject.put("gcov_resources_path", gcovDir.getAbsolutePath());
+ deviceJson.put("gcov_resources_path", gcovDir.getAbsolutePath());
coverageBuild = true;
}
- } catch (DeviceNotAvailableException e) {
- CLog.e("A device not available - continuing");
- throw new RuntimeException("Failed to get device information");
+ deviceArray.put(deviceJson);
}
- deviceArray.put(deviceItemObject);
JSONArray testBedArray = (JSONArray) jsonObject.get(TEST_BED);
if (testBedArray.length() == 0) {
@@ -685,7 +799,7 @@
"Failed to derive test module name; use --test-module-name option");
}
}
- CLog.logAndDisplay(LogLevel.INFO, "Setting test name as %s", testName);
+ CLog.d("Setting test module name as %s", testName);
testBedItemObject.put(NAME, testName);
testBedItemObject.put(ANDROIDDEVICE, deviceArray);
testBedArray.put(testBedItemObject);
@@ -712,31 +826,36 @@
throw new RuntimeException("Failed to produce VTS runner test config");
}
jsonObject.put(DATA_FILE_PATH, mTestCaseDataDir);
- CLog.i("Added %s = %s to the Json object", DATA_FILE_PATH, mTestCaseDataDir);
+ CLog.d("Added %s = %s to the Json object", DATA_FILE_PATH, mTestCaseDataDir);
JSONObject build = new JSONObject();
build.put(BUILD_ID, mBuildInfo.getBuildId());
build.put(BUILD_TARGET, mBuildInfo.getBuildTargetName());
jsonObject.put(BUILD, build);
- CLog.i("Added %s to the Json object", BUILD);
+ CLog.d("Added %s to the Json object", BUILD);
JSONObject suite = new JSONObject();
suite.put(NAME, mBuildInfo.getTestTag());
suite.put(INCLUDE_FILTER, new JSONArray(mIncludeFilters));
- CLog.i("Added include filter to test suite: %s", mIncludeFilters);
+ CLog.d("Added include filter to test suite: %s", mIncludeFilters);
suite.put(EXCLUDE_FILTER, new JSONArray(mExcludeFilters));
- CLog.i("Added exclude filter to test suite: %s", mExcludeFilters);
+ CLog.d("Added exclude filter to test suite: %s", mExcludeFilters);
+
+ String coverageReportPath = mBuildInfo.getBuildAttributes().get("coverage_report_path");
+ if (coverageReportPath != null) {
+ jsonObject.put(OUTPUT_COVERAGE_REPORT, true);
+ CLog.d("Added %s to the Json object", OUTPUT_COVERAGE_REPORT);
+ jsonObject.put(COVERAGE_REPORT_PATH, coverageReportPath);
+ CLog.d("Added %s to the Json object", COVERAGE_REPORT_PATH);
+ }
if (mExcludeOverInclude) {
jsonObject.put(EXCLUDE_OVER_INCLUDE, mExcludeOverInclude);
- CLog.i("Added %s to the Json object", EXCLUDE_OVER_INCLUDE);
+ CLog.d("Added %s to the Json object", EXCLUDE_OVER_INCLUDE);
}
jsonObject.put(TEST_SUITE, suite);
- CLog.i("Added %s to the Json object", TEST_SUITE);
-
- jsonObject.put(TEST_MAX_TIMEOUT, mTestTimeout);
- CLog.i("Added %s to the Json object: %d", TEST_MAX_TIMEOUT, mTestTimeout);
+ CLog.d("Added %s to the Json object", TEST_SUITE);
if (!mLogSeverity.isEmpty()) {
String logSeverity = mLogSeverity.toUpperCase();
@@ -748,191 +867,260 @@
logSeverity = "INFO";
}
jsonObject.put(LOG_SEVERITY, logSeverity);
- CLog.i("Added %s to the Json object: %s", LOG_SEVERITY, logSeverity);
+ CLog.d("Added %s to the Json object: %s", LOG_SEVERITY, logSeverity);
}
if (mAbi != null) {
jsonObject.put(ABI_NAME, mAbi.getName());
- CLog.i("Added %s to the Json object", ABI_NAME);
+ CLog.d("Added %s to the Json object", ABI_NAME);
jsonObject.put(ABI_BITNESS, mAbi.getBitness());
- CLog.i("Added %s to the Json object", ABI_BITNESS);
+ CLog.d("Added %s to the Json object", ABI_BITNESS);
}
if (mSkipOn32BitAbi) {
jsonObject.put(SKIP_ON_32BIT_ABI, mSkipOn32BitAbi);
- CLog.i("Added %s to the Json object", SKIP_ON_32BIT_ABI);
+ CLog.d("Added %s to the Json object", SKIP_ON_32BIT_ABI);
}
if (mSkipOn64BitAbi) {
jsonObject.put(SKIP_ON_64BIT_ABI, mSkipOn64BitAbi);
- CLog.i("Added %s to the Json object", SKIP_ON_64BIT_ABI);
+ CLog.d("Added %s to the Json object", SKIP_ON_64BIT_ABI);
} else if (mRun32bBitOn64BitAbi) {
jsonObject.put(RUN_32BIT_ON_64BIT_ABI, mRun32bBitOn64BitAbi);
- CLog.i("Added %s to the Json object", RUN_32BIT_ON_64BIT_ABI);
+ CLog.d("Added %s to the Json object", RUN_32BIT_ON_64BIT_ABI);
}
if (mSkipIfThermalThrottling) {
jsonObject.put(SKIP_IF_THERMAL_THROTTLING, mSkipIfThermalThrottling);
- CLog.i("Added %s to the Json object", SKIP_IF_THERMAL_THROTTLING);
+ CLog.d("Added %s to the Json object", SKIP_IF_THERMAL_THROTTLING);
}
+ jsonObject.put(DISABLE_CPU_FREQUENCY_SCALING, mDisableCpuFrequencyScaling);
+ CLog.d("Added %s to the Json object, value: %s", DISABLE_CPU_FREQUENCY_SCALING,
+ mDisableCpuFrequencyScaling);
+
if (!mBinaryTestSource.isEmpty()) {
jsonObject.put(BINARY_TEST_SOURCE, new JSONArray(mBinaryTestSource));
- CLog.i("Added %s to the Json object", BINARY_TEST_SOURCE);
+ CLog.d("Added %s to the Json object", BINARY_TEST_SOURCE);
}
if (!mBinaryTestWorkingDirectory.isEmpty()) {
jsonObject.put(BINARY_TEST_WORKING_DIRECTORY,
new JSONArray(mBinaryTestWorkingDirectory));
- CLog.i("Added %s to the Json object", BINARY_TEST_WORKING_DIRECTORY);
+ CLog.d("Added %s to the Json object", BINARY_TEST_WORKING_DIRECTORY);
}
if (!mBinaryTestEnvp.isEmpty()) {
jsonObject.put(BINARY_TEST_ENVP, new JSONArray(mBinaryTestEnvp));
- CLog.i("Added %s to the Json object", BINARY_TEST_ENVP);
+ CLog.d("Added %s to the Json object", BINARY_TEST_ENVP);
}
if (!mBinaryTestArgs.isEmpty()) {
jsonObject.put(BINARY_TEST_ARGS, new JSONArray(mBinaryTestArgs));
- CLog.i("Added %s to the Json object", BINARY_TEST_ARGS);
+ CLog.d("Added %s to the Json object", BINARY_TEST_ARGS);
}
if (!mBinaryTestLdLibraryPath.isEmpty()) {
jsonObject.put(BINARY_TEST_LD_LIBRARY_PATH,
new JSONArray(mBinaryTestLdLibraryPath));
- CLog.i("Added %s to the Json object", BINARY_TEST_LD_LIBRARY_PATH);
+ CLog.d("Added %s to the Json object", BINARY_TEST_LD_LIBRARY_PATH);
}
if (mBugReportOnFailure) {
jsonObject.put(BUG_REPORT_ON_FAILURE, mBugReportOnFailure);
- CLog.i("Added %s to the Json object", BUG_REPORT_ON_FAILURE);
+ CLog.d("Added %s to the Json object", BUG_REPORT_ON_FAILURE);
+ }
+
+ if (!mLogcatOnFailure) {
+ jsonObject.put(LOGCAT_ON_FAILURE, mLogcatOnFailure);
+ CLog.d("Added %s to the Json object", LOGCAT_ON_FAILURE);
}
if (mEnableProfiling) {
jsonObject.put(ENABLE_PROFILING, mEnableProfiling);
- CLog.i("Added %s to the Json object", ENABLE_PROFILING);
+ CLog.d("Added %s to the Json object", ENABLE_PROFILING);
}
if (mSaveTraceFileRemote) {
jsonObject.put(SAVE_TRACE_FIEL_REMOTE, mSaveTraceFileRemote);
- CLog.i("Added %s to the Json object", SAVE_TRACE_FIEL_REMOTE);
+ CLog.d("Added %s to the Json object", SAVE_TRACE_FIEL_REMOTE);
}
if (mEnableSystrace) {
jsonObject.put(ENABLE_SYSTRACE, mEnableSystrace);
- CLog.i("Added %s to the Json object", ENABLE_SYSTRACE);
+ CLog.d("Added %s to the Json object", ENABLE_SYSTRACE);
}
if (mEnableCoverage) {
jsonObject.put(GLOBAL_COVERAGE, mGlobalCoverage);
+ if (!mExcludeCoveragePath.isEmpty()) {
+ jsonObject.put(EXCLUDE_COVERAGE_PATH, new JSONArray(mExcludeCoveragePath));
+ CLog.d("Added %s to the Json object", EXCLUDE_COVERAGE_PATH);
+ }
if (coverageBuild) {
jsonObject.put(ENABLE_COVERAGE, mEnableCoverage);
- CLog.i("Added %s to the Json object", ENABLE_COVERAGE);
+ CLog.d("Added %s to the Json object", ENABLE_COVERAGE);
} else {
- CLog.i("Device build has coverage disabled");
+ CLog.d("Device build has coverage disabled");
}
}
if (mEnableSancov) {
if (sancovBuild) {
jsonObject.put(ENABLE_SANCOV, mEnableSancov);
- CLog.i("Added %s to the Json object", ENABLE_SANCOV);
+ CLog.d("Added %s to the Json object", ENABLE_SANCOV);
} else {
- CLog.i("Device build has sancov disabled");
+ CLog.d("Device build has sancov disabled");
}
}
- if (mOutputCoverageReport) {
- jsonObject.put(OUTPUT_COVERAGE_REPORT, mOutputCoverageReport);
- CLog.i("Added %s to the Json object", OUTPUT_COVERAGE_REPORT);
- }
-
if (mPreconditionHwBinderServiceName != null) {
jsonObject.put(PRECONDITION_HWBINDER_SERVICE, mPreconditionHwBinderServiceName);
- CLog.i("Added %s to the Json object", PRECONDITION_HWBINDER_SERVICE);
+ CLog.d("Added %s to the Json object", PRECONDITION_HWBINDER_SERVICE);
}
if (mPreconditionFeature != null) {
jsonObject.put(PRECONDITION_FEATURE, mPreconditionFeature);
- CLog.i("Added %s to the Json object", PRECONDITION_FEATURE);
+ CLog.d("Added %s to the Json object", PRECONDITION_FEATURE);
}
if (!mPreconditionFilePathPrefix.isEmpty()) {
jsonObject.put(
PRECONDITION_FILE_PATH_PREFIX, new JSONArray(mPreconditionFilePathPrefix));
- CLog.i("Added %s to the Json object", PRECONDITION_FILE_PATH_PREFIX);
+ CLog.d("Added %s to the Json object", PRECONDITION_FILE_PATH_PREFIX);
+ }
+
+ if (mPreconditionFirstApiLevel != 0) {
+ jsonObject.put(PRECONDITION_FIRST_API_LEVEL, mPreconditionFirstApiLevel);
+ CLog.d("Added %s to the Json object", PRECONDITION_FIRST_API_LEVEL);
}
if (mPreconditionLshal != null) {
jsonObject.put(PRECONDITION_LSHAL, mPreconditionLshal);
- CLog.i("Added %s to the Json object", PRECONDITION_LSHAL);
+ CLog.d("Added %s to the Json object", PRECONDITION_LSHAL);
}
if (mPreconditionVintf != null) {
jsonObject.put(PRECONDITION_VINTF, mPreconditionVintf);
- CLog.i("Added %s to the Json object", PRECONDITION_VINTF);
+ CLog.d("Added %s to the Json object", PRECONDITION_VINTF);
+ }
+
+ if (mPreconditionSysProp != null) {
+ jsonObject.put(PRECONDITION_SYSPROP, mPreconditionSysProp);
+ CLog.d("Added %s to the Json object", PRECONDITION_SYSPROP);
}
if (!mBinaryTestProfilingLibraryPath.isEmpty()) {
jsonObject.put(BINARY_TEST_PROFILING_LIBRARY_PATH,
new JSONArray(mBinaryTestProfilingLibraryPath));
- CLog.i("Added %s to the Json object", BINARY_TEST_PROFILING_LIBRARY_PATH);
+ CLog.d("Added %s to the Json object", BINARY_TEST_PROFILING_LIBRARY_PATH);
+ }
+
+ if (mDisableFramework) {
+ jsonObject.put(DISABLE_FRAMEWORK, mDisableFramework);
+ CLog.d("Added %s to the Json object", DISABLE_FRAMEWORK);
+ }
+
+ if (mStopNativeServers) {
+ jsonObject.put(STOP_NATIVE_SERVERS, mStopNativeServers);
+ CLog.d("Added %s to the Json object", STOP_NATIVE_SERVERS);
}
if (mBinaryTestDisableFramework) {
jsonObject.put(BINARY_TEST_DISABLE_FRAMEWORK, mBinaryTestDisableFramework);
- CLog.i("Added %s to the Json object", BINARY_TEST_DISABLE_FRAMEWORK);
+ CLog.d("Added %s to the Json object", BINARY_TEST_DISABLE_FRAMEWORK);
}
if (mBinaryTestStopNativeServers) {
jsonObject.put(BINARY_TEST_STOP_NATIVE_SERVERS, mBinaryTestStopNativeServers);
- CLog.i("Added %s to the Json object", BINARY_TEST_STOP_NATIVE_SERVERS);
+ CLog.d("Added %s to the Json object", BINARY_TEST_STOP_NATIVE_SERVERS);
}
if (!mNativeServerProcessName.isEmpty()) {
jsonObject.put(NATIVE_SERVER_PROCESS_NAME, new JSONArray(mNativeServerProcessName));
- CLog.i("Added %s to the Json object", NATIVE_SERVER_PROCESS_NAME);
+ CLog.d("Added %s to the Json object", NATIVE_SERVER_PROCESS_NAME);
}
if (!mHalHidlReplayTestTracePaths.isEmpty()) {
jsonObject.put(HAL_HIDL_REPLAY_TEST_TRACE_PATHS,
new JSONArray(mHalHidlReplayTestTracePaths));
- CLog.i("Added %s to the Json object", HAL_HIDL_REPLAY_TEST_TRACE_PATHS);
+ CLog.d("Added %s to the Json object", HAL_HIDL_REPLAY_TEST_TRACE_PATHS);
}
if (mHalHidlPackageName != null) {
jsonObject.put(HAL_HIDL_PACKAGE_NAME, mHalHidlPackageName);
- CLog.i("Added %s to the Json object", SYSTRACE_PROCESS_NAME);
+ CLog.d("Added %s to the Json object", SYSTRACE_PROCESS_NAME);
}
if (mSystraceProcessName != null) {
jsonObject.put(SYSTRACE_PROCESS_NAME, mSystraceProcessName);
- CLog.i("Added %s to the Json object", SYSTRACE_PROCESS_NAME);
+ CLog.d("Added %s to the Json object", SYSTRACE_PROCESS_NAME);
}
if (mPassthroughMode) {
jsonObject.put(PASSTHROUGH_MODE, mPassthroughMode);
- CLog.i("Added %s to the Json object", PASSTHROUGH_MODE);
+ CLog.d("Added %s to the Json object", PASSTHROUGH_MODE);
+ }
+
+ if (mCollectTestsOnly) {
+ jsonObject.put(COLLECT_TESTS_ONLY, mCollectTestsOnly);
+ CLog.d("Added %s to the Json object", COLLECT_TESTS_ONLY);
}
if (mGtestBatchMode) {
jsonObject.put(GTEST_BATCH_MODE, mGtestBatchMode);
- CLog.i("Added %s to the Json object", GTEST_BATCH_MODE);
+ CLog.d("Added %s to the Json object", GTEST_BATCH_MODE);
}
if (mLtpNumberOfThreads >= 0) {
jsonObject.put(LTP_NUMBER_OF_THREADS, mLtpNumberOfThreads);
- CLog.i("Added %s to the Json object", LTP_NUMBER_OF_THREADS);
+ CLog.d("Added %s to the Json object", LTP_NUMBER_OF_THREADS);
}
if (mRunAsVtsSelfTest) {
jsonObject.put(RUN_AS_VTS_SELF_TEST, mRunAsVtsSelfTest);
- CLog.i("Added %s to the Json object", RUN_AS_VTS_SELF_TEST);
+ CLog.d("Added %s to the Json object", RUN_AS_VTS_SELF_TEST);
}
if ("vts".equals(mBuildInfo.getTestTag())) {
jsonObject.put(RUN_AS_COMPLIANCE_TEST, true);
- CLog.i("Added %s to the Json object", RUN_AS_COMPLIANCE_TEST);
+ CLog.d("Added %s to the Json object", RUN_AS_COMPLIANCE_TEST);
+ }
+
+ if (!mMoblyTestModule.isEmpty()) {
+ jsonObject.put(MOBLY_TEST_MODULE, new JSONArray(mMoblyTestModule));
+ CLog.d("Added %s to the Json object", MOBLY_TEST_MODULE);
+ }
+
+ if (mActsTestModule != null) {
+ jsonObject.put(ACTS_TEST_MODULE, mActsTestModule);
+ CLog.d("Added %s to the Json object", ACTS_TEST_MODULE);
+ }
+
+ if (mBuildInfo.getFile(VtsPythonVirtualenvPreparer.VIRTUAL_ENV) != null) {
+ jsonObject.put(VtsPythonVirtualenvPreparer.VIRTUAL_ENV,
+ mBuildInfo.getFile(VtsPythonVirtualenvPreparer.VIRTUAL_ENV).getAbsolutePath());
+ }
+
+ if (mBuildInfo.getFile(VtsPythonVirtualenvPreparer.VIRTUAL_ENV_V3) != null) {
+ jsonObject.put(VtsPythonVirtualenvPreparer.VIRTUAL_ENV_V3,
+ mBuildInfo.getFile(VtsPythonVirtualenvPreparer.VIRTUAL_ENV_V3)
+ .getAbsolutePath());
+ }
+
+ if (!mConfigStr.isEmpty()) {
+ jsonObject.put(CONFIG_STR, new JSONObject(mConfigStr));
+ CLog.d("Added %s to the Json object", CONFIG_STR);
+ }
+
+ if (!mConfigInt.isEmpty()) {
+ jsonObject.put(CONFIG_INT, new JSONObject(mConfigInt));
+ CLog.d("Added %s to the Json object", CONFIG_INT);
+ }
+
+ if (!mConfigBool.isEmpty()) {
+ jsonObject.put(CONFIG_BOOL, new JSONObject(mConfigBool));
+ CLog.d("Added %s to the Json object", CONFIG_BOOL);
}
}
@@ -961,80 +1149,23 @@
}
File reportFile = mBuildInfo.getFile(TEST_PLAN_REPORT_FILE);
- try (FileWriter fw = new FileWriter(reportFile.getAbsoluteFile(), true);
- BufferedWriter bw = new BufferedWriter(fw); PrintWriter out = new PrintWriter(bw)) {
- out.println(String.format("%s %s", test_module_name, test_module_timestamp));
- } catch (IOException e) {
- CLog.e(String.format(
- "Can't write to the test plan result file, %s", TEST_PLAN_REPORT_FILE));
- return false;
+ if (reportFile != null) {
+ try (FileWriter fw = new FileWriter(reportFile.getAbsoluteFile(), true);
+ BufferedWriter bw = new BufferedWriter(fw);
+ PrintWriter out = new PrintWriter(bw)) {
+ out.println(String.format("%s %s", test_module_name, test_module_timestamp));
+ } catch (IOException e) {
+ CLog.e(String.format(
+ "Can't write to the test plan result file, %s", TEST_PLAN_REPORT_FILE));
+ return false;
+ }
+ } else {
+ CLog.w("No test plan report file configured.");
}
return true;
}
/**
- * Create a {@link ProcessHelper} from mRunUtil.
- *
- * @param cmd the command to run.
- * @throws IOException if fails to start Process.
- */
- protected ProcessHelper createProcessHelper(String[] cmd) throws IOException {
- return new ProcessHelper(mRunUtil.runCmdInBackground(cmd));
- }
-
- /**
- * Run VTS Python runner and handle interrupt from TradeFed.
- *
- * @param cmd the command to start VTS Python runner.
- * @param commandResult the object containing the command result.
- * @return null if the command terminates or times out; a message string if the command is
- * interrupted by TradeFed.
- */
- private String runPythonRunner(String[] cmd, CommandResult commandResult) {
- ProcessHelper process;
- try {
- process = createProcessHelper(cmd);
- } catch (IOException e) {
- CLog.e(e);
- commandResult.setStatus(CommandStatus.EXCEPTION);
- commandResult.setStdout("");
- commandResult.setStderr("");
- return null;
- }
-
- String interruptMessage;
- try {
- CommandStatus commandStatus;
- try {
- commandStatus = process.waitForProcess(mTestTimeout);
- interruptMessage = null;
- } catch (RunInterruptedException e) {
- CLog.e("Python process is interrupted.");
- commandStatus = CommandStatus.TIMED_OUT;
- interruptMessage = (e.getMessage() != null ? e.getMessage() : "");
- }
- if (process.isRunning()) {
- CLog.e("Cancel Python process and wait %d seconds.",
- TEST_ABORT_TIMEOUT_MSECS / 1000);
- try {
- process.closeStdin();
- // Wait for the process to clean up and ignore the CommandStatus.
- // Propagate RunInterruptedException if this is interrupted again.
- process.waitForProcess(TEST_ABORT_TIMEOUT_MSECS);
- } catch (IOException e) {
- CLog.e("Fail to cancel Python process.");
- }
- }
- commandResult.setStatus(commandStatus);
- } finally {
- process.cleanUp();
- }
- commandResult.setStdout(process.getStdout());
- commandResult.setStderr(process.getStderr());
- return interruptMessage;
- }
-
- /**
* This method prepares a command for the test and runs the python file as
* given in the arguments.
*
@@ -1043,7 +1174,9 @@
* @throws IllegalArgumentException
*/
private void doRunTest(ITestRunListener listener) throws RuntimeException, IllegalArgumentException {
- CLog.i("Device serial number: " + mDevice.getSerialNumber());
+ CLog.d("Device serial number: " + mDevice.getSerialNumber());
+
+ setTestCaseDataDir();
JSONObject jsonObject = new JSONObject();
File vtsRunnerLogDir = null;
@@ -1052,21 +1185,21 @@
updateVtsRunnerTestConfig(jsonObject);
jsonObject.put(LOG_PATH, vtsRunnerLogDir.getAbsolutePath());
- CLog.i("Added %s to the Json object", LOG_PATH);
+ CLog.d("Added %s to the Json object", LOG_PATH);
} catch(IOException e) {
throw new RuntimeException("Failed to read test config json file");
} catch(JSONException e) {
throw new RuntimeException("Failed to build updated test config json data");
}
- CLog.i("config json: %s", jsonObject.toString());
+ CLog.d("config json: %s", jsonObject.toString());
String jsonFilePath = null;
try {
File tmpFile = FileUtil.createTempFile(
mBuildInfo.getTestTag() + "-config-" + mBuildInfo.getDeviceSerial(), ".json");
jsonFilePath = tmpFile.getAbsolutePath();
- CLog.i("config json file path: %s", jsonFilePath);
+ CLog.d("config json file path: %s", jsonFilePath);
FileWriter fw = new FileWriter(jsonFilePath);
fw.write(jsonObject.toString());
fw.close();
@@ -1074,48 +1207,41 @@
throw new RuntimeException("Failed to create device config json file");
}
- if (mPythonBin == null){
- mPythonBin = getPythonBinary();
- }
- mRunUtil.setEnvVariable("VTS", "1");
- String[] baseOpts = {
- mPythonBin,
- };
- String[] testModule = new String[2];
- String[] cmd;
+ VtsPythonRunnerHelper vtsPythonRunnerHelper = createVtsPythonRunnerHelper();
+
+ List<String> cmd = new ArrayList<>();
+ cmd.add("python");
if (mTestCasePathType != null && mTestCasePathType.toLowerCase().equals("file")) {
- testModule[0] = mTestCasePath;
- if (!mTestCasePath.endsWith(".py")) {
- testModule[0] += ".py";
+ String testScript = mTestCasePath;
+ if (!testScript.endsWith(".py")) {
+ testScript += ".py";
}
+ cmd.add(testScript);
} else {
- baseOpts = new String[2];
- baseOpts[0] = mPythonBin;
- baseOpts[1] = "-m";
- testModule[0] = mTestCasePath.replace("/", ".");
+ cmd.add("-m");
+ cmd.add(mTestCasePath.replace("/", "."));
}
- testModule[1] = jsonFilePath;
- cmd = ArrayUtil.buildArray(baseOpts, testModule);
+ cmd.add(jsonFilePath);
printToDeviceLogcatAboutTestModuleStatus("BEGIN");
CommandResult commandResult = new CommandResult();
- String interruptMessage = runPythonRunner(cmd, commandResult);
+ String interruptMessage = vtsPythonRunnerHelper.runPythonRunner(
+ cmd.toArray(new String[0]), commandResult, mTestTimeout);
if (commandResult != null) {
CommandStatus commandStatus = commandResult.getStatus();
if (commandStatus != CommandStatus.SUCCESS
&& commandStatus != CommandStatus.TIMED_OUT) {
CLog.e("Python process failed");
- CLog.e("Python path: %s", mPythonPath);
- CLog.e("Stderr: %s", commandResult.getStderr());
- CLog.e("Stdout: %s", commandResult.getStdout());
- printVtsLogs(vtsRunnerLogDir);
+ CLog.e("Command stdout: " + commandResult.getStdout());
+ CLog.e("Command stderr: " + commandResult.getStderr());
+ CLog.e("Command status: " + commandStatus);
+ CLog.e("Python log: ");
+ mOutputUtil.collectVtsRunnerOutputs(vtsRunnerLogDir);
printToDeviceLogcatAboutTestModuleStatus("ERROR");
throw new RuntimeException("Failed to run VTS test");
}
- CLog.i("Standard output is: %s", commandResult.getStdout());
- CLog.i("Parsing test result: %s", commandResult.getStderr());
printToDeviceLogcatAboutTestModuleStatus("END");
}
@@ -1134,49 +1260,37 @@
JSONObject object = null;
File testRunSummary = getFileTestRunSummary(vtsRunnerLogDir);
if (testRunSummary == null) {
- throw new RuntimeException("Couldn't locate the file : " +
- TEST_RUN_SUMMARY_FILE_NAME);
- }
- try {
- jsonData = FileUtil.readStringFromFile(testRunSummary);
- CLog.i("Test Result Summary: %s", jsonData);
- object = new JSONObject(jsonData);
- } catch (IOException e) {
- CLog.e("Error occurred in parsing Json file : %s", testRunSummary.toPath());
- } catch (JSONException e) {
- CLog.e("Error occurred in parsing Json String : %s", jsonData);
- }
- if (object == null) {
- CLog.e("Json object is null.");
- throw new RuntimeException("Json object is null.");
- }
- parser.processJsonFile(object);
+ CLog.e("Couldn't locate the file : " + TEST_RUN_SUMMARY_FILE_NAME);
+ } else {
+ try {
+ jsonData = FileUtil.readStringFromFile(testRunSummary);
+ CLog.d("Test Result Summary: %s", jsonData);
+ object = new JSONObject(jsonData);
+ } catch (IOException e) {
+ CLog.e("Error occurred in parsing Json file : %s", testRunSummary.toPath());
+ } catch (JSONException e) {
+ CLog.e("Error occurred in parsing Json String : %s", jsonData);
+ }
+ if (object == null) {
+ CLog.e("Json object is null.");
+ throw new RuntimeException("Json object is null.");
+ }
+ parser.processJsonFile(object);
- try {
- JSONObject planObject = object.getJSONObject(TESTMODULE);
- String test_module_name = planObject.getString("Name");
- long test_module_timestamp = planObject.getLong("Timestamp");
- AddTestModuleKeys(test_module_name, test_module_timestamp);
- } catch (JSONException e) {
- CLog.d("Key '%s' not found in result json summary", TESTMODULE);
+ try {
+ JSONObject planObject = object.getJSONObject(TESTMODULE);
+ String test_module_name = planObject.getString("Name");
+ long test_module_timestamp = planObject.getLong("Timestamp");
+ AddTestModuleKeys(test_module_name, test_module_timestamp);
+ } catch (JSONException e) {
+ CLog.d("Key '%s' not found in result json summary", TESTMODULE);
+ }
}
}
- printVtsLogs(vtsRunnerLogDir);
+ mOutputUtil.collectVtsRunnerOutputs(vtsRunnerLogDir);
- File reportMsg;
- int waitCount = 0;
- // Wait python process to finish for 3 minutes at most
- while ((reportMsg = FileUtil.findFile(vtsRunnerLogDir, REPORT_MESSAGE_FILE_NAME)) == null
- && waitCount < 180) {
- try {
- Thread.sleep(1000);
- } catch (Exception e) {
- System.out.println(e);
- }
- waitCount++;
- }
-
- CLog.i("Report message path: %s", reportMsg);
+ File reportMsg = FileUtil.findFile(vtsRunnerLogDir, REPORT_MESSAGE_FILE_NAME);
+ CLog.d("Report message path: %s", reportMsg);
if (reportMsg == null) {
CLog.e("Cannot find report message proto file.");
@@ -1185,14 +1299,14 @@
VtsDashboardUtil dashboardUtil = new VtsDashboardUtil(configReader);
dashboardUtil.Upload(reportMsg.getAbsolutePath());
} else {
- CLog.i("Result uploading is not enabled.");
+ CLog.d("Result uploading is not enabled.");
}
FileUtil.recursiveDelete(vtsRunnerLogDir);
- CLog.i("Deleted the runner log dir, %s.", vtsRunnerLogDir);
+ CLog.d("Deleted the runner log dir, %s.", vtsRunnerLogDir);
if (jsonFilePath != null) {
FileUtil.deleteFile(new File(jsonFilePath));
- CLog.i("Deleted the runner json config file, %s.", jsonFilePath);
+ CLog.d("Deleted the runner json config file, %s.", jsonFilePath);
}
if (interruptMessage != null) {
@@ -1201,10 +1315,10 @@
}
/**
- * This method return the file test_run_details.txt which is then used to parse logs.
+ * This method return the file test_run_summary.json which is then used to parse logs.
*
* @param logDir : The file that needs to be converted
- * @return the file named test_run_details.txt
+ * @return the file named test_run_summary.json
* @throws IllegalArgumentException
*/
private File getFileTestRunSummary(File logDir) throws IllegalArgumentException {
@@ -1231,133 +1345,33 @@
}
/**
- * The method prints all VTS runner log files
- *
- * @param logDir the File instance of the base log dir.
+ * Set the path for android-vts/testcases/ which keeps the VTS python code under vts.
*/
- private void printVtsLogs(File logDir) {
- File[] children;
- if (logDir == null) {
- CLog.e("Scan VTS log dir: null\n");
- return;
+ private void setTestCaseDataDir() {
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuildInfo);
+ File testDir = null;
+ try {
+ testDir = buildHelper.getTestsDir();
+ } catch (FileNotFoundException e) {
+ /* pass */
}
- CLog.i("Scan VTS log dir %s\n", logDir.getAbsolutePath());
- children = logDir.listFiles();
- if (children != null) {
- for (File child : children) {
- if (child.isDirectory()) {
- printVtsLogs(child);
- } else {
- CLog.i("VTS log file %s\n", child.getAbsolutePath());
- try {
- if (child.getName().startsWith("vts_agent") &&
- child.getName().endsWith(".log")) {
- CLog.i("Content: %s\n", FileUtil.readStringFromFile(child));
- } else {
- CLog.i("skip %s\n", child.getName());
- }
- } catch (IOException e) {
- CLog.e("I/O error\n");
- }
- }
- }
+ if (testDir != null) {
+ mTestCaseDataDir = testDir.getAbsolutePath();
}
}
/**
- * This method returns whether the OS is Windows.
- */
- private static boolean isOnWindows() {
- return System.getProperty(OS_NAME).contains(WINDOWS);
- }
-
- /**
- * This method sets the python path. It's based on the
- * assumption that the environment variable $ANDROID_BUILD_TOP is set.
- */
- private void setPythonPath() {
- StringBuilder sb = new StringBuilder();
- String separator = File.pathSeparator;
- if (System.getenv(PYTHONPATH) != null) {
- sb.append(separator);
- sb.append(System.getenv(PYTHONPATH));
- }
-
- // to get the path for android-vts/testcases/ which keeps the VTS python code under vts.
- if (mBuildInfo != null) {
- CompatibilityBuildHelper mBuildHelper = new CompatibilityBuildHelper(mBuildInfo);
-
- File testDir = null;
- try {
- testDir = mBuildHelper.getTestsDir();
- } catch (FileNotFoundException e) {
- /* pass */
- }
- if (testDir != null) {
- sb.append(separator);
- mTestCaseDataDir = testDir.getAbsolutePath();
- sb.append(mTestCaseDataDir);
- } else if (mBuildInfo.getFile(VTS) != null) {
- sb.append(separator);
- sb.append(mBuildInfo.getFile(VTS).getAbsolutePath()).append("/..");
- }
- }
-
- // for when one uses PythonVirtualenvPreparer.
- if (mBuildInfo.getFile(PYTHONPATH) != null) {
- sb.append(separator);
- sb.append(mBuildInfo.getFile(PYTHONPATH).getAbsolutePath());
- }
- if (System.getenv("ANDROID_BUILD_TOP") != null) {
- sb.append(separator);
- sb.append(System.getenv("ANDROID_BUILD_TOP")).append("/test");
- }
- if (sb.length() == 0) {
- throw new RuntimeException("Could not find python path on host machine");
- }
- mPythonPath = sb.substring(1);
- CLog.i("mPythonPath: %s", mPythonPath);
- }
-
- /**
- * This method gets the python binary.
- */
- private String getPythonBinary() {
- boolean isWindows = isOnWindows();
- String python = (isWindows ? "python.exe" : "python" + mPythonVersion);
- File venvDir = mBuildInfo.getFile(VIRTUAL_ENV_PATH);
- if (venvDir != null) {
- String binDir = (isWindows? "Scripts": "bin");
- File pythonBinaryFile = new File(venvDir.getAbsolutePath(),
- binDir + File.separator + python);
- String pythonBinPath = pythonBinaryFile.getAbsolutePath();
- if (pythonBinaryFile.exists()) {
- CLog.i("Python path " + pythonBinPath + ".\n");
- return pythonBinPath;
- }
- CLog.e(python + " doesn't exist under the " +
- "created virtualenv dir (" + pythonBinPath + ").\n");
- } else {
- CLog.e(VIRTUAL_ENV_PATH + " not available in BuildInfo. " +
- "Please use VtsPythonVirtualenvPreparer tartget preparer.\n");
- }
-
- IRunUtil runUtil = (mRunUtil == null ? RunUtil.getDefault() : mRunUtil);
- CommandResult c = runUtil.runTimedCmd(1000,
- (isWindows ? "where" : "which"), python);
- String pythonBin = c.getStdout().trim();
- if (pythonBin.length() == 0) {
- throw new RuntimeException("Could not find python binary on host "
- + "machine");
- }
- return pythonBin;
- }
-
- /**
* {@inheritDoc}
*/
@Override
public void setAbi(IAbi abi){
mAbi = abi;
}
+
+ /**
+ * Creates VtsPythonRunnerHelper.
+ */
+ protected VtsPythonRunnerHelper createVtsPythonRunnerHelper() {
+ return new VtsPythonRunnerHelper(mBuildInfo);
+ }
}
diff --git a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTestResultParser.java b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTestResultParser.java
index 3a2bb3a..f018c9f 100644
--- a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTestResultParser.java
+++ b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTestResultParser.java
@@ -322,10 +322,16 @@
listener.testEnded(test.getKey(), Collections.<String, String>emptyMap());
} else if (test.getValue() == TIMEOUT) {
listener.testFailed(test.getKey(), test.getValue());
+ // Always call testEnded at the end of the test case
+ listener.testEnded(test.getKey(), Collections.emptyMap());
} else if (test.getValue() == SKIP) {
listener.testAssumptionFailure(test.getKey(), test.getValue());
+ // Always call testEnded at the end of the test case
+ listener.testEnded(test.getKey(), Collections.emptyMap());
} else {
listener.testFailed(test.getKey(), test.getValue());
+ // Always call testEnded at the end of the test case
+ listener.testEnded(test.getKey(), Collections.emptyMap());
}
}
listener.testRunEnded(mTotalElapsedTime, Collections.<String, String>emptyMap());
@@ -365,7 +371,7 @@
}
sb.append("\n");
}
- CLog.logAndDisplay(LogLevel.INFO, sb.toString());
+ CLog.d("JSON table: %s", sb.toString());
}
/**
@@ -414,6 +420,8 @@
recognized in TF, it is converted to FAIL. */
listener.testFailed(
testIdentifier, details.isEmpty() ? UNKNOWN_ERROR : details);
+ // Always call testEnded at the end of the test case
+ listener.testEnded(testIdentifier, Collections.emptyMap());
case PASS :
listener.testEnded(testIdentifier, Collections.<String, String>emptyMap());
break;
@@ -421,6 +429,8 @@
/* Timeout is not recognized in TF. Use FAIL instead. */
listener.testFailed(
testIdentifier, details.isEmpty() ? UNKNOWN_TIMEOUT : details);
+ // Always call testEnded at the end of the test case
+ listener.testEnded(testIdentifier, Collections.emptyMap());
break;
case SKIP :
/* Skip is not recognized in TF */
@@ -429,6 +439,8 @@
/* Indicates a test failure. */
listener.testFailed(
testIdentifier, details.isEmpty() ? UNKNOWN_FAILURE : details);
+ // Always call testEnded at the end of the test case
+ listener.testEnded(testIdentifier, Collections.emptyMap());
default:
break;
}
diff --git a/harnesses/tradefed/src/com/android/tradefed/util/CmdUtil.java b/harnesses/tradefed/src/com/android/tradefed/util/CmdUtil.java
new file mode 100644
index 0000000..c7a2256
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/tradefed/util/CmdUtil.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.tradefed.util;
+
+import com.android.annotations.VisibleForTesting;
+import com.android.ddmlib.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import java.util.Vector;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
+
+public class CmdUtil {
+ public static final int MAX_RETRY_COUNT = 10;
+ static final int DELAY_BETWEEN_RETRY_IN_SECS = 3;
+ static final long FRAMEWORK_START_TIMEOUT = 1000 * 60 * 2; // 2 minutes.
+ static final String BOOTCOMPLETE_PROP = "dev.bootcomplete";
+
+ // An interface to wait with delay. Used for testing purpose.
+ public interface ISleeper { public void sleep(int seconds) throws InterruptedException; }
+ private ISleeper mSleeper = null;
+
+ /**
+ * Helper method to retry given cmd until the expected results are satisfied.
+ * An example usage it to retry 'lshal' until the expected hal service appears.
+ *
+ * @param device testing device.
+ * @param cmd the command string to be executed on device.
+ * @param predicate function that checks the exit condition.
+ * @return true if the exit condition is satisfied, false otherwise.
+ * @throws DeviceNotAvailableException
+ */
+ public boolean waitCmdResultWithDelay(ITestDevice device, String cmd,
+ Predicate<String> predicate) throws DeviceNotAvailableException {
+ for (int count = 0; count < MAX_RETRY_COUNT; count++) {
+ if (validateCmdSuccess(device, cmd, predicate)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Helper method to retry a given set of commands, cmds.
+ *
+ * @param device testing device.
+ * @param cmds a vector of the command strings to be executed on device.
+ * @param validation_cmd the validation command string to be executed on device.
+ * @param predicate function that checks the exit condition.
+ * @return true if the exit condition is satisfied, false otherwise.
+ * @throws DeviceNotAvailableException
+ */
+ public boolean retry(ITestDevice device, Vector<String> cmds, String validation_cmd,
+ Predicate<String> predicate) throws DeviceNotAvailableException {
+ if (cmds.isEmpty()) {
+ CLog.w("retry() called but cmd is an epmty vector.");
+ return false;
+ }
+ for (int count = 0; count < MAX_RETRY_COUNT; count++) {
+ for (String cmd : cmds) {
+ CLog.d("Running a command: %s", cmd);
+ device.executeShellCommand(cmd);
+ }
+ if (validateCmdSuccess(device, validation_cmd, predicate)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Helper method to retry a given cmd.
+ *
+ * @param device testing device.
+ * @param cmd the command string to be executed on device.
+ * @param validation_cmd the validation command string to be executed on device.
+ * @param predicate function that checks the exit condition.
+ * @return true if the exit condition is satisfied, false otherwise.
+ * @throws DeviceNotAvailableException
+ */
+ public boolean retry(ITestDevice device, String cmd, String validation_cmd,
+ Predicate<String> predicate) throws DeviceNotAvailableException {
+ return retry(device, cmd, validation_cmd, predicate, MAX_RETRY_COUNT);
+ }
+
+ /**
+ * Helper method to retry a given cmd.
+ *
+ * @param device testing device.
+ * @param cmd the command string to be executed on device.
+ * @param validation_cmd the validation command string to be executed on device.
+ * @param predicate function that checks the exit condition.
+ * @param retry_count the max number of times to try
+ * @return true if the exit condition is satisfied, false otherwise.
+ * @throws DeviceNotAvailableException
+ */
+ public boolean retry(ITestDevice device, String cmd, String validation_cmd,
+ Predicate<String> predicate, int retry_count) throws DeviceNotAvailableException {
+ for (int count = 0; count < retry_count; count++) {
+ CLog.d("Running a command: %s", cmd);
+ device.executeShellCommand(cmd);
+ if (validateCmdSuccess(device, validation_cmd, predicate)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Validates the device status and waits if the validation fails.
+ *
+ * @param device testing device.
+ * @param cmd the command string to be executed on device.
+ * @param predicate function that checks the exit condition.
+ * @return true if the exit condition is satisfied, false otherwise.
+ * @throws DeviceNotAvailableException
+ */
+ protected boolean validateCmdSuccess(ITestDevice device, String cmd,
+ Predicate<String> predicate) throws DeviceNotAvailableException {
+ if (cmd == null) {
+ CLog.w("validateCmdSuccess() called but cmd is null");
+ return false;
+ }
+ String out = device.executeShellCommand(cmd);
+ CLog.d("validating cmd output: %s", out);
+ if (out != null && predicate.test(out)) {
+ CLog.d("Exit condition satisfied.");
+ return true;
+ } else {
+ CLog.d("Exit condition not satisfied. Waiting for %s more seconds.",
+ DELAY_BETWEEN_RETRY_IN_SECS);
+ try {
+ if (mSleeper != null) {
+ mSleeper.sleep(DELAY_BETWEEN_RETRY_IN_SECS);
+ } else {
+ TimeUnit.SECONDS.sleep(DELAY_BETWEEN_RETRY_IN_SECS);
+ }
+ } catch (InterruptedException ex) {
+ /* pass */
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Restarts the Andriod framework and waits for the device boot completion.
+ *
+ * @param device the test device instance.
+ * @throws DeviceNotAvailableException
+ */
+ public void restartFramework(ITestDevice device) throws DeviceNotAvailableException {
+ device.executeShellCommand("stop");
+ setSystemProperty(device, BOOTCOMPLETE_PROP, "0");
+ device.executeShellCommand("start");
+ device.waitForDeviceAvailable(FRAMEWORK_START_TIMEOUT);
+ }
+
+ /**
+ * Gets a sysprop from the device.
+ *
+ * @param device the test device instance.
+ * @param name the name of a sysprop.
+ * @return the device sysprop value.
+ * @throws DeviceNotAvailableException
+ */
+ public String getSystemProperty(ITestDevice device, String name)
+ throws DeviceNotAvailableException {
+ CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ device.executeShellCommand(String.format("getprop %s", name), receiver);
+ return receiver.getOutput();
+ }
+
+ /**
+ * Sets a sysprop on the device.
+ *
+ * @param device the test device instance.
+ * @param name the name of a sysprop.
+ * @param value the value of a sysprop.
+ * @throws DeviceNotAvailableException
+ */
+ public void setSystemProperty(ITestDevice device, String name, String value)
+ throws DeviceNotAvailableException {
+ device.executeShellCommand(String.format("setprop %s %s", name, value));
+ }
+
+ @VisibleForTesting
+ void setSleeper(ISleeper sleeper) {
+ mSleeper = sleeper;
+ }
+}
diff --git a/harnesses/tradefed/src/com/android/tradefed/util/EnvUtil.java b/harnesses/tradefed/src/com/android/tradefed/util/EnvUtil.java
new file mode 100644
index 0000000..03c1b4b
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/tradefed/util/EnvUtil.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.tradefed.util;
+
+/**
+ * Utility class to deal with system environment
+ */
+public class EnvUtil {
+ static final String OS_NAME = "os.name";
+ static final String WINDOWS = "Windows"; // Not officially supported OS.
+
+ /**
+ * This method returns whether the OS is Windows.
+ */
+ public static boolean isOnWindows() {
+ return System.getProperty(OS_NAME).contains(WINDOWS);
+ }
+}
diff --git a/harnesses/tradefed/src/com/android/tradefed/util/JsonUtil.java b/harnesses/tradefed/src/com/android/tradefed/util/JsonUtil.java
index 5373965..77ef13f 100644
--- a/harnesses/tradefed/src/com/android/tradefed/util/JsonUtil.java
+++ b/harnesses/tradefed/src/com/android/tradefed/util/JsonUtil.java
@@ -45,7 +45,7 @@
try {
target_value = target.get(key);
} catch (JSONException e) {
- CLog.i("Merging Json key '%s' into target object.", key);
+ CLog.d("Merging Json key '%s' into target object.", key);
target.put(key, source_value);
continue;
}
diff --git a/harnesses/tradefed/src/com/android/tradefed/util/OutputUtil.java b/harnesses/tradefed/src/com/android/tradefed/util/OutputUtil.java
new file mode 100644
index 0000000..9d463c1
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/tradefed/util/OutputUtil.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.tradefed.util;
+
+import com.android.tradefed.log.ITestLogger;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.FileInputStreamSource;
+import com.android.tradefed.result.LogDataType;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Utility class to add output file to TradeFed log directory.
+ */
+public class OutputUtil {
+ // Test logger object from test invocation
+ ITestLogger mListener;
+ private String mTestModuleName = null;
+ private String mAbiName = null;
+
+ // Python output file patterns to be included in results
+ static private String[] PYTHON_OUTPUT_PATTERNS = new String[] {"test_run_details.*\\.txt",
+ "vts_agent_.*\\.log", "systrace_.*\\.html", "logcat.*\\.txt", "bugreport.*\\.zip"};
+ // Python folder pattern in which any files will be included in results
+ static private String PYTHON_OUTPUT_ADDITIONAL = ".*additional_output_files";
+
+ public OutputUtil(ITestLogger listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Add a text file to log directory.
+ * @param outputFileName output file base name.
+ * The actual output name will contain a hash postfix.
+ * @param source text file source
+ */
+ public void addOutputFromTextFile(String outputFileName, File source) {
+ FileInputStreamSource inputSource = new FileInputStreamSource(source);
+ mListener.testLog(outputFileName, LogDataType.TEXT, inputSource);
+ }
+
+ /**
+ * Collect all VTS python runner log output files
+ * @param logDirectory
+ */
+ public void collectVtsRunnerOutputs(File logDirectory) {
+ // First, collect known patterns.
+ for (String pattern : PYTHON_OUTPUT_PATTERNS) {
+ try {
+ FileUtil.findFiles(logDirectory, pattern)
+ .forEach(path -> addVtsRunnerOutputFile(new File(path)));
+ } catch (IOException e) {
+ CLog.e("Error reading log directory: %s", logDirectory);
+ CLog.e(e);
+ }
+ }
+
+ // Next, collect any additional files produced by tests.
+ try {
+ for (String path : FileUtil.findFiles(logDirectory, PYTHON_OUTPUT_ADDITIONAL)) {
+ for (File f : new File(path).listFiles()) {
+ addVtsRunnerOutputFile(f);
+ }
+
+ // Only use the first result, if many were found.
+ break;
+ }
+ } catch (IOException e) {
+ CLog.e("Error reading log directory: %s", logDirectory);
+ CLog.e(e);
+ }
+ }
+
+ /**
+ *
+ * @param logFile
+ */
+ private void addVtsRunnerOutputFile(File logFile) {
+ String fileName = logFile.getName();
+
+ LogDataType type;
+ if (fileName.endsWith(".html")) {
+ type = LogDataType.HTML;
+ } else if (fileName.startsWith("logcat")) {
+ type = LogDataType.LOGCAT;
+ } else if (fileName.startsWith("bugreport") && fileName.endsWith(".zip")) {
+ type = LogDataType.BUGREPORTZ;
+ } else if (fileName.endsWith(".txt") || fileName.endsWith(".log")) {
+ type = LogDataType.TEXT;
+ } else if (fileName.endsWith(".zip")) {
+ type = LogDataType.ZIP;
+ } else {
+ CLog.w("Unknown output file type. Skipping %s", logFile);
+ return;
+ }
+
+ String outputFileName = mTestModuleName + "_" + fileName + "_" + mAbiName;
+ FileInputStreamSource inputSource = new FileInputStreamSource(logFile);
+ mListener.testLog(outputFileName, type, inputSource);
+ }
+
+ /**
+ * @param testModuleName
+ */
+ public void setTestModuleName(String testModuleName) {
+ mTestModuleName = testModuleName;
+ }
+
+ /**
+ * @param bitness
+ */
+ public void setAbiName(String abiName) {
+ mAbiName = abiName;
+ }
+}
\ No newline at end of file
diff --git a/harnesses/tradefed/src/com/android/tradefed/util/ProcessHelper.java b/harnesses/tradefed/src/com/android/tradefed/util/ProcessHelper.java
index 13ea165..5df6279 100644
--- a/harnesses/tradefed/src/com/android/tradefed/util/ProcessHelper.java
+++ b/harnesses/tradefed/src/com/android/tradefed/util/ProcessHelper.java
@@ -17,10 +17,6 @@
package com.android.tradefed.util;
import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.util.CommandStatus;
-import com.android.tradefed.util.IRunUtil;
-import com.android.tradefed.util.RunInterruptedException;
-import com.android.tradefed.util.RunUtil;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -65,15 +61,24 @@
private Reader mReader;
private StringBuilder mBuffer;
+ static enum LogType {
+ STDOUT,
+ STDERR;
+ }
+
+ private LogType mLogType;
+
/**
* @param reader the input stream to read from.
* @param buffer the buffer containing the input data.
* @param name the name of the thread.
+ * @param logType enum, type of log output.
*/
- public ReaderThread(Reader reader, StringBuilder buffer, String name) {
+ public ReaderThread(Reader reader, StringBuilder buffer, String name, LogType logType) {
+ super(name);
mReader = reader;
mBuffer = buffer;
- setName(name);
+ mLogType = logType;
}
/**
@@ -89,10 +94,29 @@
if (readCount < 0) {
break;
}
- mBuffer.append(charBuffer, 0, readCount);
+ String newRead = new String(charBuffer, 0, readCount);
+
+ int newLineLen = 0;
+ if (newRead.endsWith("\r\n")) {
+ newLineLen = 2;
+ } else if (newRead.endsWith("\n")) {
+ newLineLen = 1;
+ }
+
+ String newReadPrint = newRead.substring(0, newRead.length() - newLineLen);
+ switch (mLogType) {
+ case STDOUT:
+ CLog.i(newReadPrint);
+ break;
+ case STDERR:
+ CLog.e(newReadPrint);
+ break;
+ }
+ mBuffer.append(newRead);
}
} catch (IOException e) {
- CLog.e("%s: %s", getName(), e.toString());
+ CLog.e("IOException during ProcessHelper#ReaderThread run.");
+ CLog.e(e);
}
}
}
@@ -115,17 +139,17 @@
synchronized (mLock) {
mExecutionThread = Thread.currentThread();
if (mCancelled) {
- CLog.i("Process was cancelled before being awaited.");
+ CLog.w("Process was cancelled before being awaited.");
return false;
}
}
boolean success;
try {
success = (mProcess.waitFor() == 0);
- CLog.i("Process terminates normally.");
+ CLog.d("Process terminates normally.");
} catch (InterruptedException e) {
success = false;
- CLog.i("Process is interrupted.");
+ CLog.e("Process is interrupted.");
}
return success;
}
@@ -137,17 +161,17 @@
*/
@Override
public void cancel() {
- CLog.i("Attempt to interrupt execution thread.");
+ CLog.w("Attempt to interrupt execution thread.");
synchronized (mLock) {
if (!mCancelled) {
mCancelled = true;
if (mExecutionThread != null) {
mExecutionThread.interrupt();
} else {
- CLog.i("Execution thread has not started.");
+ CLog.d("Execution thread has not started.");
}
} else {
- CLog.i("Execution thread has been cancelled.");
+ CLog.e("Execution thread has been cancelled.");
}
}
}
@@ -174,8 +198,10 @@
mStdinWriter = new OutputStreamWriter(mProcess.getOutputStream());
mStdoutReader = new InputStreamReader(mProcess.getInputStream());
mStderrReader = new InputStreamReader(mProcess.getErrorStream());
- mStdoutThread = new ReaderThread(mStdoutReader, mStdout, "process-helper-stdout");
- mStderrThread = new ReaderThread(mStderrReader, mStderr, "process-helper-stderr");
+ mStdoutThread = new ReaderThread(
+ mStdoutReader, mStdout, "process-helper-stdout", ReaderThread.LogType.STDOUT);
+ mStderrThread = new ReaderThread(
+ mStderrReader, mStderr, "process-helper-stderr", ReaderThread.LogType.STDERR);
mStdoutThread.start();
mStderrThread.start();
}
@@ -191,9 +217,10 @@
*/
public CommandStatus waitForProcess(long timeoutMsecs) throws RunInterruptedException {
VtsRunnable vtsRunnable = new VtsRunnable();
+ CommandStatus status;
// Use default RunUtil because it can receive the notification of "invocation stop".
try {
- return RunUtil.getDefault().runTimed(timeoutMsecs, vtsRunnable, true);
+ status = RunUtil.getDefault().runTimed(timeoutMsecs, vtsRunnable, true);
} catch (RunInterruptedException e) {
// clear the flag set by default RunUtil.
Thread.interrupted();
@@ -205,6 +232,14 @@
}
throw e;
}
+ if (CommandStatus.SUCCESS.equals(status) || CommandStatus.FAILED.equals(status)) {
+ // Join the receiver threads otherwise output might not be available yet.
+ joinThread(mStdoutThread, THREAD_JOIN_TIMEOUT_MSECS);
+ joinThread(mStderrThread, THREAD_JOIN_TIMEOUT_MSECS);
+ } else {
+ CLog.w("Process status is %s", status);
+ }
+ return status;
}
/**
@@ -228,16 +263,18 @@
}
/**
- * @return the stdout of the process. As the buffer is not thread safe, this method should be
- * called after {@link #cleanUp()}.
+ * @return the stdout of the process. As the buffer is not thread safe, the caller must call
+ * {@link #cleanUp()} or {@link #waitForProcess(long)} to ensure process termination before
+ * calling this method.
*/
public String getStdout() {
return mStdout.toString();
}
/**
- * @return the stderr of the process. As the buffer is not thread safe, this method should be
- * called after {@link #cleanUp()}.
+ * @return the stderr of the process. As the buffer is not thread safe, the caller must call
+ * {@link #cleanUp()} or {@link #waitForProcess(long)} to ensure process termination before
+ * calling this method.
*/
public String getStderr() {
return mStderr.toString();
diff --git a/harnesses/tradefed/src/com/android/tradefed/util/VtsDashboardUtil.java b/harnesses/tradefed/src/com/android/tradefed/util/VtsDashboardUtil.java
index c6b3c79..ab02739 100644
--- a/harnesses/tradefed/src/com/android/tradefed/util/VtsDashboardUtil.java
+++ b/harnesses/tradefed/src/com/android/tradefed/util/VtsDashboardUtil.java
@@ -23,10 +23,13 @@
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.LinkedList;
import java.util.NoSuchElementException;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
@@ -119,10 +122,16 @@
String commandTemplate =
mConfigReader.GetVendorConfigVariable("dashboard_post_command");
commandTemplate = commandTemplate.replace("{path}", messageFilePath);
+ // removes ', while keeping any substrings quoted by "".
commandTemplate = commandTemplate.replace("'", "");
- CLog.i(String.format("Upload command: %s", commandTemplate));
- CommandResult c =
- mRunUtil.runTimedCmd(BASE_TIMEOUT_MSECS * 3, commandTemplate.split(" "));
+ CLog.d(String.format("Upload command: %s", commandTemplate));
+ List<String> commandList = new ArrayList<String>();
+ Matcher matcher = Pattern.compile("([^\"]\\S*|\".+?\")\\s*").matcher(commandTemplate);
+ while (matcher.find()) {
+ commandList.add(matcher.group(1));
+ }
+ CommandResult c = mRunUtil.runTimedCmd(BASE_TIMEOUT_MSECS * 3,
+ (String[]) commandList.toArray(new String[commandList.size()]));
if (c == null || c.getStatus() != CommandStatus.SUCCESS) {
CLog.e("Uploading the test plan execution result to GAE DB faiied.");
CLog.e("Stdout: %s", c.getStdout());
diff --git a/harnesses/tradefed/src/com/android/tradefed/util/VtsFileUtil.java b/harnesses/tradefed/src/com/android/tradefed/util/VtsFileUtil.java
new file mode 100644
index 0000000..0ae05b0
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/tradefed/util/VtsFileUtil.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package com.android.tradefed.util;
+
+import com.android.tradefed.log.LogUtil.CLog;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Paths;
+
+public class VtsFileUtil extends FileUtil {
+ /**
+ * Replacing characters in a string to make it a valid file name.
+ *
+ * The current method is to replace any non-word character with '_' except '.' and '-'.
+ *
+ * @param filename the potential name of a file to normalize.
+ * Do not use path here as path delimitor will be replaced
+ * @return normalized file name
+ */
+ public static String normalizeFileName(String filename) {
+ return filename.replaceAll("[^\\w.-]", "_");
+ }
+
+ /**
+ * Save a resource file to a directory.
+ *
+ * TODO(yuexima): This method is to be removed when it becomes available in FileUtil.
+ *
+ * @param resourceStream a {link InputStream} object to the resource to be saved.
+ * @param destDir a {@link File} object of a directory to where the resource file will be saved.
+ * @param targetFileName a {@link String} for the name of the file to be saved to.
+ * @return a {@link File} object of the file saved.
+ * @throws IOException if the file failed to be saved.
+ */
+ public static File saveResourceFile(
+ InputStream resourceStream, File destDir, String targetFileName) throws IOException {
+ FileWriter writer = null;
+ File file = Paths.get(destDir.getAbsolutePath(), targetFileName).toFile();
+ try {
+ writer = new FileWriter(file);
+ StreamUtil.copyStreamToWriter(resourceStream, writer);
+ return file;
+ } catch (IOException e) {
+ CLog.e("IOException while saving resource %s/%s", destDir, targetFileName);
+ deleteFile(file);
+ throw e;
+ } finally {
+ if (writer != null) {
+ writer.close();
+ }
+ if (resourceStream != null) {
+ resourceStream.close();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/harnesses/tradefed/src/com/android/tradefed/util/VtsPythonRunnerHelper.java b/harnesses/tradefed/src/com/android/tradefed/util/VtsPythonRunnerHelper.java
new file mode 100644
index 0000000..4f05a7a
--- /dev/null
+++ b/harnesses/tradefed/src/com/android/tradefed/util/VtsPythonRunnerHelper.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.tradefed.util;
+
+import com.android.compatibility.common.tradefed.build.VtsCompatibilityInvocationHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.EnvUtil;
+import com.android.tradefed.util.IRunUtil;
+import com.android.tradefed.util.ProcessHelper;
+import com.android.tradefed.util.RunInterruptedException;
+import com.android.tradefed.util.RunUtil;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * A helper class for executing VTS python scripts.
+ */
+public class VtsPythonRunnerHelper {
+ static final String PATH = "PATH";
+ static final String PYTHONHOME = "PYTHONHOME";
+ static final String VTS = "vts";
+ static final long TEST_ABORT_TIMEOUT_MSECS = 1000 * 15;
+
+ // Python virtual environment root path
+ private File mVirtualenvPath;
+ protected IRunUtil mRunUtil;
+
+ public VtsPythonRunnerHelper(IBuildInfo buildInfo) {
+ this(buildInfo.getFile(VtsPythonVirtualenvPreparer.VIRTUAL_ENV));
+ }
+
+ public VtsPythonRunnerHelper(File virtualEnvPath) {
+ mVirtualenvPath = virtualEnvPath;
+ mRunUtil = new RunUtil();
+ activateVirtualenv(mRunUtil, getPythonVirtualEnv());
+ VtsCompatibilityInvocationHelper invocationHelper = new VtsCompatibilityInvocationHelper();
+ try {
+ mRunUtil.setWorkingDir(invocationHelper.getTestsDir());
+ } catch (FileNotFoundException e) {
+ CLog.e("VtsCompatibilityInvocationHelper cannot find test case directory. "
+ + "Command working directory not set.");
+ }
+ }
+
+ /**
+ * Create a {@link ProcessHelper} from mRunUtil.
+ *
+ * @param cmd the command to run.
+ * @throws IOException if fails to start Process.
+ */
+ protected ProcessHelper createProcessHelper(String[] cmd) throws IOException {
+ return new ProcessHelper(mRunUtil.runCmdInBackground(cmd));
+ }
+
+ /**
+ * Run VTS Python runner and handle interrupt from TradeFed.
+ *
+ * @param cmd the command to start VTS Python runner.
+ * @param commandResult the object containing the command result.
+ * @param timeout command timeout value.
+ * @return null if the command terminates or times out; a message string if the command is
+ * interrupted by TradeFed.
+ */
+ public String runPythonRunner(String[] cmd, CommandResult commandResult, long timeout) {
+ ProcessHelper process;
+ try {
+ process = createProcessHelper(cmd);
+ } catch (IOException e) {
+ CLog.e(e);
+ commandResult.setStatus(CommandStatus.EXCEPTION);
+ commandResult.setStdout("");
+ commandResult.setStderr("");
+ return null;
+ }
+
+ String interruptMessage;
+ try {
+ CommandStatus commandStatus;
+ try {
+ commandStatus = process.waitForProcess(timeout);
+ interruptMessage = null;
+ } catch (RunInterruptedException e) {
+ CLog.e("Python process is interrupted.");
+ commandStatus = CommandStatus.TIMED_OUT;
+ interruptMessage = (e.getMessage() != null ? e.getMessage() : "");
+ }
+ if (process.isRunning()) {
+ CLog.e("Cancel Python process and wait %d seconds.",
+ TEST_ABORT_TIMEOUT_MSECS / 1000);
+ try {
+ process.closeStdin();
+ // Wait for the process to clean up and ignore the CommandStatus.
+ // Propagate RunInterruptedException if this is interrupted again.
+ process.waitForProcess(TEST_ABORT_TIMEOUT_MSECS);
+ } catch (IOException e) {
+ CLog.e("Fail to cancel Python process.");
+ }
+ }
+ commandResult.setStatus(commandStatus);
+ } finally {
+ process.cleanUp();
+ }
+ commandResult.setStdout(process.getStdout());
+ commandResult.setStderr(process.getStderr());
+ return interruptMessage;
+ }
+
+ /**
+ * Gets python bin directory path.
+ *
+ * This method will check the directory existence.
+ *
+ * @return python bin directory; null if not exist.
+ */
+ public static String getPythonBinDir(String virtualenvPath) {
+ if (virtualenvPath == null) {
+ return null;
+ }
+ String binDirName = EnvUtil.isOnWindows() ? "Scripts" : "bin";
+ File res = new File(virtualenvPath, binDirName);
+ if (!res.exists()) {
+ return null;
+ }
+ return res.getAbsolutePath();
+ }
+
+ /**
+ * Get python virtualenv path
+ * @return virutalenv path. null if doesn't exist
+ */
+ public String getPythonVirtualEnv() {
+ if (mVirtualenvPath == null) {
+ return null;
+ }
+ return mVirtualenvPath.getAbsolutePath();
+ }
+
+ /**
+ * Activate virtualenv for a RunUtil.
+ *
+ * This method will check for python bin directory existence
+ *
+ * @param runUtil
+ * @param virtualenvPath
+ */
+ public static void activateVirtualenv(IRunUtil runUtil, String virtualenvPath) {
+ String pythonBinDir = getPythonBinDir(virtualenvPath);
+ if (pythonBinDir == null || !new File(pythonBinDir).exists()) {
+ CLog.e("Invalid python virtualenv path. Using python from system path.");
+ } else {
+ String separater = EnvUtil.isOnWindows() ? ";" : ":";
+ runUtil.setEnvVariable(PATH, pythonBinDir + separater + System.getenv().get(PATH));
+ runUtil.setEnvVariable(VtsPythonVirtualenvPreparer.VIRTUAL_ENV, virtualenvPath);
+ runUtil.unsetEnvVariable(PYTHONHOME);
+ }
+ }
+}
diff --git a/harnesses/tradefed/src/com/android/tradefed/util/VtsVendorConfigFileUtil.java b/harnesses/tradefed/src/com/android/tradefed/util/VtsVendorConfigFileUtil.java
index 788baa6..6495fd2 100644
--- a/harnesses/tradefed/src/com/android/tradefed/util/VtsVendorConfigFileUtil.java
+++ b/harnesses/tradefed/src/com/android/tradefed/util/VtsVendorConfigFileUtil.java
@@ -73,10 +73,10 @@
if (configPath == null || configPath.length() == 0) {
configPath = GetVendorConfigFilePath();
}
- CLog.i("Loading vendor test config %s", configPath);
+ CLog.d("Loading vendor test config %s", configPath);
InputStream config = getClass().getResourceAsStream(configPath);
if (config == null) {
- CLog.e("Vendor test config file %s does not exist", configPath);
+ CLog.d("Vendor test config file %s does not exist", configPath);
return false;
}
try {
@@ -85,7 +85,7 @@
CLog.e("Loaded vendor test config is empty");
return false;
}
- CLog.i("Loaded vendor test config %s", content);
+ CLog.d("Loaded vendor test config %s", content);
vendorConfigJson = new JSONObject(content);
} catch (IOException e) {
throw new RuntimeException("Failed to read vendor config json file");
@@ -121,7 +121,7 @@
if (attrs.containsKey(KEY_VENDOR_TEST_CONFIG_DEFAULT_TYPE)) {
mDefaultType = attrs.get(KEY_VENDOR_TEST_CONFIG_DEFAULT_TYPE);
} else {
- CLog.i("No default vendor test configuration provided. Defaulting to prod.");
+ CLog.d("No default vendor test configuration provided. Defaulting to prod.");
}
mVendorConfigFilePath = attrs.get(KEY_VENDOR_TEST_CONFIG_FILE_PATH);
return LoadVendorConfig(mDefaultType, mVendorConfigFilePath);
diff --git a/harnesses/tradefed/tests/Android.mk b/harnesses/tradefed/tests/Android.mk
index f0dc12a..41c6dc5 100644
--- a/harnesses/tradefed/tests/Android.mk
+++ b/harnesses/tradefed/tests/Android.mk
@@ -20,8 +20,9 @@
LOCAL_MODULE := vts-tradefed-tests
LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES := easymock
+LOCAL_STATIC_JAVA_LIBRARIES := easymock mockito-host
LOCAL_JAVA_LIBRARIES := tradefed vts-tradefed
+LOCAL_JAVA_RESOURCE_DIRS := res
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/harnesses/tradefed/tests/res/util/results/2017.09.01_17.30.00/test_result.xml b/harnesses/tradefed/tests/res/util/results/2017.09.01_17.30.00/test_result.xml
new file mode 100644
index 0000000..31203b2
--- /dev/null
+++ b/harnesses/tradefed/tests/res/util/results/2017.09.01_17.30.00/test_result.xml
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='UTF-8' standalone='no' ?><?xml-stylesheet type="text/xsl" href="vts_result.xsl"?>
+<Result start="1504258200493" end="1504258240603" start_display="Fri Sep 01 17:30:00 CST 2017" end_display="Fri Sep 01 17:30:40 CST 2017" suite_name="VTS" suite_version="8.0" suite_plan="vts" suite_build_number="test123456" report_version="5.0" command_line_args="vts -m SampleShellTest -a arm64-v8a" devices="TEST123456" host_name="unit.test.google.com" os_name="Linux" os_version="4.4.0-92-generic" os_arch="amd64" java_vendor="JetBrains s.r.o" java_version="1.8.0_152-android">
+ <Build build_abis_64="arm64-v8a" build_manufacturer="unknown" build_abis_32="armeabi-v7a,armeabi" build_product="aosp_arm64_ab" build_brand="Android" build_board="sailfish" build_serial="TEST123456" build_version_security_patch="2017-10-05" build_system_fingerprint="Android/aosp_arm64_ab/generic_arm64_ab:8.0.0/OC/4311089:userdebug/test-keys" build_reference_fingerprint="null" build_fingerprint="Android/aosp_sailfish/sailfish:8.0.0/OC/4311111:userdebug/test-keys" build_version_sdk="26" build_abis="arm64-v8a,armeabi-v7a,armeabi" build_device="generic_arm64_ab" build_abi="arm64-v8a" build_model="AOSP on ARM64" build_id="OC" build_abi2="null" build_vendor_fingerprint="Android/aosp_sailfish/sailfish:8.0.0/OC/4311111:userdebug/test-keys" build_version_release="8.0.0" build_version_base_os="" build_type="userdebug" build_tags="test-keys" />
+ <Summary pass="7" failed="0" modules_done="1" modules_total="1" />
+ <Module name="SampleShellTest" abi="arm64-v8a" runtime="21450" done="true" pass="7">
+ <TestCase name="SampleShellTest">
+ <Test result="pass" name="testCommandList" />
+ <Test result="pass" name="testCommandSequenceCd" />
+ <Test result="pass" name="testCommandSequenceExport" />
+ <Test result="pass" name="testCommandSequenceMktemp" />
+ <Test result="pass" name="testMultipleCommands" />
+ <Test result="pass" name="testMultipleShells" />
+ <Test result="pass" name="testOneCommand" />
+ </TestCase>
+ </Module>
+</Result>
diff --git a/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/VtsUnitTests.java b/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/VtsUnitTests.java
new file mode 100644
index 0000000..1c98e6f
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/VtsUnitTests.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package com.android.compatibility.common.tradefed;
+
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTestMultiDeviceTest;
+import com.android.compatibility.common.tradefed.testtype.ModuleDefMultiDeviceTest;
+import com.android.compatibility.common.tradefed.util.VtsRetryFilterHelperTest;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+/**
+ * A test suite for all VTS Tradefed unit tests.
+ *
+ * <p>All tests listed here should be self-contained, and do not require any external dependencies.
+ */
+@RunWith(Suite.class)
+@SuiteClasses({
+ // NOTE: please keep classes sorted lexicographically in each group
+ // testtype
+ CompatibilityTestMultiDeviceTest.class,
+ ModuleDefMultiDeviceTest.class,
+
+ // util
+ VtsRetryFilterHelperTest.class,
+})
+public class VtsUnitTests {
+ // empty on purpose
+}
diff --git a/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestMultiDeviceTest.java b/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestMultiDeviceTest.java
new file mode 100644
index 0000000..0c426e5
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTestMultiDeviceTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.testtype.VtsMultiDeviceTest;
+import com.android.tradefed.testtype.IAbi;
+
+import java.io.FileNotFoundException;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.HashMap;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link CompatibilityTestMultiDevice}.
+ */
+@RunWith(JUnit4.class)
+public class CompatibilityTestMultiDeviceTest {
+ CompatibilityTestMultiDevice mTest = null;
+ private ITestDevice mMockDevice;
+ private ModuleDefMultiDevice moduleDef;
+ Map<ITestDevice, IBuildInfo> deviceInfos;
+ IInvocationContext invocationContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mMockDevice = EasyMock.createMock(ITestDevice.class);
+ IAbi abi = EasyMock.createMock(IAbi.class);
+ EasyMock.expect(abi.getName()).andReturn("FAKE_ABI");
+ moduleDef = new ModuleDefMultiDevice("FAKE_MODULE", abi, new VtsMultiDeviceTest(),
+ new ArrayList<>(), new ArrayList<>(), null);
+ deviceInfos = new HashMap<>();
+ invocationContext = EasyMock.createMock(IInvocationContext.class);
+
+ mTest = new CompatibilityTestMultiDevice(1, new ModuleRepoMultiDevice() {
+ @Override
+ public boolean isInitialized() {
+ return true;
+ }
+ @Override
+ public LinkedList<IModuleDef> getModules(String serial, int shardIndex) {
+ LinkedList<IModuleDef> modules = new LinkedList<>();
+ modules.add(moduleDef);
+ return modules;
+ }
+ }, 0);
+ mTest.setDevice(mMockDevice);
+ mTest.setDeviceInfos(deviceInfos);
+ mTest.setInvocationContext(invocationContext);
+ }
+
+ /**
+ * Test the initializeModuleRepo method.
+ * @throws DeviceNotAvailableException
+ * @throws FileNotFoundException
+ */
+ @Test
+ public void testInitializeModuleRepo()
+ throws FileNotFoundException, DeviceNotAvailableException {
+ mTest.initializeModuleRepo();
+ assertEquals(deviceInfos, moduleDef.getDeviceInfos());
+ assertEquals(invocationContext, moduleDef.getInvocationContext());
+ }
+}
diff --git a/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefMultiDeviceTest.java b/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefMultiDeviceTest.java
new file mode 100644
index 0000000..2022f64
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefMultiDeviceTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.targetprep.multi.IMultiTargetPreparer;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.VtsMultiDeviceTest;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link ModuleDefMultiDeviceTest}.
+ */
+@RunWith(JUnit4.class)
+public class ModuleDefMultiDeviceTest {
+ private ITestDevice mMockDevice;
+ private IBuildInfo mBuildInfo;
+ private ModuleDefMultiDevice mTest;
+ private Map<ITestDevice, IBuildInfo> mDeviceInfos;
+ private IInvocationContext mInvocationContext;
+ private IMultiTargetPreparer mMultiTargetPreparer;
+ private VtsMultiDeviceTest mVtsMultiDeviceTest;
+
+ @Before
+ public void setUp() throws Exception {
+ mMockDevice = EasyMock.createMock(ITestDevice.class);
+ mBuildInfo = EasyMock.createMock(IBuildInfo.class);
+ IAbi mAbi = EasyMock.createMock(IAbi.class);
+ EasyMock.expect(mAbi.getName()).andReturn("FAKE_ABI");
+ mMultiTargetPreparer = EasyMock.createMock(IMultiTargetPreparer.class);
+
+ List<IMultiTargetPreparer> preparers = new ArrayList<>();
+ preparers.add(mMultiTargetPreparer);
+ mVtsMultiDeviceTest = new VtsMultiDeviceTest();
+ mTest = new ModuleDefMultiDevice(
+ "FAKE_MODULE", mAbi, mVtsMultiDeviceTest, new ArrayList<>(), preparers, null);
+ mDeviceInfos = new HashMap<>();
+ mInvocationContext = EasyMock.createMock(IInvocationContext.class);
+ ArrayList<ITestDevice> devices = new ArrayList<>();
+ devices.add(mMockDevice);
+ ArrayList<IBuildInfo> buildInfos = new ArrayList<>();
+ buildInfos.add(mBuildInfo);
+ EasyMock.expect(mInvocationContext.getDevices()).andReturn(devices);
+ EasyMock.expect(mInvocationContext.getBuildInfos()).andReturn(buildInfos);
+ EasyMock.replay(mInvocationContext);
+
+ mTest.setDeviceInfos(mDeviceInfos);
+ mTest.setInvocationContext(mInvocationContext);
+ }
+
+ /**
+ * Test the testRunPreparerSetUp method.
+ * @throws BuildError
+ * @throws TargetSetupError
+ * @throws DeviceNotAvailableException
+ */
+ @Test
+ public void testRunPreparerSetups()
+ throws TargetSetupError, BuildError, DeviceNotAvailableException {
+ mMultiTargetPreparer.setUp(mInvocationContext);
+ EasyMock.expectLastCall();
+ EasyMock.replay(mMultiTargetPreparer);
+ mTest.runPreparerSetups();
+ EasyMock.verify(mMultiTargetPreparer);
+ }
+
+ /**
+ * Test the prepareTestClass method.
+ */
+ @Test
+ public void testPrepareTestClass() {
+ mTest.prepareTestClass();
+ assertEquals(mVtsMultiDeviceTest.getInvocationContext(), mInvocationContext);
+ }
+}
diff --git a/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/util/VtsRetryFilterHelperTest.java b/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/util/VtsRetryFilterHelperTest.java
new file mode 100644
index 0000000..2fc5a11
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/compatibility/common/tradefed/util/VtsRetryFilterHelperTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.compatibility.common.tradefed.util;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.util.VtsFileUtil;
+
+import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.util.HashSet;
+
+/**
+ * Unit tests for {@link VtsRetryFilterHelper}.
+ */
+@RunWith(JUnit4.class)
+public class VtsRetryFilterHelperTest {
+ private final String RESULTS_FILE = "/util/results/2017.09.01_17.30.00/test_result.xml";
+ private final String VENDOR_FINGERPRINT =
+ "Android/aosp_sailfish/sailfish:8.0.0/OC/4311111:userdebug/test-keys";
+ private final String WRONG_FINGERPRINT =
+ "Android/other_device/other_device:8.0.0/OC/4311112:userdebug/test-keys";
+ private final String VENDOR_FINGERPRINT_PROPERTY = "ro.vendor.build.fingerprint";
+ private CompatibilityBuildHelper mBuildHelper;
+ private RetryFilterHelper mHelper;
+
+ private File mTmpDir;
+
+ @Before
+ public void setUp() throws Exception {
+ mTmpDir = VtsFileUtil.createTempDir("vts-unit-tests");
+ File invDir = new File(mTmpDir, "2017.09.01_17.30.00");
+ invDir.mkdirs();
+ VtsFileUtil.saveResourceFile(
+ getClass().getResourceAsStream(RESULTS_FILE), invDir, "test_result.xml");
+ mBuildHelper = new CompatibilityBuildHelper(null) {
+ @Override
+ public File getResultsDir() {
+ return mTmpDir;
+ }
+ };
+ mHelper = new VtsRetryFilterHelper(mBuildHelper, 0, "SUB_PLAN", new HashSet<String>(),
+ new HashSet<String>(), "ABI_NAME", "MODULE_NAME", "TEST_NAME", RetryType.FAILED);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ VtsFileUtil.recursiveDelete(mTmpDir);
+ }
+
+ /**
+ * Create a mock {@link ITestDevice} with fingerprint properties.
+ * @param vendorFingerprint The vendor fingerprint of the device.
+ * @return The mock device.
+ * @throws DeviceNotAvailableException
+ */
+ private ITestDevice createMockDevice(String vendorFingerprint)
+ throws DeviceNotAvailableException {
+ ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
+ EasyMock.expect(mockDevice.getProperty(VENDOR_FINGERPRINT_PROPERTY))
+ .andReturn(vendorFingerprint);
+ EasyMock.replay(mockDevice);
+ return mockDevice;
+ }
+
+ /**
+ * Test ValidateBuildFingerprint without error.
+ * @throws DeviceNotAvailableException
+ */
+ @Test
+ public void testValidateBuildFingerprint() throws DeviceNotAvailableException {
+ mHelper.validateBuildFingerprint(createMockDevice(VENDOR_FINGERPRINT));
+ }
+
+ /**
+ * Test ValidateBuildFingerprint with the incorrect fingerprint.
+ * @throws DeviceNotAvailableException
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testMismatchSystemFingerprint() throws DeviceNotAvailableException {
+ mHelper.validateBuildFingerprint(createMockDevice(WRONG_FINGERPRINT));
+ }
+}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/VtsUnitTests.java b/harnesses/tradefed/tests/src/com/android/tradefed/VtsUnitTests.java
new file mode 100644
index 0000000..977f181
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/VtsUnitTests.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package com.android.tradefed;
+
+import com.android.tradefed.presubmit.VtsConfigLoadingTest;
+import com.android.tradefed.targetprep.VtsCoveragePreparerTest;
+import com.android.tradefed.targetprep.VtsHalAdapterPreparerTest;
+import com.android.tradefed.targetprep.VtsPythonVirtualenvPreparerTest;
+import com.android.tradefed.targetprep.VtsTraceCollectPreparerTest;
+import com.android.tradefed.testtype.VtsFuzzTestResultParserTest;
+import com.android.tradefed.testtype.VtsFuzzTestTest;
+import com.android.tradefed.testtype.VtsMultiDeviceTestResultParserTest;
+import com.android.tradefed.testtype.VtsMultiDeviceTestTest;
+import com.android.tradefed.util.CmdUtilTest;
+import com.android.tradefed.util.ProcessHelperTest;
+import com.android.tradefed.util.VtsPythonRunnerHelperTest;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * A test suite for all VTS Tradefed unit tests.
+ *
+ * <p>All tests listed here should be self-contained, and do not require any external dependencies.
+ */
+@RunWith(Suite.class)
+@SuiteClasses({
+ // NOTE: please keep classes sorted lexicographically in each group
+ // presubmit
+ VtsConfigLoadingTest.class,
+ // targetprep
+ VtsCoveragePreparerTest.class,
+ VtsHalAdapterPreparerTest.class,
+ VtsPythonVirtualenvPreparerTest.class,
+ VtsTraceCollectPreparerTest.class,
+
+ // testtype
+ VtsFuzzTestResultParserTest.class,
+ VtsFuzzTestTest.class,
+ VtsMultiDeviceTestResultParserTest.class,
+ VtsMultiDeviceTestTest.class,
+
+ // util
+ CmdUtilTest.class,
+ ProcessHelperTest.class,
+ VtsPythonRunnerHelperTest.class,
+})
+public class VtsUnitTests {
+ // empty on purpose
+}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/presubmit/VtsConfigLoadingTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/presubmit/VtsConfigLoadingTest.java
new file mode 100644
index 0000000..f5b2fb3
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/presubmit/VtsConfigLoadingTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package com.android.tradefed.presubmit;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.config.ConfigurationDescriptor;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.ConfigurationFactory;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.testtype.IRemoteTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Test that configuration in VTS can load and have expected properties.
+ */
+@RunWith(JUnit4.class)
+public class VtsConfigLoadingTest {
+ /**
+ * List of the officially supported runners in VTS.
+ */
+ private static final Set<String> SUPPORTED_VTS_TEST_TYPE = new HashSet<>(Arrays.asList(
+ "com.android.compatibility.common.tradefed.testtype.JarHostTest",
+ "com.android.tradefed.testtype.AndroidJUnitTest",
+ "com.android.tradefed.testtype.GTest",
+ "com.android.tradefed.testtype.VtsMultiDeviceTest"));
+
+ /**
+ * Test that configuration shipped in Tradefed can be parsed.
+ */
+ @Test
+ public void testConfigurationLoad() throws Exception {
+ String vtsRoot = System.getProperty("VTS_ROOT");
+ File testcases = new File(vtsRoot, "/android-vts/testcases/");
+ if (!testcases.exists()) {
+ fail(String.format("%s does not exists", testcases));
+ return;
+ }
+ File[] listVtsConfig = testcases.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ // Only check the VTS test config
+ if (name.startsWith("Vts") && name.endsWith(".config")) {
+ return true;
+ }
+ return false;
+ }
+ });
+ assertTrue(listVtsConfig.length > 0);
+ for (File config : listVtsConfig) {
+ IConfiguration c = ConfigurationFactory.getInstance().createConfigurationFromArgs(
+ new String[] {config.getAbsolutePath()});
+ for (IRemoteTest test : c.getTests()) {
+ // Check that all the tests runners are well supported.
+ if (!SUPPORTED_VTS_TEST_TYPE.contains(test.getClass().getCanonicalName())) {
+ throw new ConfigurationException(
+ String.format("testtype %s is not officially supported by VTS.",
+ test.getClass().getCanonicalName()));
+ }
+ }
+ }
+ }
+}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsCoveragePreparerTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsCoveragePreparerTest.java
new file mode 100644
index 0000000..5765b80
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsCoveragePreparerTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.tradefed.targetprep;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.IRunUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+/**
+ * Unit tests for {@link VtsCoveragePreparer}.
+ */
+@RunWith(JUnit4.class)
+public final class VtsCoveragePreparerTest {
+ private String BUILD_INFO_ARTIFACT = VtsCoveragePreparer.BUILD_INFO_ARTIFACT;
+ private String GCOV_PROPERTY = VtsCoveragePreparer.GCOV_PROPERTY;
+ private String GCOV_FILE_NAME = VtsCoveragePreparer.GCOV_FILE_NAME;
+ private String SYMBOLS_FILE_NAME = VtsCoveragePreparer.SYMBOLS_FILE_NAME;
+ private String COVERAGE_REPORT_PATH = VtsCoveragePreparer.COVERAGE_REPORT_PATH;
+
+ // Path to store coverage report files.
+ private static final String TEST_COVERAGE_REPORT_PATH = "/tmp/test-coverage";
+
+ private File mTestDir;
+ private CompatibilityBuildHelper mMockHelper;
+
+ private class TestCoveragePreparer extends VtsCoveragePreparer {
+ @Override
+ CompatibilityBuildHelper createBuildHelper(IBuildInfo buildInfo) {
+ return mMockHelper;
+ }
+
+ @Override
+ File createTempDir(ITestDevice device) {
+ return mTestDir;
+ }
+
+ @Override
+ String getArtifactFetcher(IBuildInfo buildInfo) {
+ return "fetcher --bid %s --target %s %s %s";
+ }
+ }
+
+ @Mock private IBuildInfo mBuildInfo;
+ @Mock private ITestDevice mDevice;
+ @Mock private IRunUtil mRunUtil;
+ @InjectMocks private TestCoveragePreparer mPreparer = new TestCoveragePreparer();
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mTestDir = FileUtil.createTempDir("vts-coverage-preparer-unit-tests");
+ mMockHelper = new CompatibilityBuildHelper(mBuildInfo) {
+ @Override
+ public File getTestsDir() throws FileNotFoundException {
+ return mTestDir;
+ }
+ public File getResultDir() throws FileNotFoundException {
+ return mTestDir;
+ }
+ };
+ doReturn("build_id").when(mDevice).getBuildId();
+ doReturn("1234").when(mDevice).getSerialNumber();
+ doReturn("enforcing").when(mDevice).executeShellCommand("getenforce");
+ doReturn("build_id").when(mBuildInfo).getBuildId();
+ CommandResult commandResult = new CommandResult();
+ commandResult.setStatus(CommandStatus.SUCCESS);
+ doReturn(commandResult).when(mRunUtil).runTimedCmd(anyLong(), any());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtil.recursiveDelete(mTestDir);
+ }
+
+ @Test
+ public void testOnSetUpCoverageDisabled() throws Exception {
+ doReturn("UnknowFlaver").when(mDevice).getBuildFlavor();
+ doReturn("None").when(mDevice).getProperty(GCOV_PROPERTY);
+
+ mPreparer.setUp(mDevice, mBuildInfo);
+ verify(mBuildInfo, never()).setFile(any(), any(), any());
+ }
+
+ @Test
+ public void testOnSetUpSancovEnabled() throws Exception {
+ doReturn("walleye_asan_coverage-userdebug").when(mDevice).getBuildFlavor();
+ createTestFile(SYMBOLS_FILE_NAME);
+ createTestFile(BUILD_INFO_ARTIFACT);
+
+ mPreparer.setUp(mDevice, mBuildInfo);
+ verify(mBuildInfo, times(1))
+ .setFile(eq(VtsCoveragePreparer.getSancovResourceDirKey(mDevice)), eq(mTestDir),
+ eq("build_id"));
+ }
+
+ @Test
+ public void testOnSetUpGcovEnabled() throws Exception {
+ doReturn("walleye_coverage-userdebug").when(mDevice).getBuildFlavor();
+ doReturn("1").when(mDevice).getProperty(GCOV_PROPERTY);
+ createTestFile(GCOV_FILE_NAME);
+ createTestFile(BUILD_INFO_ARTIFACT);
+ mPreparer.setUp(mDevice, mBuildInfo);
+ verify(mBuildInfo, times(1))
+ .setFile(eq(VtsCoveragePreparer.getGcovResourceDirKey(mDevice)), eq(mTestDir),
+ eq("build_id"));
+ }
+
+ @Test
+ public void testOnSetUpLocalArtifectsNormal() throws Exception {
+ OptionSetter setter = new OptionSetter(mPreparer);
+ setter.setOptionValue("use-local-artifects", "true");
+ setter.setOptionValue("local-coverage-resource-path", mTestDir.getAbsolutePath());
+ doReturn("1").when(mDevice).getProperty(GCOV_PROPERTY);
+ createTestFile(GCOV_FILE_NAME);
+ createTestFile(BUILD_INFO_ARTIFACT);
+
+ mPreparer.setUp(mDevice, mBuildInfo);
+ verify(mBuildInfo, times(1))
+ .setFile(eq(VtsCoveragePreparer.getGcovResourceDirKey(mDevice)), eq(mTestDir),
+ eq("build_id"));
+ }
+
+ @Test
+ public void testOnSetUpLocalArtifectsNotExists() throws Exception {
+ OptionSetter setter = new OptionSetter(mPreparer);
+ setter.setOptionValue("use-local-artifects", "true");
+ setter.setOptionValue("local-coverage-resource-path", mTestDir.getAbsolutePath());
+ doReturn("1").when(mDevice).getProperty(GCOV_PROPERTY);
+
+ try {
+ mPreparer.setUp(mDevice, mBuildInfo);
+ } catch (TargetSetupError e) {
+ // Expected.
+ assertEquals(String.format("Could not find %s under %s.", GCOV_FILE_NAME,
+ mTestDir.getAbsolutePath()),
+ e.getMessage());
+ verify(mBuildInfo, never()).setFile(any(), any(), any());
+ return;
+ }
+ fail();
+ }
+
+ @Test
+ public void testOnSetUpOutputCoverageReport() throws Exception {
+ OptionSetter setter = new OptionSetter(mPreparer);
+ setter.setOptionValue("coverage-report-dir", TEST_COVERAGE_REPORT_PATH);
+ doReturn("walleye_coverage-userdebug").when(mDevice).getBuildFlavor();
+ doReturn("1").when(mDevice).getProperty(GCOV_PROPERTY);
+ createTestFile(GCOV_FILE_NAME);
+ createTestFile(BUILD_INFO_ARTIFACT);
+
+ mPreparer.setUp(mDevice, mBuildInfo);
+ verify(mBuildInfo, times(1))
+ .addBuildAttribute(eq(COVERAGE_REPORT_PATH),
+ eq(mTestDir.getAbsolutePath() + TEST_COVERAGE_REPORT_PATH));
+ }
+
+ @Test
+ public void testOnTearDown() throws Exception {
+ doReturn("walleye_coverage-userdebug").when(mDevice).getBuildFlavor();
+ doReturn("1").when(mDevice).getProperty(GCOV_PROPERTY);
+ File artifectsFile = createTestFile(GCOV_FILE_NAME);
+ File buildInfoFile = createTestFile(BUILD_INFO_ARTIFACT);
+ mPreparer.setUp(mDevice, mBuildInfo);
+ mPreparer.tearDown(mDevice, mBuildInfo, null);
+ verify(mDevice, times(1)).executeShellCommand("setenforce enforcing");
+ assertFalse(artifectsFile.exists());
+ assertFalse(buildInfoFile.exists());
+ }
+
+ /**
+ * Helper method to create a test file under mTestDir.
+ *
+ * @param fileName test file name.
+ * @return created test file.
+ */
+ private File createTestFile(String fileName) throws IOException {
+ File testFile = new File(mTestDir, fileName);
+ testFile.createNewFile();
+ return testFile;
+ }
+}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsHalAdapterPreparerTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsHalAdapterPreparerTest.java
new file mode 100644
index 0000000..d1fc88a
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsHalAdapterPreparerTest.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.tradefed.targetprep;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.*;
+
+import com.android.compatibility.common.tradefed.build.VtsCompatibilityInvocationHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.util.CmdUtil;
+import com.android.tradefed.util.FileUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+import java.util.function.Predicate;
+/**
+ * Unit tests for {@link VtsHalAdapterPreparer}.
+ */
+@RunWith(JUnit4.class)
+public final class VtsHalAdapterPreparerTest {
+ private int THREAD_COUNT_DEFAULT = VtsHalAdapterPreparer.THREAD_COUNT_DEFAULT;
+ private String SCRIPT_PATH = VtsHalAdapterPreparer.SCRIPT_PATH;
+ private String LIST_HAL_CMD = VtsHalAdapterPreparer.LIST_HAL_CMD;
+
+ private String VTS_NATIVE_TEST_DIR = "DATA/nativetest64/";
+ private String TARGET_NATIVE_TEST_DIR = "/data/nativetest64/";
+ private String TEST_HAL_ADAPTER_BINARY = "android.hardware.foo@1.0-adapter";
+ private String TEST_HAL_PACKAGE = "android.hardware.foo@1.1";
+
+ private class TestCmdUtil extends CmdUtil {
+ public boolean mCmdSuccess = true;
+ @Override
+ public boolean waitCmdResultWithDelay(ITestDevice device, String cmd,
+ Predicate<String> predicate) throws DeviceNotAvailableException {
+ return mCmdSuccess;
+ }
+
+ @Override
+ public boolean retry(ITestDevice device, String cmd, String validation_cmd,
+ Predicate<String> predicate, int retry_count) throws DeviceNotAvailableException {
+ device.executeShellCommand(cmd);
+ return mCmdSuccess;
+ }
+
+ @Override
+ public boolean retry(ITestDevice device, Vector<String> cmds, String validation_cmd,
+ Predicate<String> predicate) throws DeviceNotAvailableException {
+ for (String cmd : cmds) {
+ device.executeShellCommand(cmd);
+ }
+ return mCmdSuccess;
+ }
+
+ @Override
+ public void restartFramework(ITestDevice device) throws DeviceNotAvailableException {}
+
+ @Override
+ public void setSystemProperty(ITestDevice device, String name, String value)
+ throws DeviceNotAvailableException {}
+ }
+ private TestCmdUtil mCmdUtil = new TestCmdUtil();
+ VtsCompatibilityInvocationHelper mMockHelper = null;
+ private class TestPreparer extends VtsHalAdapterPreparer {
+ @Override
+ VtsCompatibilityInvocationHelper createVtsHelper() {
+ return mMockHelper;
+ }
+ }
+ File mTestDir = null;
+
+ @Mock private IBuildInfo mBuildInfo;
+ @Mock private ITestDevice mDevice;
+ @Mock private IAbi mAbi;
+ @InjectMocks private TestPreparer mPreparer = new TestPreparer();
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ // Create the base dirs
+ mTestDir = FileUtil.createTempDir("vts-hal-adapter-preparer-unit-tests");
+ new File(mTestDir, VTS_NATIVE_TEST_DIR).mkdirs();
+ mMockHelper = new VtsCompatibilityInvocationHelper() {
+ @Override
+ public File getTestsDir() throws FileNotFoundException {
+ return mTestDir;
+ }
+ };
+ mPreparer.setCmdUtil(mCmdUtil);
+ OptionSetter setter = new OptionSetter(mPreparer);
+ setter.setOptionValue("adapter-binary-name", TEST_HAL_ADAPTER_BINARY);
+ setter.setOptionValue("hal-package-name", TEST_HAL_PACKAGE);
+ doReturn("64").when(mAbi).getBitness();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtil.recursiveDelete(mTestDir);
+ }
+
+ @Test
+ public void testOnSetUpAdapterSingleInstance() throws Exception {
+ File testAdapter = createTestAdapter();
+ String output = "android.hardware.foo@1.1::IFoo/default";
+ doReturn(output).doReturn("").when(mDevice).executeShellCommand(
+ String.format(LIST_HAL_CMD, TEST_HAL_PACKAGE));
+
+ mPreparer.setUp(mDevice, mBuildInfo);
+ verify(mDevice, times(1))
+ .pushFile(eq(testAdapter), eq(TARGET_NATIVE_TEST_DIR + TEST_HAL_ADAPTER_BINARY));
+ String adapterCmd = String.format("%s /data/nativetest64/%s %s %s %d", SCRIPT_PATH,
+ TEST_HAL_ADAPTER_BINARY, "IFoo", "default", THREAD_COUNT_DEFAULT);
+ verify(mDevice, times(1)).executeShellCommand(eq(adapterCmd));
+ }
+
+ @Test
+ public void testOnSetUpAdapterMultipleInstance() throws Exception {
+ File testAdapter = createTestAdapter();
+ String output = "android.hardware.foo@1.1::IFoo/default\n"
+ + "android.hardware.foo@1.1::IFoo/test\n"
+ + "android.hardware.foo@1.1::IFooSecond/default\n"
+ + "android.hardware.foo@1.1::IFooSecond/slot/1\n";
+ doReturn(output).doReturn("").when(mDevice).executeShellCommand(
+ String.format(LIST_HAL_CMD, TEST_HAL_PACKAGE));
+
+ mPreparer.setUp(mDevice, mBuildInfo);
+
+ List<String> adapterCmds = new ArrayList<String>();
+ adapterCmds.add(String.format("%s /data/nativetest64/%s %s %s %d", SCRIPT_PATH,
+ TEST_HAL_ADAPTER_BINARY, "IFoo", "default", THREAD_COUNT_DEFAULT));
+ adapterCmds.add(String.format("%s /data/nativetest64/%s %s %s %d", SCRIPT_PATH,
+ TEST_HAL_ADAPTER_BINARY, "IFoo", "test", THREAD_COUNT_DEFAULT));
+ adapterCmds.add(String.format("%s /data/nativetest64/%s %s %s %d", SCRIPT_PATH,
+ TEST_HAL_ADAPTER_BINARY, "IFooSecond", "default", THREAD_COUNT_DEFAULT));
+ adapterCmds.add(String.format("%s /data/nativetest64/%s %s %s %d", SCRIPT_PATH,
+ TEST_HAL_ADAPTER_BINARY, "IFooSecond", "slot/1", THREAD_COUNT_DEFAULT));
+
+ for (String cmd : adapterCmds) {
+ verify(mDevice, times(1)).executeShellCommand(eq(cmd));
+ }
+ }
+
+ @Test
+ public void testOnSetupAdapterNotFound() throws Exception {
+ try {
+ mPreparer.setUp(mDevice, mBuildInfo);
+ } catch (TargetSetupError e) {
+ assertEquals("Could not push adapter.", e.getMessage());
+ return;
+ }
+ fail();
+ }
+
+ @Test
+ public void testOnSetupServiceNotAvailable() throws Exception {
+ File testAdapter = createTestAdapter();
+ doReturn("").when(mDevice).executeShellCommand(
+ String.format(LIST_HAL_CMD, TEST_HAL_PACKAGE));
+ mPreparer.setUp(mDevice, mBuildInfo);
+ }
+
+ @Test
+ public void testOnSetUpAdapterFailed() throws Exception {
+ File testAdapter = createTestAdapter();
+ String output = "android.hardware.foo@1.1::IFoo/default";
+ doReturn(output).when(mDevice).executeShellCommand(
+ String.format(LIST_HAL_CMD, TEST_HAL_PACKAGE));
+ mCmdUtil.mCmdSuccess = false;
+ try {
+ mPreparer.setUp(mDevice, mBuildInfo);
+ } catch (TargetSetupError e) {
+ assertEquals("HAL adapter setup failed.", e.getMessage());
+ return;
+ }
+ fail();
+ }
+
+ @Test
+ public void testOnTearDownRestoreFailed() throws Exception {
+ mCmdUtil.mCmdSuccess = false;
+ try {
+ mPreparer.setCmdUtil(mCmdUtil);
+ mPreparer.addCommand("one");
+ mPreparer.tearDown(mDevice, mBuildInfo, null);
+ } catch (AssertionError | DeviceNotAvailableException e) {
+ assertEquals("HAL restore failed.", e.getMessage());
+ return;
+ }
+ fail();
+ }
+
+ /**
+ * Helper method to create a test adapter under mTestDir.
+ *
+ * @return created test file.
+ */
+ private File createTestAdapter() throws IOException {
+ File testAdapter = new File(mTestDir, VTS_NATIVE_TEST_DIR + TEST_HAL_ADAPTER_BINARY);
+ testAdapter.createNewFile();
+ return testAdapter;
+ }
+}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsPythonVirtualenvPreparerTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsPythonVirtualenvPreparerTest.java
index 7d0f46a..319296a 100644
--- a/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsPythonVirtualenvPreparerTest.java
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsPythonVirtualenvPreparerTest.java
@@ -17,87 +17,151 @@
package com.android.tradefed.targetprep;
import static org.easymock.EasyMock.anyLong;
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import com.android.tradefed.build.BuildInfo;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.IRunUtil;
-
-import junit.framework.TestCase;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
import java.io.File;
-public class VtsPythonVirtualenvPreparerTest extends TestCase {
+/**
+ * Unit tests for {@link VtsPythonVirtualenvPreparer}.</p>
+ * TODO: add tests to cover a full end-to-end scenario.
+ */
+@RunWith(JUnit4.class)
+public class VtsPythonVirtualenvPreparerTest {
private VtsPythonVirtualenvPreparer mPreparer;
private IRunUtil mMockRunUtil;
- @Override
+ @Before
public void setUp() throws Exception {
- mMockRunUtil = createNiceMock(IRunUtil.class);
- mPreparer = new VtsPythonVirtualenvPreparer();
- mPreparer.mRunUtil = mMockRunUtil;
+ mMockRunUtil = EasyMock.createMock(IRunUtil.class);
+ mPreparer = new VtsPythonVirtualenvPreparer() {
+ @Override
+ IRunUtil getRunUtil() {
+ return mMockRunUtil;
+ }
+ };
+ mPreparer.mVenvDir = new File("");
+ mPreparer.mDepModules.add("enum");
}
+ /**
+ * Test that the installation of dependencies and requirements file is as expected.
+ */
+ @Test
public void testInstallDeps_reqFile_success() throws Exception {
- mPreparer.setRequirementsFile(new File("foobar"));
- expect(mMockRunUtil.runTimedCmd(anyLong(),
- (String)anyObject(), (String)anyObject(), (String)anyObject(), (String)anyObject()))
- .andReturn(new CommandResult(CommandStatus.SUCCESS));
- replay(mMockRunUtil);
- IBuildInfo buildInfo = new BuildInfo();
- mPreparer.installDeps(buildInfo);
- assertTrue(buildInfo.getFile("PYTHONPATH") != null);
+ File requirementFile = FileUtil.createTempFile("reqfile", ".txt");
+ try {
+ mPreparer.setRequirementsFile(requirementFile);
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout("output");
+ result.setStderr("std err");
+ // First check that the install requirements was attempted.
+ expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
+ EasyMock.eq("install"), EasyMock.eq("-r"),
+ EasyMock.eq(requirementFile.getAbsolutePath())))
+ .andReturn(result);
+ // Check that all default modules are installed
+ addDefaultModuleExpectations(mMockRunUtil, result);
+ EasyMock.replay(mMockRunUtil);
+ mPreparer.installDeps();
+ EasyMock.verify(mMockRunUtil);
+ } finally {
+ FileUtil.deleteFile(requirementFile);
+ }
}
+ /**
+ * Test that if an extra dependency module is required, we install it too.
+ */
+ @Test
public void testInstallDeps_depModule_success() throws Exception {
mPreparer.addDepModule("blahblah");
- expect(mMockRunUtil.runTimedCmd(anyLong(),
- (String)anyObject(), (String)anyObject(), (String)anyObject())).andReturn(
- new CommandResult(CommandStatus.SUCCESS));
- replay(mMockRunUtil);
- IBuildInfo buildInfo = new BuildInfo();
- mPreparer.installDeps(buildInfo);
- assertTrue(buildInfo.getFile("PYTHONPATH") != null);
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout("output");
+ result.setStderr("std err");
+ addDefaultModuleExpectations(mMockRunUtil, result);
+ // The non default module provided is also attempted to be installed.
+ expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
+ EasyMock.eq("install"), EasyMock.eq("blahblah")))
+ .andReturn(result);
+
+ EasyMock.replay(mMockRunUtil);
+ mPreparer.installDeps();
+ EasyMock.verify(mMockRunUtil);
}
+ /**
+ * Test that an installation failure of the requirements file throws a {@link TargetSetupError}.
+ */
+ @Test
public void testInstallDeps_reqFile_failure() throws Exception {
- mPreparer.setRequirementsFile(new File("foobar"));
- expect(mMockRunUtil.runTimedCmd(anyLong(),
- (String)anyObject(), (String)anyObject(), (String)anyObject(), (String)anyObject()))
- .andReturn(new CommandResult(CommandStatus.TIMED_OUT));
- replay(mMockRunUtil);
- IBuildInfo buildInfo = new BuildInfo();
+ File requirementFile = FileUtil.createTempFile("reqfile", ".txt");
try {
- mPreparer.installDeps(buildInfo);
- fail("installDeps succeeded despite a failed command");
- } catch (TargetSetupError e) {
- assertTrue(buildInfo.getFile("PYTHONPATH") == null);
+ mPreparer.setRequirementsFile(requirementFile);
+ CommandResult result = new CommandResult(CommandStatus.TIMED_OUT);
+ result.setStdout("output");
+ result.setStderr("std err");
+ expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
+ EasyMock.eq("install"), EasyMock.eq("-r"),
+ EasyMock.eq(requirementFile.getAbsolutePath())))
+ .andReturn(result);
+ EasyMock.replay(mMockRunUtil);
+ IBuildInfo buildInfo = new BuildInfo();
+ try {
+ mPreparer.installDeps();
+ fail("installDeps succeeded despite a failed command");
+ } catch (TargetSetupError e) {
+ assertTrue(buildInfo.getFile("PYTHONPATH") == null);
+ }
+ EasyMock.verify(mMockRunUtil);
+ } finally {
+ FileUtil.deleteFile(requirementFile);
}
}
+ /**
+ * Test that an installation failure of the dep module throws a {@link TargetSetupError}.
+ */
+ @Test
public void testInstallDeps_depModule_failure() throws Exception {
- mPreparer.addDepModule("blahblah");
- expect(mMockRunUtil.runTimedCmd(anyLong(),
- (String)anyObject(), (String)anyObject(), (String)anyObject())).andReturn(
- new CommandResult(CommandStatus.TIMED_OUT));
- replay(mMockRunUtil);
+ CommandResult result = new CommandResult(CommandStatus.TIMED_OUT);
+ result.setStdout("output");
+ result.setStderr("std err");
+ expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
+ EasyMock.eq("install"), EasyMock.eq("enum")))
+ .andReturn(result);
+ // If installing the dependency failed, an upgrade is attempted:
+ expect(mMockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
+ EasyMock.eq("install"), EasyMock.eq("--upgrade"), EasyMock.eq("enum")))
+ .andReturn(result);
+ EasyMock.replay(mMockRunUtil);
IBuildInfo buildInfo = new BuildInfo();
try {
- mPreparer.installDeps(buildInfo);
+ mPreparer.installDeps();
+ mPreparer.addPathToBuild(buildInfo);
fail("installDeps succeeded despite a failed command");
} catch (TargetSetupError e) {
assertTrue(buildInfo.getFile("PYTHONPATH") == null);
}
+ EasyMock.verify(mMockRunUtil);
}
- public void testInstallDeps_noDeps() throws Exception {
- BuildInfo buildInfo = new BuildInfo();
- mPreparer.installDeps(buildInfo);
- assertTrue(buildInfo.getFile("PYTHONPATH") == null);
+ private void addDefaultModuleExpectations(IRunUtil mockRunUtil, CommandResult result) {
+ expect(mockRunUtil.runTimedCmd(anyLong(), EasyMock.eq(mPreparer.getPipPath()),
+ EasyMock.eq("install"), EasyMock.eq("enum")))
+ .andReturn(result);
}
}
\ No newline at end of file
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsTraceCollectPreparerTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsTraceCollectPreparerTest.java
new file mode 100644
index 0000000..d745760
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/targetprep/VtsTraceCollectPreparerTest.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package com.android.tradefed.targetprep;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import junit.framework.AssertionFailedError;
+
+import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.NoSuchElementException;
+
+/**
+ * Unit tests for {@link VtsTraceCollectPreparer}.
+ */
+@RunWith(JUnit4.class)
+public final class VtsTraceCollectPreparerTest {
+ private String SELINUX_PERMISSIVE = VtsTraceCollectPreparer.SELINUX_PERMISSIVE;
+ private String VTS_LIB_DIR_32 = VtsTraceCollectPreparer.VTS_LIB_DIR_32;
+ private String VTS_LIB_DIR_64 = VtsTraceCollectPreparer.VTS_LIB_DIR_64;
+ private String VTS_BINARY_DIR = VtsTraceCollectPreparer.VTS_BINARY_DIR;
+ private String VTS_TMP_LIB_DIR_32 = VtsTraceCollectPreparer.VTS_TMP_LIB_DIR_32;
+ private String VTS_TMP_LIB_DIR_64 = VtsTraceCollectPreparer.VTS_TMP_LIB_DIR_64;
+ private String VTS_TMP_DIR = VtsTraceCollectPreparer.VTS_TMP_DIR;
+ private String PROFILING_CONFIGURE_BINARY = VtsTraceCollectPreparer.PROFILING_CONFIGURE_BINARY;
+ private String TRACE_PATH = VtsTraceCollectPreparer.TRACE_PATH;
+ private String LOCAL_TRACE_DIR = VtsTraceCollectPreparer.LOCAL_TRACE_DIR;
+
+ private static final String TEST_VTS_PROFILER = "test-vts.profiler.so";
+ private static final String TEST_VTS_LIB = "libvts-for-test.so";
+ private static final String UNRELATED_LIB = "somelib.so";
+
+ private VtsTraceCollectPreparer mPreparer;
+ private IBuildInfo mMockBuildInfo;
+ private ITestDevice mMockDevice;
+ private CompatibilityBuildHelper mMockHelper;
+ private File mTestDir;
+
+ @Before
+ public void setUp() throws Exception {
+ mMockDevice = EasyMock.createNiceMock(ITestDevice.class);
+ mMockBuildInfo = EasyMock.createNiceMock(IBuildInfo.class);
+ mTestDir = FileUtil.createTempDir("vts-trace-collect-unit-tests");
+ mMockHelper = new CompatibilityBuildHelper(mMockBuildInfo) {
+ @Override
+ public File getTestsDir() throws FileNotFoundException {
+ return mTestDir;
+ }
+ public File getResultDir() throws FileNotFoundException {
+ return mTestDir;
+ }
+ };
+ mPreparer = new VtsTraceCollectPreparer() {
+ @Override
+ CompatibilityBuildHelper createBuildHelper(IBuildInfo buildInfo) {
+ return mMockHelper;
+ }
+ };
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ // Cleanup test files.
+ FileUtil.recursiveDelete(mTestDir);
+ }
+
+ @Test
+ public void testOnSetUp() throws Exception {
+ // Create the base dirs
+ new File(mTestDir, VTS_LIB_DIR_32).mkdirs();
+ new File(mTestDir, VTS_LIB_DIR_64).mkdirs();
+ // Files that should be pushed.
+ File testProfilerlib32 = createTestFile(TEST_VTS_PROFILER, "32");
+ File testProfilerlib64 = createTestFile(TEST_VTS_PROFILER, "64");
+ File testVtslib32 = createTestFile(TEST_VTS_LIB, "32");
+ File testVtslib64 = createTestFile(TEST_VTS_LIB, "64");
+ // Files that should not be pushed.
+ File testUnrelatedlib32 = createTestFile(UNRELATED_LIB, "32");
+ File testUnrelatedlib64 = createTestFile(UNRELATED_LIB, "64");
+
+ EasyMock.expect(mMockDevice.pushFile(EasyMock.eq(testProfilerlib32),
+ EasyMock.eq(VTS_TMP_LIB_DIR_32 + TEST_VTS_PROFILER)))
+ .andReturn(true)
+ .times(1);
+ EasyMock.expect(mMockDevice.pushFile(EasyMock.eq(testProfilerlib64),
+ EasyMock.eq(VTS_TMP_LIB_DIR_64 + TEST_VTS_PROFILER)))
+ .andReturn(true)
+ .times(1);
+ EasyMock.expect(mMockDevice.pushFile(EasyMock.eq(testVtslib32),
+ EasyMock.eq(VTS_TMP_LIB_DIR_32 + TEST_VTS_LIB)))
+ .andReturn(true)
+ .times(1);
+ EasyMock.expect(mMockDevice.pushFile(EasyMock.eq(testVtslib64),
+ EasyMock.eq(VTS_TMP_LIB_DIR_64 + TEST_VTS_LIB)))
+ .andReturn(true)
+ .times(1);
+ EasyMock.expect(mMockDevice.pushFile(EasyMock.eq(testUnrelatedlib32),
+ EasyMock.eq(VTS_TMP_LIB_DIR_32 + UNRELATED_LIB)))
+ .andThrow(new AssertionFailedError())
+ .anyTimes();
+ EasyMock.expect(mMockDevice.pushFile(EasyMock.eq(testUnrelatedlib64),
+ EasyMock.eq(VTS_TMP_LIB_DIR_64 + UNRELATED_LIB)))
+ .andThrow(new AssertionFailedError())
+ .anyTimes();
+ EasyMock.expect(mMockDevice.pushFile(EasyMock.eq(new File(mTestDir,
+ VTS_BINARY_DIR + PROFILING_CONFIGURE_BINARY)),
+ EasyMock.eq(VTS_TMP_DIR + PROFILING_CONFIGURE_BINARY)))
+ .andReturn(true)
+ .times(1);
+ EasyMock.expect(mMockDevice.executeShellCommand(EasyMock.eq("getenforce")))
+ .andReturn("")
+ .times(1);
+ EasyMock.expect(mMockDevice.executeShellCommand(
+ EasyMock.eq("setenforce " + SELINUX_PERMISSIVE)))
+ .andReturn("")
+ .times(1);
+
+ // Configure the trace directory path.
+ File traceDir = new File(mTestDir, LOCAL_TRACE_DIR);
+ mMockBuildInfo.addBuildAttribute(TRACE_PATH, traceDir.getAbsolutePath());
+ EasyMock.expectLastCall().times(1);
+ EasyMock.replay(mMockDevice, mMockBuildInfo);
+
+ // Run setUp.
+ mPreparer.setUp(mMockDevice, mMockBuildInfo);
+ EasyMock.verify(mMockDevice, mMockBuildInfo);
+ }
+
+ @Test
+ public void testOnSetUpPushFileException() throws Exception {
+ EasyMock.expect(mMockDevice.pushFile(EasyMock.anyObject(), EasyMock.anyObject()))
+ .andThrow(new NoSuchElementException("file not found."));
+ EasyMock.replay(mMockDevice);
+ try {
+ mPreparer.setUp(mMockDevice, mMockBuildInfo);
+ EasyMock.verify(mMockDevice);
+ } catch (TargetSetupError e) {
+ // Expected.
+ assertEquals("Could not push profiler.", e.getMessage());
+ return;
+ }
+ fail();
+ }
+
+ @Test
+ public void testOnTearDown() throws Exception {
+ EasyMock.expect(mMockDevice.executeShellCommand(EasyMock.eq("getenforce")))
+ .andReturn(SELINUX_PERMISSIVE);
+ EasyMock.expect(mMockDevice.executeShellCommand(
+ EasyMock.eq("setenforce " + SELINUX_PERMISSIVE)))
+ .andReturn("")
+ .times(1);
+ EasyMock.replay(mMockDevice, mMockBuildInfo);
+ mPreparer.setUp(mMockDevice, mMockBuildInfo);
+ mPreparer.tearDown(mMockDevice, mMockBuildInfo, null);
+ EasyMock.verify(mMockDevice, mMockBuildInfo);
+ }
+
+ /**
+ * Helper method to create a test file under mTestDir.
+ *
+ * @param fileName test file name.
+ * @param bitness bitness for the test file. Only supports "32" or "64".
+ * @return created test file, null for unsupported bitness.
+ */
+ private File createTestFile(String fileName, String bitness) throws Exception {
+ if (bitness == "32") {
+ File testFile32 = new File(mTestDir, VTS_LIB_DIR_32 + fileName);
+ testFile32.createNewFile();
+ return testFile32;
+ } else if (bitness == "64") {
+ File testFile64 = new File(mTestDir, VTS_LIB_DIR_64 + fileName);
+ testFile64.createNewFile();
+ return testFile64;
+ }
+ return null;
+ }
+}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/testtype/VtsMultiDeviceTestResultParserTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/testtype/VtsMultiDeviceTestResultParserTest.java
index 4973200..a7bb40c 100644
--- a/harnesses/tradefed/tests/src/com/android/tradefed/testtype/VtsMultiDeviceTestResultParserTest.java
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/testtype/VtsMultiDeviceTestResultParserTest.java
@@ -17,9 +17,13 @@
import com.android.ddmlib.testrunner.ITestRunListener;
import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.VtsFileUtil;
-import junit.framework.TestCase;
import org.easymock.EasyMock;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
import java.io.BufferedReader;
import java.io.File;
@@ -33,203 +37,173 @@
/**
* Unit tests for {@link VtsMultiDeviceTestResultParser}.
*/
-public class VtsMultiDeviceTestResultParserTest extends TestCase {
-
- // for file path
- private static final String TEST_DIR = "tests";
- private static final String OUTPUT_FILE_1 = "vts_multi_device_test_parser_output.txt";
- private static final String OUTPUT_FILE_2 = "vts_multi_device_test_parser_output_timeout.txt";
- private static final String OUTPUT_FILE_3 = "vts_multi_device_test_parser_output_error.txt";
- private static final String USER_DIR = "user.dir";
- private static final String RES = "res";
- private static final String TEST_TYPE = "testtype";
-
- //test results
- static final String PASS = "PASS";
- static final String FAIL = "FAIL";
- static final String TIME_OUT = "TIMEOUT";
+@RunWith(JUnit4.class)
+public class VtsMultiDeviceTestResultParserTest {
+ // Test file paths in the resources
+ private static final String OUTPUT_FILE_1 = "/testtype/vts_multi_device_test_parser_output.txt";
+ private static final String OUTPUT_FILE_2 =
+ "/testtype/vts_multi_device_test_parser_output_timeout.txt";
+ private static final String OUTPUT_FILE_3 =
+ "/testtype/vts_multi_device_test_parser_output_error.txt";
// test name
private static final String RUN_NAME = "SampleLightFuzzTest";
private static final String TEST_NAME_1 = "testTurnOnLightBlackBoxFuzzing";
private static final String TEST_NAME_2 = "testTurnOnLightWhiteBoxFuzzing";
- // enumeration to indicate the input file used for each run.
- private TestCase mTestCase = TestCase.NORMAL;
- private enum TestCase {
- NORMAL, ERROR, TIMEOUT;
- }
-
/**
* Test the run method with a normal input.
- * @throws IOException
*/
- public void testRunTimeoutInput() throws IOException{
- mTestCase = TestCase.TIMEOUT;
- String[] contents = getOutput();
+ @Test
+ public void testRunTimeoutInput() throws IOException {
+ String[] contents = getOutput(OUTPUT_FILE_2);
long totalTime = getTotalTime(contents);
// prepare the mock object
ITestRunListener mockRunListener = EasyMock.createMock(ITestRunListener.class);
- mockRunListener.testRunStarted(TEST_NAME_1, 2);
mockRunListener.testRunStarted(TEST_NAME_2, 2);
- mockRunListener.testStarted(new TestIdentifier(RUN_NAME, TEST_NAME_1));
- mockRunListener.testStarted(new TestIdentifier(RUN_NAME, TEST_NAME_2));
- mockRunListener.testEnded(new TestIdentifier(RUN_NAME, TEST_NAME_1),
- Collections.<String, String>emptyMap());
- mockRunListener.testFailed(new TestIdentifier(RUN_NAME, TEST_NAME_2), TIME_OUT);
+ TestIdentifier test1 = new TestIdentifier(RUN_NAME, TEST_NAME_2);
+ mockRunListener.testStarted(test1);
+ mockRunListener.testFailed(test1, "TIMEOUT");
+ mockRunListener.testEnded(test1, Collections.emptyMap());
+
+ TestIdentifier test2 = new TestIdentifier(RUN_NAME, TEST_NAME_1);
+ mockRunListener.testStarted(test2);
+ mockRunListener.testEnded(test2, Collections.emptyMap());
+ mockRunListener.testRunEnded(totalTime, Collections.emptyMap());
+
+ EasyMock.replay(mockRunListener);
+ VtsMultiDeviceTestResultParser resultParser =
+ new VtsMultiDeviceTestResultParser(mockRunListener, RUN_NAME);
+ resultParser.processNewLines(contents);
+ resultParser.done();
+ EasyMock.verify(mockRunListener);
+ }
+
+ /**
+ * Test the run method with a normal input.
+ */
+ @Test
+ public void testRunNormalInput() throws IOException {
+ String[] contents = getOutput(OUTPUT_FILE_1);
+ long totalTime = getTotalTime(contents);
+
+ // prepare the mock object
+ ITestRunListener mockRunListener = EasyMock.createMock(ITestRunListener.class);
+ mockRunListener.testRunStarted(TEST_NAME_2, 2);
+ TestIdentifier test1 = new TestIdentifier(RUN_NAME, TEST_NAME_2);
+ mockRunListener.testStarted(test1);
+ mockRunListener.testEnded(test1, Collections.emptyMap());
+
+ TestIdentifier test2 = new TestIdentifier(RUN_NAME, TEST_NAME_1);
+ mockRunListener.testStarted(test2);
+ mockRunListener.testEnded(test2, Collections.emptyMap());
+ mockRunListener.testRunEnded(totalTime, Collections.emptyMap());
+
+ EasyMock.replay(mockRunListener);
+ VtsMultiDeviceTestResultParser resultParser =
+ new VtsMultiDeviceTestResultParser(mockRunListener, RUN_NAME);
+ resultParser.processNewLines(contents);
+ resultParser.done();
+ EasyMock.verify(mockRunListener);
+ }
+
+ /**
+ * Test the run method with a erroneous input.
+ */
+ @Test
+ public void testRunErrorInput() throws IOException {
+ String[] contents = getOutput(OUTPUT_FILE_3);
+ long totalTime = getTotalTime(contents);
+
+ // prepare the mock object
+ ITestRunListener mockRunListener = EasyMock.createMock(ITestRunListener.class);
+ mockRunListener.testRunStarted(null, 0);
mockRunListener.testRunEnded(totalTime, Collections.<String, String>emptyMap());
EasyMock.replay(mockRunListener);
- VtsMultiDeviceTestResultParser resultParser = new VtsMultiDeviceTestResultParser(
- mockRunListener, RUN_NAME);
+ VtsMultiDeviceTestResultParser resultParser =
+ new VtsMultiDeviceTestResultParser(mockRunListener, RUN_NAME);
resultParser.processNewLines(contents);
resultParser.done();
+ EasyMock.verify(mockRunListener);
}
-
- /**
- * Test the run method with a normal input.
- * @throws IOException
- */
- public void testRunNormalInput() throws IOException{
- mTestCase = TestCase.NORMAL;
- String[] contents = getOutput();
- long totalTime = getTotalTime(contents);
-
- // prepare the mock object
- ITestRunListener mockRunListener = EasyMock.createMock(ITestRunListener.class);
- mockRunListener.testRunStarted(TEST_NAME_1, 2);
- mockRunListener.testRunStarted(TEST_NAME_2, 2);
- mockRunListener.testStarted(new TestIdentifier(RUN_NAME, TEST_NAME_1));
- mockRunListener.testStarted(new TestIdentifier(RUN_NAME, TEST_NAME_2));
- mockRunListener.testEnded(new TestIdentifier(RUN_NAME, TEST_NAME_1),
- Collections.<String, String>emptyMap());
- mockRunListener.testEnded(new TestIdentifier(RUN_NAME, TEST_NAME_2),
- Collections.<String, String>emptyMap());
- mockRunListener.testRunEnded(totalTime, Collections.<String, String>emptyMap());
-
- EasyMock.replay(mockRunListener);
- VtsMultiDeviceTestResultParser resultParser = new VtsMultiDeviceTestResultParser(
- mockRunListener, RUN_NAME);
- resultParser.processNewLines(contents);
- resultParser.done();
- }
-
- /**
- * Test the run method with a erroneous input.
- * @throws IOException
- */
- public void testRunErrorInput() throws IOException{
- mTestCase = TestCase.ERROR;
- String[] contents = getOutput();
- long totalTime = getTotalTime(contents);
-
- // prepare the mock object
- ITestRunListener mockRunListener = EasyMock.createMock(ITestRunListener.class);
- mockRunListener.testRunStarted(null, 0);
- mockRunListener.testRunEnded(totalTime, Collections.<String, String>emptyMap());
-
- EasyMock.replay(mockRunListener);
- VtsMultiDeviceTestResultParser resultParser = new VtsMultiDeviceTestResultParser(
- mockRunListener, RUN_NAME);
- resultParser.processNewLines(contents);
- resultParser.done();
- }
- /**
+ /**
* @param contents The logs that are used for a test case.
* @return {long} total running time of the test.
*/
- private long getTotalTime(String[] contents) {
- Date startDate = getDate(contents, true);
- Date endDate = getDate(contents, false);
+ private long getTotalTime(String[] contents) {
+ Date startDate = getDate(contents, true);
+ Date endDate = getDate(contents, false);
- if (startDate == null || endDate == null) {
- return 0;
- }
- return endDate.getTime() - startDate.getTime();
- }
+ if (startDate == null || endDate == null) {
+ return 0;
+ }
+ return endDate.getTime() - startDate.getTime();
+ }
/**
- * Returns the sample shell output for a test command.
- * @return {String} shell output
- * @throws IOException
- */
- private String[] getOutput() throws IOException{
- BufferedReader br = null;
- String output = null;
- try {
- br = new BufferedReader(new FileReader(getFileName()));
- StringBuilder sb = new StringBuilder();
- String line = br.readLine();
+ * Returns the sample shell output for a test command.
+ *
+ * @return {String} shell output
+ * @throws IOException
+ */
+ private String[] getOutput(String filePath) throws IOException {
+ File tmpDir = FileUtil.createTempDir("tmp-dir");
+ BufferedReader br = null;
+ String output = null;
+ try {
+ File resFile = VtsFileUtil.saveResourceFile(
+ this.getClass().getResourceAsStream(filePath), tmpDir, "test-file");
+ br = new BufferedReader(new FileReader(resFile));
+ StringBuilder sb = new StringBuilder();
+ String line = br.readLine();
- while (line != null) {
- sb.append(line);
- sb.append(System.lineSeparator());
- line = br.readLine();
- }
- output = sb.toString();
- } finally {
- br.close();
- }
- return output.split("\n");
- }
+ while (line != null) {
+ sb.append(line);
+ sb.append(System.lineSeparator());
+ line = br.readLine();
+ }
+ output = sb.toString();
+ } finally {
+ if (br != null) {
+ br.close();
+ }
+ FileUtil.recursiveDelete(tmpDir);
+ }
+ return output.split("\n");
+ }
- /** Return the file path that contains sample shell output logs.
- *
- * @return {String} The file path.
- */
- private String getFileName(){
- String fileName = null;
- switch (mTestCase) {
- case NORMAL:
- fileName = OUTPUT_FILE_1;
- break;
- case TIMEOUT:
- fileName = OUTPUT_FILE_2;
- break;
- case ERROR:
- fileName = OUTPUT_FILE_3;
- break;
- default:
- break;
- }
- StringBuilder path = new StringBuilder();
- path.append(System.getProperty(USER_DIR)).append(File.separator).append(TEST_DIR).
- append(File.separator).append(RES).append(File.separator).
- append(TEST_TYPE).append(File.separator).append(fileName);
- return path.toString();
- }
+ /**
+ * Return the time in milliseconds to calculate the time elapsed in a particular test.
+ *
+ * @param lines The logs that need to be parsed.
+ * @param calculateStartDate flag which is true if we need to calculate start date.
+ * @return {Date} the start and end time corresponding to a test.
+ */
+ private Date getDate(String[] lines, boolean calculateStartDate) {
+ Date date = null;
+ int begin = calculateStartDate ? 0 : lines.length - 1;
+ int diff = calculateStartDate ? 1 : -1;
- /**
- * Return the time in milliseconds to calculate the time elapsed in a particular test.
- *
- * @param lines The logs that need to be parsed.
- * @param calculateStartDate flag which is true if we need to calculate start date.
- * @return {Date} the start and end time corresponding to a test.
- */
- private Date getDate(String[] lines, boolean calculateStartDate) {
- Date date = null;
- int begin = calculateStartDate ? 0 : lines.length - 1;
- int diff = calculateStartDate ? 1 : -1;
+ for (int index = begin; index >= 0 && index < lines.length; index += diff) {
+ lines[index].trim();
+ String[] toks = lines[index].split(" ");
- for (int index = begin; index >= 0 && index < lines.length; index += diff) {
- lines[index].trim();
- String[] toks = lines[index].split(" ");
-
- // set the start time from the first line
- // the loop should continue if exception occurs, else it can break
- if (toks.length < 3) {
- continue;
- }
- String time = toks[2];
- SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
- try {
- date = sdf.parse(time);
- } catch (ParseException e) {
- continue;
- }
- break;
- }
- return date;
- }
+ // set the start time from the first line
+ // the loop should continue if exception occurs, else it can break
+ if (toks.length < 3) {
+ continue;
+ }
+ String time = toks[2];
+ SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
+ try {
+ date = sdf.parse(time);
+ } catch (ParseException e) {
+ continue;
+ }
+ break;
+ }
+ return date;
+ }
}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/testtype/VtsMultiDeviceTestTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/testtype/VtsMultiDeviceTestTest.java
index 503cfab..14774e9 100644
--- a/harnesses/tradefed/tests/src/com/android/tradefed/testtype/VtsMultiDeviceTestTest.java
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/testtype/VtsMultiDeviceTestTest.java
@@ -15,6 +15,10 @@
*/
package com.android.tradefed.testtype;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -22,21 +26,19 @@
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.util.CommandResult;
import com.android.tradefed.util.CommandStatus;
-import com.android.tradefed.util.IRunUtil;
-import com.android.tradefed.util.ProcessHelper;
-import com.android.tradefed.util.RunInterruptedException;
import com.android.tradefed.util.StreamUtil;
+import com.android.tradefed.util.VtsPythonRunnerHelper;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
-import java.io.IOException;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.Map;
-import junit.framework.TestCase;
-import org.easymock.EasyMock;
import org.json.JSONObject;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
/**
* Unit tests for {@link VtsMultiDeviceTest}.
@@ -46,35 +48,30 @@
* which contains the same config as the build output
* out/host/linux-x86/vts/android-vts/testcases/
*/
-public class VtsMultiDeviceTestTest extends TestCase {
-
- private ITestInvocationListener mMockInvocationListener = null;
- private VtsMultiDeviceTest mTest = null;
- private ProcessHelper mProcessHelper = null;
- private String mPython = null;
+@RunWith(JUnit4.class)
+public class VtsMultiDeviceTestTest {
+ private static final String PYTHON_BINARY = "python";
private static final String PYTHON_DIR = "mock/";
private static final String TEST_CASE_PATH =
"vts/testcases/host/sample/SampleLightTest";
+ private ITestInvocationListener mMockInvocationListener = null;
+ private VtsMultiDeviceTest mTest = null;
/**
* Helper to initialize the various EasyMocks we'll need.
*/
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
mMockInvocationListener = EasyMock.createMock(ITestInvocationListener.class);
- mProcessHelper = null;
- mPython = "python";
mTest = new VtsMultiDeviceTest() {
+ // TODO: Test this method.
@Override
- protected ProcessHelper createProcessHelper(String[] cmd) {
- assertCommand(cmd);
- try {
- createResult(cmd[3]);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- return mProcessHelper;
+ protected void updateVtsRunnerTestConfig(JSONObject jsonObject) {
+ return;
+ }
+ @Override
+ protected VtsPythonRunnerHelper createVtsPythonRunnerHelper() {
+ return createMockVtsPythonRunnerHelper(CommandStatus.SUCCESS);
}
};
mTest.setBuild(createMockBuildInfo());
@@ -86,7 +83,7 @@
* Check VTS Python command strings.
*/
private void assertCommand(String[] cmd) {
- assertEquals(cmd[0], PYTHON_DIR + mPython);
+ assertEquals(cmd[0], PYTHON_BINARY);
assertEquals(cmd[1], "-m");
assertEquals(cmd[2], TEST_CASE_PATH.replace("/", "."));
assertTrue(cmd[3].endsWith(".json"));
@@ -110,33 +107,6 @@
new File(logPath, VtsMultiDeviceTest.REPORT_MESSAGE_FILE_NAME).createNewFile();
}
- /**
- * Create a process helper which mocks status of a running process.
- */
- private static ProcessHelper createMockProcessHelper(CommandStatus... status) {
- Process process;
- try {
- process = new ProcessBuilder("true").start();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- LinkedList<CommandStatus> nextStatus = new LinkedList<CommandStatus>(Arrays.asList(status));
- return new ProcessHelper(process) {
- @Override
- public CommandStatus waitForProcess(long timeoutMsecs) throws RunInterruptedException {
- CommandStatus currentStatus = nextStatus.removeFirst();
- if (currentStatus == null) {
- throw new RunInterruptedException();
- }
- return currentStatus;
- }
-
- @Override
- public boolean isRunning() {
- return !nextStatus.isEmpty();
- }
- };
- }
/**
* Create a mock IBuildInfo with necessary getter methods.
@@ -146,71 +116,36 @@
buildAttributes.put("ROOT_DIR", "DIR_NOT_EXIST");
buildAttributes.put("ROOT_DIR2", "DIR_NOT_EXIST");
buildAttributes.put("SUITE_NAME", "JUNIT_TEST_SUITE");
- IFolderBuildInfo buildInfo = EasyMock.createMock(IFolderBuildInfo.class);
- EasyMock.expect(buildInfo.getBuildId()).
- andReturn("BUILD_ID");
- EasyMock.expect(buildInfo.getBuildTargetName()).
- andReturn("BUILD_TARGET_NAME");
- EasyMock.expect(buildInfo.getTestTag()).
- andReturn("TEST_TAG").atLeastOnce();
- EasyMock.expect(buildInfo.getDeviceSerial()).
- andReturn("1234567890ABCXYZ").atLeastOnce();
- EasyMock.expect(buildInfo.getRootDir()).
- andReturn(new File("DIR_NOT_EXIST"));
- EasyMock.expect(buildInfo.getBuildAttributes()).
- andReturn(buildAttributes).atLeastOnce();
- EasyMock.expect(buildInfo.getFile(EasyMock.eq("vts"))).
- andReturn(null);
- EasyMock.expect(buildInfo.getFile(EasyMock.eq("PYTHONPATH"))).
- andReturn(new File("DIR_NOT_EXIST")).atLeastOnce();
- EasyMock.expect(buildInfo.getFile(EasyMock.eq("VIRTUALENVPATH"))).
- andReturn(new File("DIR_NOT_EXIST"));
- EasyMock.expect(buildInfo.getFile(EasyMock.anyObject())).andReturn(null).anyTimes();
+ IFolderBuildInfo buildInfo = EasyMock.createNiceMock(IFolderBuildInfo.class);
+ EasyMock.expect(buildInfo.getBuildId()).andReturn("BUILD_ID").anyTimes();
+ EasyMock.expect(buildInfo.getBuildTargetName()).andReturn("BUILD_TARGET_NAME").anyTimes();
+ EasyMock.expect(buildInfo.getTestTag()).andReturn("TEST_TAG").anyTimes();
+ EasyMock.expect(buildInfo.getDeviceSerial()).andReturn("1234567890ABCXYZ").anyTimes();
+ EasyMock.expect(buildInfo.getRootDir()).andReturn(new File("DIR_NOT_EXIST")).anyTimes();
+ EasyMock.expect(buildInfo.getBuildAttributes()).andReturn(buildAttributes).anyTimes();
+ EasyMock.expect(buildInfo.getFile(EasyMock.eq("PYTHONPATH")))
+ .andReturn(new File("DIR_NOT_EXIST"))
+ .anyTimes();
+ EasyMock.expect(buildInfo.getFile(EasyMock.eq("VIRTUALENVPATH")))
+ .andReturn(new File("DIR_NOT_EXIST"))
+ .anyTimes();
EasyMock.replay(buildInfo);
return buildInfo;
}
/**
- * Create a mock IRunUtil which sets environment variables and finds Python binary file.
- */
- private IRunUtil createMockRunUtil(String findFileCommand) {
- IRunUtil runUtil = EasyMock.createMock(IRunUtil.class);
- runUtil.setEnvVariable(EasyMock.eq("VTS"), EasyMock.eq("1"));
- EasyMock.expectLastCall();
- CommandResult findResult = new CommandResult();
- findResult.setStatus(CommandStatus.SUCCESS);
- findResult.setStdout(PYTHON_DIR + mPython);
- EasyMock.expect(runUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq(findFileCommand),
- EasyMock.eq(mPython)))
- .andReturn(findResult);
- EasyMock.replay(runUtil);
- return runUtil;
- }
-
- /**
* Create a mock ITestDevice with necessary getter methods.
*/
private static ITestDevice createMockDevice() {
// TestDevice
- ITestDevice device = EasyMock.createMock(ITestDevice.class);
+ ITestDevice device = EasyMock.createNiceMock(ITestDevice.class);
try {
- EasyMock.expect(device.getSerialNumber()).
- andReturn("1234567890ABCXYZ").atLeastOnce();
- EasyMock.expect(device.getBuildAlias()).
- andReturn("BUILD_ALIAS");
- EasyMock.expect(device.getBuildFlavor()).
- andReturn("BUILD_FLAVOR");
- EasyMock.expect(device.getBuildId()).
- andReturn("BUILD_ID");
- EasyMock.expect(device.getProperty("ro.vts.coverage")).
- andReturn(null);
- EasyMock.expect(device.getProductType()).
- andReturn("PRODUCT_TYPE");
- EasyMock.expect(device.getProductVariant()).
- andReturn("PRODUCT_VARIANT");
- EasyMock.expect(device.executeShellCommand(EasyMock.startsWith("log")))
- .andReturn(null)
- .anyTimes();
+ EasyMock.expect(device.getSerialNumber()).andReturn("1234567890ABCXYZ").anyTimes();
+ EasyMock.expect(device.getBuildAlias()).andReturn("BUILD_ALIAS").anyTimes();
+ EasyMock.expect(device.getBuildFlavor()).andReturn("BUILD_FLAVOR").anyTimes();
+ EasyMock.expect(device.getBuildId()).andReturn("BUILD_ID").anyTimes();
+ EasyMock.expect(device.getProductType()).andReturn("PRODUCT_TYPE").anyTimes();
+ EasyMock.expect(device.getProductVariant()).andReturn("PRODUCT_VARIANT").anyTimes();
} catch (DeviceNotAvailableException e) {
fail();
}
@@ -219,12 +154,31 @@
}
/**
+ * Create a process helper which mocks status of a running process.
+ */
+ private VtsPythonRunnerHelper createMockVtsPythonRunnerHelper(CommandStatus status) {
+ return new VtsPythonRunnerHelper(new File(PYTHON_DIR)) {
+ @Override
+ public String runPythonRunner(
+ String[] cmd, CommandResult commandResult, long testTimeout) {
+ assertCommand(cmd);
+ try {
+ createResult(cmd[3]);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ commandResult.setStatus(status);
+ return null;
+ }
+ };
+ }
+
+ /**
* Test the run method with a normal input.
*/
+ @Test
public void testRunNormalInput() {
- mProcessHelper = createMockProcessHelper(CommandStatus.SUCCESS);
mTest.setDevice(createMockDevice());
- mTest.setRunUtil(createMockRunUtil("which"));
try {
mTest.run(mMockInvocationListener);
} catch (IllegalArgumentException e) {
@@ -239,26 +193,9 @@
}
/**
- * Test the run method with a normal input and Windows environment variable.
- */
- public void testRunNormalInputOnWindows()
- throws IllegalArgumentException, DeviceNotAvailableException {
- mProcessHelper = createMockProcessHelper(CommandStatus.SUCCESS);
- mPython = "python.exe";
- String originalName = System.getProperty(VtsMultiDeviceTest.OS_NAME);
- System.setProperty(VtsMultiDeviceTest.OS_NAME, VtsMultiDeviceTest.WINDOWS);
- mTest.setDevice(createMockDevice());
- mTest.setRunUtil(createMockRunUtil("where"));
- try {
- mTest.run(mMockInvocationListener);
- } finally {
- System.setProperty(VtsMultiDeviceTest.OS_NAME, originalName);
- }
- }
-
- /**
* Test the run method when the device is set null.
*/
+ @Test
public void testRunDeviceNotAvailable() {
mTest.setDevice(null);
try {
@@ -271,61 +208,4 @@
// expected
}
}
-
- /**
- * Test the run method with abnormal input data.
- */
- public void testRunNormalInputCommandFailed() {
- mProcessHelper = createMockProcessHelper(CommandStatus.FAILED);
- mTest.setDevice(createMockDevice());
- mTest.setRunUtil(createMockRunUtil("which"));
- try {
- mTest.run(mMockInvocationListener);
- fail();
- } catch (RuntimeException e) {
- if (!"Failed to run VTS test".equals(e.getMessage())) {
- fail();
- }
- // expected
- } catch (DeviceNotAvailableException e) {
- // not expected
- fail();
- e.printStackTrace();
- }
- }
-
- /**
- * Test the run method in which the command times out.
- */
- public void testRunNormalInputTimeout() {
- mProcessHelper = createMockProcessHelper(CommandStatus.TIMED_OUT, CommandStatus.TIMED_OUT);
- mTest.setDevice(createMockDevice());
- mTest.setRunUtil(createMockRunUtil("which"));
- try {
- mTest.run(mMockInvocationListener);
- } catch (IllegalArgumentException e) {
- fail();
- } catch (DeviceNotAvailableException e) {
- fail();
- }
- }
-
- /**
- * Test the run method in which the command is interrupted.
- */
- public void testRunNormalInputInterrupted() {
- mProcessHelper = createMockProcessHelper(null, CommandStatus.SUCCESS);
- mTest.setDevice(createMockDevice());
- mTest.setRunUtil(createMockRunUtil("which"));
- try {
- mTest.run(mMockInvocationListener);
- fail();
- } catch (IllegalArgumentException e) {
- fail();
- } catch (RunInterruptedException e) {
- // expected
- } catch (DeviceNotAvailableException e) {
- fail();
- }
- }
}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/util/CmdUtilTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/util/CmdUtilTest.java
new file mode 100644
index 0000000..e115bd0
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/util/CmdUtilTest.java
@@ -0,0 +1,102 @@
+package com.android.tradefed.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.*;
+
+import com.android.tradefed.device.ITestDevice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Predicate;
+import java.util.Vector;
+
+/**
+ * Unit tests for {@link CmdUtil}.
+ */
+@RunWith(JUnit4.class)
+public class CmdUtilTest {
+ static final String RUN_CMD = "run cmd";
+ static final String TEST_CMD = "test cmd";
+
+ class MockSleeper implements CmdUtil.ISleeper {
+ @Override
+ public void sleep(int seconds) throws InterruptedException {
+ return;
+ }
+ };
+
+ CmdUtil mCmdUtil = null;
+
+ // Predicates to stop retrying cmd.
+ private Predicate<String> mCheckEmpty = (String str) -> {
+ return str.isEmpty();
+ };
+
+ @Mock private ITestDevice mDevice;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ CmdUtil.ISleeper msleeper = new MockSleeper();
+ mCmdUtil = new CmdUtil();
+ mCmdUtil.setSleeper(msleeper);
+ }
+
+ @Test
+ public void testWaitCmdSuccess() throws Exception {
+ doReturn("").when(mDevice).executeShellCommand(TEST_CMD);
+ assertTrue(mCmdUtil.waitCmdResultWithDelay(mDevice, TEST_CMD, mCheckEmpty));
+ }
+
+ @Test
+ public void testWaitCmdSuccessWithRetry() throws Exception {
+ when(mDevice.executeShellCommand(TEST_CMD)).thenReturn("something").thenReturn("");
+ assertTrue(mCmdUtil.waitCmdResultWithDelay(mDevice, TEST_CMD, mCheckEmpty));
+ }
+
+ @Test
+ public void testWaitCmdSuccessFail() throws Exception {
+ doReturn("something").when(mDevice).executeShellCommand(TEST_CMD);
+ assertFalse(mCmdUtil.waitCmdResultWithDelay(mDevice, TEST_CMD, mCheckEmpty));
+ }
+
+ @Test
+ public void testRetrySuccess() throws Exception {
+ doReturn("").when(mDevice).executeShellCommand(TEST_CMD);
+ assertTrue(mCmdUtil.retry(mDevice, RUN_CMD, TEST_CMD, mCheckEmpty));
+ verify(mDevice, times(1)).executeShellCommand(eq(RUN_CMD));
+ }
+
+ @Test
+ public void testRetrySuccessWithRetry() throws Exception {
+ when(mDevice.executeShellCommand(TEST_CMD)).thenReturn("something").thenReturn("");
+ assertTrue(mCmdUtil.retry(mDevice, RUN_CMD, TEST_CMD, mCheckEmpty));
+ verify(mDevice, times(2)).executeShellCommand(eq(RUN_CMD));
+ }
+
+ @Test
+ public void testRetryFail() throws Exception {
+ doReturn("something").when(mDevice).executeShellCommand(TEST_CMD);
+ assertFalse(mCmdUtil.retry(mDevice, RUN_CMD, TEST_CMD, mCheckEmpty));
+ verify(mDevice, times(mCmdUtil.MAX_RETRY_COUNT)).executeShellCommand(eq(RUN_CMD));
+ }
+
+ @Test
+ public void testRetryMultipleCommandsSuccess() throws Exception {
+ doReturn("").when(mDevice).executeShellCommand(TEST_CMD);
+ Vector<String> cmds = new Vector<String>();
+ int command_count = 5;
+ for (int i = 0; i < command_count; i++) {
+ cmds.add(RUN_CMD);
+ }
+ assertTrue(mCmdUtil.retry(mDevice, cmds, TEST_CMD, mCheckEmpty));
+ verify(mDevice, times(command_count)).executeShellCommand(eq(RUN_CMD));
+ }
+}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/util/ProcessHelperTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/util/ProcessHelperTest.java
index 2859f27..70ff407 100644
--- a/harnesses/tradefed/tests/src/com/android/tradefed/util/ProcessHelperTest.java
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/util/ProcessHelperTest.java
@@ -16,79 +16,149 @@
package com.android.tradefed.util;
-import com.android.tradefed.util.CommandStatus;
-import com.android.tradefed.util.IRunUtil;
-import com.android.tradefed.util.ProcessHelper;
-import com.android.tradefed.util.RunInterruptedException;
-import com.android.tradefed.util.RunUtil;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
-import junit.framework.TestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
/**
* Test cases for {@link ProcessHelper}.
*/
-public class ProcessHelperTest extends TestCase {
- private ProcessHelper mProcess;
+@RunWith(JUnit4.class)
+public class ProcessHelperTest {
+ private ProcessHelper mProcessHelper;
/**
- * Reset the ProcessHelper
+ * Return a mock process.
*/
- @Override
+ private Process createMockProcess(
+ String stdout, String stderr, int exitValue, long executionTimeMsecs) {
+ // No need to close OutputStream and ByteArrayInputStream because doing so has no effect.
+ OutputStream stdinStream = new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {}
+ };
+ InputStream stdoutStream = new ByteArrayInputStream(stdout.getBytes());
+ InputStream stderrStream = new ByteArrayInputStream(stderr.getBytes());
+ long endTime = System.currentTimeMillis() + executionTimeMsecs;
+
+ return new Process() {
+ private boolean destroyed = false;
+
+ private boolean isRunning() {
+ return System.currentTimeMillis() <= endTime && !destroyed;
+ }
+
+ @Override
+ public void destroy() {
+ destroyed = true;
+ }
+
+ @Override
+ public int exitValue() {
+ if (isRunning()) {
+ throw new IllegalThreadStateException();
+ }
+ return exitValue;
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return stdoutStream;
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return stdinStream;
+ }
+
+ @Override
+ public InputStream getErrorStream() {
+ return stderrStream;
+ }
+
+ @Override
+ public int waitFor() throws InterruptedException {
+ while (isRunning()) {
+ Thread.sleep(50);
+ }
+ return exitValue;
+ }
+ };
+ }
+
+ /**
+ * Reset the ProcessHelper.
+ */
+ @Before
public void setUp() {
- mProcess = null;
+ mProcessHelper = null;
}
/**
* Terminate the process, join threads and close IO streams.
*/
- @Override
+ @After
public void tearDown() {
- if (mProcess != null) {
- mProcess.cleanUp();
+ if (mProcessHelper != null) {
+ mProcessHelper.cleanUp();
}
}
/**
* Test running a process that returns zero.
*/
- public void testSuccess() throws IOException {
- mProcess = new ProcessHelper(new ProcessBuilder("echo", "123").start());
- CommandStatus status = mProcess.waitForProcess(1000);
+ @Test
+ public void testSuccess() {
+ mProcessHelper = new ProcessHelper(createMockProcess("123\n", "456\n", 0, 10));
+ CommandStatus status = mProcessHelper.waitForProcess(10000);
assertEquals(CommandStatus.SUCCESS, status);
- assertFalse(mProcess.isRunning());
- assertTrue(mProcess.getStdout().equals("123\n"));
- assertTrue(mProcess.getStderr().isEmpty());
+ assertFalse(mProcessHelper.isRunning());
+ assertTrue(mProcessHelper.getStdout().equals("123\n"));
+ assertTrue(mProcessHelper.getStderr().equals("456\n"));
}
/**
* Test running a process that returns non-zero.
*/
- public void testFailure() throws IOException {
- mProcess = new ProcessHelper(new ProcessBuilder("ls", "--WRONG-OPTION").start());
- CommandStatus status = mProcess.waitForProcess(1000);
+ @Test
+ public void testFailure() {
+ mProcessHelper = new ProcessHelper(createMockProcess("123\n", "456\n", 1, 10));
+ CommandStatus status = mProcessHelper.waitForProcess(10000);
assertEquals(CommandStatus.FAILED, status);
- assertFalse(mProcess.isRunning());
- assertTrue(mProcess.getStdout().isEmpty());
- assertTrue(mProcess.getStderr().contains("unrecognized option"));
+ assertFalse(mProcessHelper.isRunning());
+ assertTrue(mProcessHelper.getStdout().equals("123\n"));
+ assertTrue(mProcessHelper.getStderr().equals("456\n"));
}
/**
* Test running a process that times out.
*/
- public void testTimeout() throws IOException {
- mProcess = new ProcessHelper(new ProcessBuilder("cat").start());
- CommandStatus status = mProcess.waitForProcess(30);
+ @Test
+ public void testTimeout() {
+ mProcessHelper = new ProcessHelper(createMockProcess("", "", 1, 10000));
+ CommandStatus status = mProcessHelper.waitForProcess(100);
assertEquals(CommandStatus.TIMED_OUT, status);
- assertTrue(mProcess.isRunning());
+ assertTrue(mProcessHelper.isRunning());
}
/**
* Test running a process and being interrupted.
*/
- public void testInterrupt() throws IOException, InterruptedException {
- mProcess = new ProcessHelper(new ProcessBuilder("cat").start());
+ @Test
+ public void testInterrupt() throws InterruptedException {
+ mProcessHelper = new ProcessHelper(createMockProcess("", "", 1, 10000));
IRunUtil runUtil = RunUtil.getDefault();
Thread testThread = Thread.currentThread();
@@ -107,10 +177,10 @@
runUtil.allowInterrupt(true);
timer.start();
try {
- mProcess.waitForProcess(100);
+ mProcessHelper.waitForProcess(100);
fail();
} catch (RunInterruptedException e) {
- assertTrue(mProcess.isRunning());
+ assertTrue(mProcessHelper.isRunning());
} finally {
timer.join(1000);
}
diff --git a/harnesses/tradefed/tests/src/com/android/tradefed/util/VtsPythonRunnerHelperTest.java b/harnesses/tradefed/tests/src/com/android/tradefed/util/VtsPythonRunnerHelperTest.java
new file mode 100644
index 0000000..875ca79
--- /dev/null
+++ b/harnesses/tradefed/tests/src/com/android/tradefed/util/VtsPythonRunnerHelperTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package com.android.tradefed.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tradefed.build.IFolderBuildInfo;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.EnvUtil;
+import com.android.tradefed.util.IRunUtil;
+import com.android.tradefed.util.ProcessHelper;
+import com.android.tradefed.util.RunInterruptedException;
+import com.android.tradefed.util.VtsPythonRunnerHelper;
+import java.io.File;
+import java.io.IOException;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit tests for {@link VtsPythonRunnerHelper}.
+ */
+@RunWith(JUnit4.class)
+public class VtsPythonRunnerHelperTest {
+ private static final String[] mPythonCmd = {"python"};
+ private static final long mTestTimeout = 1000 * 5;
+
+ private ProcessHelper mProcessHelper = null;
+ private VtsPythonRunnerHelper mVtsPythonRunnerHelper = null;
+ private String mVirtualenvPath = "virtualenv_path_" + System.currentTimeMillis();
+
+ @Before
+ public void setUp() throws Exception {
+ IFolderBuildInfo buildInfo = EasyMock.createNiceMock(IFolderBuildInfo.class);
+ EasyMock.replay(buildInfo);
+ mVtsPythonRunnerHelper = new VtsPythonRunnerHelper(new File(mVirtualenvPath)) {
+ @Override
+ protected ProcessHelper createProcessHelper(String[] cmd) {
+ return mProcessHelper;
+ }
+ };
+ }
+
+ /**
+ * Create a process helper which mocks status of a running process.
+ */
+ private static ProcessHelper createMockProcessHelper(
+ CommandStatus status, boolean interrupted, boolean keepRunning) {
+ Process process;
+ try {
+ process = new ProcessBuilder("true").start();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return new ProcessHelper(process) {
+ @Override
+ public CommandStatus waitForProcess(long timeoutMsecs) throws RunInterruptedException {
+ if (interrupted) {
+ throw new RunInterruptedException();
+ }
+ return status;
+ }
+
+ @Override
+ public boolean isRunning() {
+ return keepRunning;
+ }
+ };
+ }
+
+ private static ProcessHelper createMockProcessHelper(
+ CommandStatus status, boolean interrupted) {
+ return createMockProcessHelper(status, interrupted, /*keepRunning=*/false);
+ }
+
+ private static ProcessHelper createMockProcessHelper(CommandStatus status) {
+ return createMockProcessHelper(status, /*interrupted=*/false, /*keepRunning=*/false);
+ }
+
+ /**
+ * Create a mock runUtil with returns the expected results.
+ */
+ private IRunUtil createMockRunUtil() {
+ IRunUtil runUtil = new RunUtil() {
+ private String path = null;
+
+ @Override
+ public void setEnvVariable(String key, String value) {
+ super.setEnvVariable(key, value);
+ if (key.equals("PATH")) {
+ path = value;
+ }
+ }
+
+ @Override
+ public CommandResult runTimedCmd(final long timeout, final String... command) {
+ CommandResult cmdRes = new CommandResult(CommandStatus.SUCCESS);
+ String out = "";
+ if (command.length == 2 && command[0].equals("which")
+ && command[1].equals("python")) {
+ if (path != null) {
+ out = path.split(":")[0] + "/python";
+ } else {
+ out = "/usr/bin/python";
+ }
+ }
+ cmdRes.setStdout(out);
+ return cmdRes;
+ }
+ };
+ return runUtil;
+ }
+
+ @Test
+ public void testProcessRunSuccess() {
+ CommandResult commandResult = new CommandResult();
+ mProcessHelper = createMockProcessHelper(CommandStatus.SUCCESS);
+ String interruptMessage =
+ mVtsPythonRunnerHelper.runPythonRunner(mPythonCmd, commandResult, mTestTimeout);
+ assertEquals(interruptMessage, null);
+ assertEquals(commandResult.getStatus(), CommandStatus.SUCCESS);
+ }
+
+ @Test
+ public void testProcessRunFailed() {
+ CommandResult commandResult = new CommandResult();
+ mProcessHelper = createMockProcessHelper(CommandStatus.FAILED);
+ String interruptMessage =
+ mVtsPythonRunnerHelper.runPythonRunner(mPythonCmd, commandResult, mTestTimeout);
+ assertEquals(interruptMessage, null);
+ assertEquals(commandResult.getStatus(), CommandStatus.FAILED);
+ }
+
+ @Test
+ public void testProcessRunTimeout() {
+ CommandResult commandResult = new CommandResult();
+ mProcessHelper = createMockProcessHelper(CommandStatus.TIMED_OUT);
+ String interruptMessage =
+ mVtsPythonRunnerHelper.runPythonRunner(mPythonCmd, commandResult, mTestTimeout);
+ assertEquals(interruptMessage, null);
+ assertEquals(commandResult.getStatus(), CommandStatus.TIMED_OUT);
+ }
+
+ @Test
+ public void testProcessRunInterrupted() {
+ CommandResult commandResult = new CommandResult();
+ mProcessHelper = createMockProcessHelper(null, /*interrupted=*/true);
+ String interruptMessage =
+ mVtsPythonRunnerHelper.runPythonRunner(mPythonCmd, commandResult, mTestTimeout);
+ assertNotEquals(interruptMessage, null);
+ assertEquals(commandResult.getStatus(), CommandStatus.TIMED_OUT);
+ }
+
+ @Test
+ public void testActivateVirtualEnvNotExist() {
+ IRunUtil runUtil = createMockRunUtil();
+ assertEquals(null, VtsPythonRunnerHelper.getPythonBinDir(mVirtualenvPath));
+ VtsPythonRunnerHelper.activateVirtualenv(runUtil, mVirtualenvPath);
+ String pythonBinary = runUtil.runTimedCmd(1000, "which", "python").getStdout();
+ assertEquals(pythonBinary, "/usr/bin/python");
+ }
+
+ @Test
+ public void testActivateVirtualEnvExist() {
+ IRunUtil runUtil = createMockRunUtil();
+ String binDirName = EnvUtil.isOnWindows() ? "Scripts" : "bin";
+ File envDir = new File(mVirtualenvPath);
+ File binDir = new File(mVirtualenvPath, binDirName);
+ try {
+ System.out.println(envDir.mkdir());
+ System.out.println(binDir.mkdir());
+ System.out.println(binDir.exists());
+ assertEquals(binDir.getAbsolutePath(),
+ VtsPythonRunnerHelper.getPythonBinDir(mVirtualenvPath));
+ VtsPythonRunnerHelper.activateVirtualenv(runUtil, mVirtualenvPath);
+ String pythonBinary = runUtil.runTimedCmd(1000, "which", "python").getStdout();
+ assertEquals(pythonBinary, new File(binDir, "python").getAbsolutePath());
+ } finally {
+ binDir.delete();
+ envDir.delete();
+ }
+ }
+
+}
diff --git a/proto/ComponentSpecificationMessage.proto b/proto/ComponentSpecificationMessage.proto
index 4375405..5ccc88b 100644
--- a/proto/ComponentSpecificationMessage.proto
+++ b/proto/ComponentSpecificationMessage.proto
@@ -188,11 +188,14 @@
// Component type, e.g., BLUETOOTH, used for Conventional HAL only.
optional ComponentType component_type = 22;
// Component version (e.g., 1.0).
- optional bytes component_type_version = 23;
+ optional bytes component_type_version = 23 [deprecated = true];
// Component name (e.g., INfc), used for HIDL HALs only.
optional bytes component_name = 24;
// Component package name (e.g., android.hardware.nfc).
optional bytes package_name = 25;
+ // Component major and minor versions stored separately.
+ optional uint32 component_type_version_major = 26;
+ optional uint32 component_type_version_minor = 27;
// Specifies API function and inputs.
optional FunctionSpecificationMessage api = 100;
diff --git a/proto/ComponentSpecificationMessage_pb2.py b/proto/ComponentSpecificationMessage_pb2.py
index edff528..28520b4 100644
--- a/proto/ComponentSpecificationMessage_pb2.py
+++ b/proto/ComponentSpecificationMessage_pb2.py
@@ -14,7 +14,7 @@
DESCRIPTOR = _descriptor.FileDescriptor(
name='ComponentSpecificationMessage.proto',
package='android.vts',
- serialized_pb='\n#ComponentSpecificationMessage.proto\x12\x0b\x61ndroid.vts\"e\n\x1c\x43\x61llFlowSpecificationMessage\x12\x14\n\x05\x65ntry\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04\x65xit\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x0c\n\x04next\x18\x0b \x03(\x0c\x12\x0c\n\x04prev\x18\x0c \x03(\x0c\"C\n NativeCodeCoverageRawDataMessage\x12\x11\n\tfile_path\x18\x01 \x01(\x0c\x12\x0c\n\x04gcda\x18\x0b \x01(\x0c\"\xbd\x02\n\x13\x46unctionCallMessage\x12\x1b\n\x13hidl_interface_name\x18\x01 \x01(\x0c\x12\x19\n\rhal_driver_id\x18\x0b \x01(\x05:\x02-1\x12\x34\n\x0f\x63omponent_class\x18\x15 \x01(\x0e\x32\x1b.android.vts.ComponentClass\x12\x32\n\x0e\x63omponent_type\x18\x16 \x01(\x0e\x32\x1a.android.vts.ComponentType\x12\x1e\n\x16\x63omponent_type_version\x18\x17 \x01(\x0c\x12\x16\n\x0e\x63omponent_name\x18\x18 \x01(\x0c\x12\x14\n\x0cpackage_name\x18\x19 \x01(\x0c\x12\x36\n\x03\x61pi\x18\x64 \x01(\x0b\x32).android.vts.FunctionSpecificationMessage\"\xde\x05\n\x1c\x46unctionSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x16\n\x0esubmodule_name\x18\x02 \x01(\x0c\x12\x19\n\x11hidl_interface_id\x18\x03 \x01(\x05\x12>\n\x0breturn_type\x18\x0b \x01(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x43\n\x10return_type_hidl\x18\x0c \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12N\n\x1areturn_type_submodule_spec\x18\r \x01(\x0b\x32*.android.vts.ComponentSpecificationMessage\x12\x36\n\x03\x61rg\x18\x15 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12;\n\x08\x63\x61llflow\x18\x1f \x03(\x0b\x32).android.vts.CallFlowSpecificationMessage\x12\x1a\n\x0b\x64o_not_fuzz\x18 \x01(\x08:\x05\x66\x61lse\x12\x17\n\x0bis_callback\x18) \x01(\x08\x42\x02\x18\x01\x12J\n\x10\x66unction_pointer\x18* \x01(\x0b\x32\x30.android.vts.FunctionPointerSpecificationMessage\x12\x16\n\x0eprofiling_data\x18\x65 \x03(\x02\x12 \n\x17processed_coverage_data\x18\xc9\x01 \x03(\r\x12I\n\x11raw_coverage_data\x18\xca\x01 \x03(\x0b\x32-.android.vts.NativeCodeCoverageRawDataMessage\x12\x14\n\x0bparent_path\x18\xad\x02 \x01(\x0c\x12\x17\n\x0esyscall_number\x18\x91\x03 \x01(\r\"\xf5\x02\n\x16ScalarDataValueMessage\x12\x0e\n\x06\x62ool_t\x18\x01 \x01(\x08\x12\x0e\n\x06int8_t\x18\x0b \x01(\x05\x12\x0f\n\x07uint8_t\x18\x0c \x01(\r\x12\x0c\n\x04\x63har\x18\r \x01(\x05\x12\r\n\x05uchar\x18\x0e \x01(\r\x12\x0f\n\x07int16_t\x18\x15 \x01(\x05\x12\x10\n\x08uint16_t\x18\x16 \x01(\r\x12\x0f\n\x07int32_t\x18\x1f \x01(\x05\x12\x10\n\x08uint32_t\x18 \x01(\r\x12\x0f\n\x07int64_t\x18) \x01(\x03\x12\x10\n\x08uint64_t\x18* \x01(\x04\x12\x0f\n\x07\x66loat_t\x18\x65 \x01(\x02\x12\x10\n\x08\x64ouble_t\x18\x66 \x01(\x01\x12\x10\n\x07pointer\x18\xc9\x01 \x01(\r\x12\x0f\n\x06opaque\x18\xca\x01 \x01(\r\x12\x15\n\x0cvoid_pointer\x18\xd3\x01 \x01(\r\x12\x15\n\x0c\x63har_pointer\x18\xd4\x01 \x01(\r\x12\x16\n\ruchar_pointer\x18\xd5\x01 \x01(\r\x12\x18\n\x0fpointer_pointer\x18\xfb\x01 \x01(\r\"\xd1\x01\n#FunctionPointerSpecificationMessage\x12\x15\n\rfunction_name\x18\x01 \x01(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x0b \x01(\r\x12\n\n\x02id\x18\x15 \x01(\x0c\x12\x36\n\x03\x61rg\x18\x65 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12>\n\x0breturn_type\x18o \x01(\x0b\x32).android.vts.VariableSpecificationMessage\"9\n\x16StringDataValueMessage\x12\x0f\n\x07message\x18\x01 \x01(\x0c\x12\x0e\n\x06length\x18\x0b \x01(\r\"z\n\x14\x45numDataValueMessage\x12\x12\n\nenumerator\x18\x01 \x03(\x0c\x12\x39\n\x0cscalar_value\x18\x02 \x03(\x0b\x32#.android.vts.ScalarDataValueMessage\x12\x13\n\x0bscalar_type\x18\x03 \x01(\x0c\"8\n\x16MemoryDataValueMessage\x12\x0c\n\x04size\x18\x01 \x01(\x03\x12\x10\n\x08\x63ontents\x18\x02 \x01(\x0c\"\x93\x01\n\tFdMessage\x12!\n\x04type\x18\x01 \x01(\x0e\x32\x13.android.vts.FdType\x12\x0c\n\x04mode\x18\x02 \x01(\r\x12\r\n\x05\x66lags\x18\x03 \x01(\x05\x12\x11\n\tfile_name\x18\x04 \x01(\x0c\x12\x33\n\x06memory\x18\x06 \x01(\x0b\x32#.android.vts.MemoryDataValueMessage\"\x85\x01\n\x16HandleDataValueMessage\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12\x0f\n\x07num_fds\x18\x02 \x01(\x05\x12\x10\n\x08num_ints\x18\x03 \x01(\x05\x12&\n\x06\x66\x64_val\x18\x04 \x03(\x0b\x32\x16.android.vts.FdMessage\x12\x0f\n\x07int_val\x18\x05 \x03(\x05\"\xc3\t\n\x1cVariableSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\'\n\x04type\x18\x02 \x01(\x0e\x32\x19.android.vts.VariableType\x12\x39\n\x0cscalar_value\x18\x65 \x01(\x0b\x32#.android.vts.ScalarDataValueMessage\x12\x13\n\x0bscalar_type\x18\x66 \x01(\x0c\x12\x39\n\x0cstring_value\x18o \x01(\x0b\x32#.android.vts.StringDataValueMessage\x12\x35\n\nenum_value\x18y \x01(\x0b\x32!.android.vts.EnumDataValueMessage\x12@\n\x0cvector_value\x18\x83\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x14\n\x0bvector_size\x18\x84\x01 \x01(\x05\x12@\n\x0cstruct_value\x18\x8d\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x14\n\x0bstruct_type\x18\x8e\x01 \x01(\x0c\x12>\n\nsub_struct\x18\x8f\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12?\n\x0bunion_value\x18\x97\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x13\n\nunion_type\x18\x98\x01 \x01(\x0c\x12=\n\tsub_union\x18\x99\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12=\n\tfmq_value\x18\xa1\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12=\n\tref_value\x18\xab\x01 \x01(\x0b\x32).android.vts.VariableSpecificationMessage\x12?\n\x11hidl_memory_value\x18\xac\x01 \x01(\x0b\x32#.android.vts.MemoryDataValueMessage\x12:\n\x0chandle_value\x18\xb5\x01 \x01(\x0b\x32#.android.vts.HandleDataValueMessage\x12\x18\n\x0fpredefined_type\x18\xc9\x01 \x01(\x0c\x12K\n\x10\x66unction_pointer\x18\xdd\x01 \x03(\x0b\x32\x30.android.vts.FunctionPointerSpecificationMessage\x12\x1b\n\x12hidl_callback_type\x18\xe7\x01 \x01(\x0c\x12\x1a\n\x11hidl_interface_id\x18\xf1\x01 \x01(\x05\x12\x1f\n\x16hidl_interface_pointer\x18\xf2\x01 \x01(\x04\x12\x17\n\x08is_input\x18\xad\x02 \x01(\x08:\x04true\x12\x19\n\tis_output\x18\xae\x02 \x01(\x08:\x05\x66\x61lse\x12\x18\n\x08is_const\x18\xaf\x02 \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0bis_callback\x18\xb0\x02 \x01(\x08:\x05\x66\x61lse\"\xfb\x01\n\x1aStructSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x19\n\nis_pointer\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x37\n\x03\x61pi\x18\xe9\x07 \x03(\x0b\x32).android.vts.FunctionSpecificationMessage\x12<\n\nsub_struct\x18\xd1\x0f \x03(\x0b\x32\'.android.vts.StructSpecificationMessage\x12=\n\tattribute\x18\xb9\x17 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\"\xf6\x01\n\x1dInterfaceSpecificationMessage\x12\x1f\n\x10is_hidl_callback\x18\x65 \x01(\x08:\x05\x66\x61lse\x12\x37\n\x03\x61pi\x18\xd1\x0f \x03(\x0b\x32).android.vts.FunctionSpecificationMessage\x12=\n\tattribute\x18\xb9\x17 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12<\n\nsub_struct\x18\xa1\x1f \x03(\x0b\x32\'.android.vts.StructSpecificationMessage\"\xca\x03\n\x1d\x43omponentSpecificationMessage\x12\x34\n\x0f\x63omponent_class\x18\x01 \x01(\x0e\x32\x1b.android.vts.ComponentClass\x12\x32\n\x0e\x63omponent_type\x18\x02 \x01(\x0e\x32\x1a.android.vts.ComponentType\x12!\n\x16\x63omponent_type_version\x18\x03 \x01(\x02:\x01\x31\x12\x16\n\x0e\x63omponent_name\x18\x04 \x01(\x0c\x12,\n\x0btarget_arch\x18\x05 \x01(\x0e\x32\x17.android.vts.TargetArch\x12\x0f\n\x07package\x18\x0b \x01(\x0c\x12\x0e\n\x06import\x18\x0c \x03(\x0c\x12%\n\x1coriginal_data_structure_name\x18\xe9\x07 \x01(\x0c\x12\x0f\n\x06header\x18\xea\x07 \x03(\x0c\x12>\n\tinterface\x18\xd1\x0f \x01(\x0b\x32*.android.vts.InterfaceSpecificationMessage\x12=\n\tattribute\x18\xb5\x10 \x03(\x0b\x32).android.vts.VariableSpecificationMessage*\xc9\x01\n\x0e\x43omponentClass\x12\x11\n\rUNKNOWN_CLASS\x10\x00\x12\x14\n\x10HAL_CONVENTIONAL\x10\x01\x12\x1e\n\x1aHAL_CONVENTIONAL_SUBMODULE\x10\x02\x12\x0e\n\nHAL_LEGACY\x10\x03\x12\x0c\n\x08HAL_HIDL\x10\x04\x12!\n\x1dHAL_HIDL_WRAPPED_CONVENTIONAL\x10\x05\x12\x0e\n\nLIB_SHARED\x10\x0b\x12\n\n\x06KERNEL\x10\x15\x12\x11\n\rKERNEL_MODULE\x10\x16*\xa8\x03\n\rComponentType\x12\x10\n\x0cUNKNOWN_TYPE\x10\x00\x12\t\n\x05\x41UDIO\x10\x01\x12\n\n\x06\x43\x41MERA\x10\x02\x12\x07\n\x03GPS\x10\x03\x12\t\n\x05LIGHT\x10\x04\x12\x08\n\x04WIFI\x10\x05\x12\n\n\x06MOBILE\x10\x06\x12\r\n\tBLUETOOTH\x10\x07\x12\x07\n\x03NFC\x10\x08\x12\t\n\x05POWER\x10\t\x12\x0c\n\x08MEMTRACK\x10\n\x12\x07\n\x03\x42\x46P\x10\x0b\x12\x0c\n\x08VIBRATOR\x10\x0c\x12\x0b\n\x07THERMAL\x10\r\x12\x0c\n\x08TV_INPUT\x10\x0e\x12\n\n\x06TV_CEC\x10\x0f\x12\x0b\n\x07SENSORS\x10\x10\x12\x0b\n\x07VEHICLE\x10\x11\x12\x06\n\x02VR\x10\x12\x12\x16\n\x12GRAPHICS_ALLOCATOR\x10\x13\x12\x13\n\x0fGRAPHICS_MAPPER\x10\x14\x12\t\n\x05RADIO\x10\x15\x12\x0e\n\nCONTEXTHUB\x10\x16\x12\x15\n\x11GRAPHICS_COMPOSER\x10\x17\x12\r\n\tMEDIA_OMX\x10\x18\x12\x10\n\x0b\x42IONIC_LIBM\x10\xe9\x07\x12\x10\n\x0b\x42IONIC_LIBC\x10\xea\x07\x12\x13\n\x0eVNDK_LIBCUTILS\x10\xcd\x08\x12\x0c\n\x07SYSCALL\x10\xd1\x0f*\x9e\x03\n\x0cVariableType\x12\x19\n\x15UNKNOWN_VARIABLE_TYPE\x10\x00\x12\x13\n\x0fTYPE_PREDEFINED\x10\x01\x12\x0f\n\x0bTYPE_SCALAR\x10\x02\x12\x0f\n\x0bTYPE_STRING\x10\x03\x12\r\n\tTYPE_ENUM\x10\x04\x12\x0e\n\nTYPE_ARRAY\x10\x05\x12\x0f\n\x0bTYPE_VECTOR\x10\x06\x12\x0f\n\x0bTYPE_STRUCT\x10\x07\x12\x19\n\x15TYPE_FUNCTION_POINTER\x10\x08\x12\r\n\tTYPE_VOID\x10\t\x12\x16\n\x12TYPE_HIDL_CALLBACK\x10\n\x12\x12\n\x0eTYPE_SUBMODULE\x10\x0b\x12\x0e\n\nTYPE_UNION\x10\x0c\x12\x17\n\x13TYPE_HIDL_INTERFACE\x10\r\x12\x0f\n\x0bTYPE_HANDLE\x10\x0e\x12\r\n\tTYPE_MASK\x10\x0f\x12\x14\n\x10TYPE_HIDL_MEMORY\x10\x10\x12\x10\n\x0cTYPE_POINTER\x10\x11\x12\x11\n\rTYPE_FMQ_SYNC\x10\x12\x12\x13\n\x0fTYPE_FMQ_UNSYNC\x10\x13\x12\x0c\n\x08TYPE_REF\x10\x14*Q\n\nTargetArch\x12\x17\n\x13UNKNOWN_TARGET_ARCH\x10\x00\x12\x13\n\x0fTARGET_ARCH_ARM\x10\x01\x12\x15\n\x11TARGET_ARCH_ARM64\x10\x02*b\n\x06\x46\x64Type\x12\r\n\tFILE_TYPE\x10\x01\x12\x0c\n\x08\x44IR_TYPE\x10\x02\x12\x0c\n\x08\x44\x45V_TYPE\x10\x03\x12\r\n\tPIPE_TYPE\x10\x04\x12\x0f\n\x0bSOCKET_TYPE\x10\x05\x12\r\n\tLINK_TYPE\x10\x06\x42\x39\n\x15\x63om.android.vts.protoB VtsComponentSpecificationMessage')
+ serialized_pb='\n#ComponentSpecificationMessage.proto\x12\x0b\x61ndroid.vts\"e\n\x1c\x43\x61llFlowSpecificationMessage\x12\x14\n\x05\x65ntry\x18\x01 \x01(\x08:\x05\x66\x61lse\x12\x13\n\x04\x65xit\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x0c\n\x04next\x18\x0b \x03(\x0c\x12\x0c\n\x04prev\x18\x0c \x03(\x0c\"C\n NativeCodeCoverageRawDataMessage\x12\x11\n\tfile_path\x18\x01 \x01(\x0c\x12\x0c\n\x04gcda\x18\x0b \x01(\x0c\"\x8d\x03\n\x13\x46unctionCallMessage\x12\x1b\n\x13hidl_interface_name\x18\x01 \x01(\x0c\x12\x19\n\rhal_driver_id\x18\x0b \x01(\x05:\x02-1\x12\x34\n\x0f\x63omponent_class\x18\x15 \x01(\x0e\x32\x1b.android.vts.ComponentClass\x12\x32\n\x0e\x63omponent_type\x18\x16 \x01(\x0e\x32\x1a.android.vts.ComponentType\x12\"\n\x16\x63omponent_type_version\x18\x17 \x01(\x0c\x42\x02\x18\x01\x12\x16\n\x0e\x63omponent_name\x18\x18 \x01(\x0c\x12\x14\n\x0cpackage_name\x18\x19 \x01(\x0c\x12$\n\x1c\x63omponent_type_version_major\x18\x1a \x01(\r\x12$\n\x1c\x63omponent_type_version_minor\x18\x1b \x01(\r\x12\x36\n\x03\x61pi\x18\x64 \x01(\x0b\x32).android.vts.FunctionSpecificationMessage\"\xde\x05\n\x1c\x46unctionSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x16\n\x0esubmodule_name\x18\x02 \x01(\x0c\x12\x19\n\x11hidl_interface_id\x18\x03 \x01(\x05\x12>\n\x0breturn_type\x18\x0b \x01(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x43\n\x10return_type_hidl\x18\x0c \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12N\n\x1areturn_type_submodule_spec\x18\r \x01(\x0b\x32*.android.vts.ComponentSpecificationMessage\x12\x36\n\x03\x61rg\x18\x15 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12;\n\x08\x63\x61llflow\x18\x1f \x03(\x0b\x32).android.vts.CallFlowSpecificationMessage\x12\x1a\n\x0b\x64o_not_fuzz\x18 \x01(\x08:\x05\x66\x61lse\x12\x17\n\x0bis_callback\x18) \x01(\x08\x42\x02\x18\x01\x12J\n\x10\x66unction_pointer\x18* \x01(\x0b\x32\x30.android.vts.FunctionPointerSpecificationMessage\x12\x16\n\x0eprofiling_data\x18\x65 \x03(\x02\x12 \n\x17processed_coverage_data\x18\xc9\x01 \x03(\r\x12I\n\x11raw_coverage_data\x18\xca\x01 \x03(\x0b\x32-.android.vts.NativeCodeCoverageRawDataMessage\x12\x14\n\x0bparent_path\x18\xad\x02 \x01(\x0c\x12\x17\n\x0esyscall_number\x18\x91\x03 \x01(\r\"\xf5\x02\n\x16ScalarDataValueMessage\x12\x0e\n\x06\x62ool_t\x18\x01 \x01(\x08\x12\x0e\n\x06int8_t\x18\x0b \x01(\x05\x12\x0f\n\x07uint8_t\x18\x0c \x01(\r\x12\x0c\n\x04\x63har\x18\r \x01(\x05\x12\r\n\x05uchar\x18\x0e \x01(\r\x12\x0f\n\x07int16_t\x18\x15 \x01(\x05\x12\x10\n\x08uint16_t\x18\x16 \x01(\r\x12\x0f\n\x07int32_t\x18\x1f \x01(\x05\x12\x10\n\x08uint32_t\x18 \x01(\r\x12\x0f\n\x07int64_t\x18) \x01(\x03\x12\x10\n\x08uint64_t\x18* \x01(\x04\x12\x0f\n\x07\x66loat_t\x18\x65 \x01(\x02\x12\x10\n\x08\x64ouble_t\x18\x66 \x01(\x01\x12\x10\n\x07pointer\x18\xc9\x01 \x01(\r\x12\x0f\n\x06opaque\x18\xca\x01 \x01(\r\x12\x15\n\x0cvoid_pointer\x18\xd3\x01 \x01(\r\x12\x15\n\x0c\x63har_pointer\x18\xd4\x01 \x01(\r\x12\x16\n\ruchar_pointer\x18\xd5\x01 \x01(\r\x12\x18\n\x0fpointer_pointer\x18\xfb\x01 \x01(\r\"\xd1\x01\n#FunctionPointerSpecificationMessage\x12\x15\n\rfunction_name\x18\x01 \x01(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x0b \x01(\r\x12\n\n\x02id\x18\x15 \x01(\x0c\x12\x36\n\x03\x61rg\x18\x65 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12>\n\x0breturn_type\x18o \x01(\x0b\x32).android.vts.VariableSpecificationMessage\"9\n\x16StringDataValueMessage\x12\x0f\n\x07message\x18\x01 \x01(\x0c\x12\x0e\n\x06length\x18\x0b \x01(\r\"z\n\x14\x45numDataValueMessage\x12\x12\n\nenumerator\x18\x01 \x03(\x0c\x12\x39\n\x0cscalar_value\x18\x02 \x03(\x0b\x32#.android.vts.ScalarDataValueMessage\x12\x13\n\x0bscalar_type\x18\x03 \x01(\x0c\"8\n\x16MemoryDataValueMessage\x12\x0c\n\x04size\x18\x01 \x01(\x03\x12\x10\n\x08\x63ontents\x18\x02 \x01(\x0c\"\x93\x01\n\tFdMessage\x12!\n\x04type\x18\x01 \x01(\x0e\x32\x13.android.vts.FdType\x12\x0c\n\x04mode\x18\x02 \x01(\r\x12\r\n\x05\x66lags\x18\x03 \x01(\x05\x12\x11\n\tfile_name\x18\x04 \x01(\x0c\x12\x33\n\x06memory\x18\x06 \x01(\x0b\x32#.android.vts.MemoryDataValueMessage\"\x85\x01\n\x16HandleDataValueMessage\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12\x0f\n\x07num_fds\x18\x02 \x01(\x05\x12\x10\n\x08num_ints\x18\x03 \x01(\x05\x12&\n\x06\x66\x64_val\x18\x04 \x03(\x0b\x32\x16.android.vts.FdMessage\x12\x0f\n\x07int_val\x18\x05 \x03(\x05\"\xc3\t\n\x1cVariableSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\'\n\x04type\x18\x02 \x01(\x0e\x32\x19.android.vts.VariableType\x12\x39\n\x0cscalar_value\x18\x65 \x01(\x0b\x32#.android.vts.ScalarDataValueMessage\x12\x13\n\x0bscalar_type\x18\x66 \x01(\x0c\x12\x39\n\x0cstring_value\x18o \x01(\x0b\x32#.android.vts.StringDataValueMessage\x12\x35\n\nenum_value\x18y \x01(\x0b\x32!.android.vts.EnumDataValueMessage\x12@\n\x0cvector_value\x18\x83\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x14\n\x0bvector_size\x18\x84\x01 \x01(\x05\x12@\n\x0cstruct_value\x18\x8d\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x14\n\x0bstruct_type\x18\x8e\x01 \x01(\x0c\x12>\n\nsub_struct\x18\x8f\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12?\n\x0bunion_value\x18\x97\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12\x13\n\nunion_type\x18\x98\x01 \x01(\x0c\x12=\n\tsub_union\x18\x99\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12=\n\tfmq_value\x18\xa1\x01 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12=\n\tref_value\x18\xab\x01 \x01(\x0b\x32).android.vts.VariableSpecificationMessage\x12?\n\x11hidl_memory_value\x18\xac\x01 \x01(\x0b\x32#.android.vts.MemoryDataValueMessage\x12:\n\x0chandle_value\x18\xb5\x01 \x01(\x0b\x32#.android.vts.HandleDataValueMessage\x12\x18\n\x0fpredefined_type\x18\xc9\x01 \x01(\x0c\x12K\n\x10\x66unction_pointer\x18\xdd\x01 \x03(\x0b\x32\x30.android.vts.FunctionPointerSpecificationMessage\x12\x1b\n\x12hidl_callback_type\x18\xe7\x01 \x01(\x0c\x12\x1a\n\x11hidl_interface_id\x18\xf1\x01 \x01(\x05\x12\x1f\n\x16hidl_interface_pointer\x18\xf2\x01 \x01(\x04\x12\x17\n\x08is_input\x18\xad\x02 \x01(\x08:\x04true\x12\x19\n\tis_output\x18\xae\x02 \x01(\x08:\x05\x66\x61lse\x12\x18\n\x08is_const\x18\xaf\x02 \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0bis_callback\x18\xb0\x02 \x01(\x08:\x05\x66\x61lse\"\xfb\x01\n\x1aStructSpecificationMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x19\n\nis_pointer\x18\x02 \x01(\x08:\x05\x66\x61lse\x12\x37\n\x03\x61pi\x18\xe9\x07 \x03(\x0b\x32).android.vts.FunctionSpecificationMessage\x12<\n\nsub_struct\x18\xd1\x0f \x03(\x0b\x32\'.android.vts.StructSpecificationMessage\x12=\n\tattribute\x18\xb9\x17 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\"\xf6\x01\n\x1dInterfaceSpecificationMessage\x12\x1f\n\x10is_hidl_callback\x18\x65 \x01(\x08:\x05\x66\x61lse\x12\x37\n\x03\x61pi\x18\xd1\x0f \x03(\x0b\x32).android.vts.FunctionSpecificationMessage\x12=\n\tattribute\x18\xb9\x17 \x03(\x0b\x32).android.vts.VariableSpecificationMessage\x12<\n\nsub_struct\x18\xa1\x1f \x03(\x0b\x32\'.android.vts.StructSpecificationMessage\"\xca\x03\n\x1d\x43omponentSpecificationMessage\x12\x34\n\x0f\x63omponent_class\x18\x01 \x01(\x0e\x32\x1b.android.vts.ComponentClass\x12\x32\n\x0e\x63omponent_type\x18\x02 \x01(\x0e\x32\x1a.android.vts.ComponentType\x12!\n\x16\x63omponent_type_version\x18\x03 \x01(\x02:\x01\x31\x12\x16\n\x0e\x63omponent_name\x18\x04 \x01(\x0c\x12,\n\x0btarget_arch\x18\x05 \x01(\x0e\x32\x17.android.vts.TargetArch\x12\x0f\n\x07package\x18\x0b \x01(\x0c\x12\x0e\n\x06import\x18\x0c \x03(\x0c\x12%\n\x1coriginal_data_structure_name\x18\xe9\x07 \x01(\x0c\x12\x0f\n\x06header\x18\xea\x07 \x03(\x0c\x12>\n\tinterface\x18\xd1\x0f \x01(\x0b\x32*.android.vts.InterfaceSpecificationMessage\x12=\n\tattribute\x18\xb5\x10 \x03(\x0b\x32).android.vts.VariableSpecificationMessage*\xc9\x01\n\x0e\x43omponentClass\x12\x11\n\rUNKNOWN_CLASS\x10\x00\x12\x14\n\x10HAL_CONVENTIONAL\x10\x01\x12\x1e\n\x1aHAL_CONVENTIONAL_SUBMODULE\x10\x02\x12\x0e\n\nHAL_LEGACY\x10\x03\x12\x0c\n\x08HAL_HIDL\x10\x04\x12!\n\x1dHAL_HIDL_WRAPPED_CONVENTIONAL\x10\x05\x12\x0e\n\nLIB_SHARED\x10\x0b\x12\n\n\x06KERNEL\x10\x15\x12\x11\n\rKERNEL_MODULE\x10\x16*\xa8\x03\n\rComponentType\x12\x10\n\x0cUNKNOWN_TYPE\x10\x00\x12\t\n\x05\x41UDIO\x10\x01\x12\n\n\x06\x43\x41MERA\x10\x02\x12\x07\n\x03GPS\x10\x03\x12\t\n\x05LIGHT\x10\x04\x12\x08\n\x04WIFI\x10\x05\x12\n\n\x06MOBILE\x10\x06\x12\r\n\tBLUETOOTH\x10\x07\x12\x07\n\x03NFC\x10\x08\x12\t\n\x05POWER\x10\t\x12\x0c\n\x08MEMTRACK\x10\n\x12\x07\n\x03\x42\x46P\x10\x0b\x12\x0c\n\x08VIBRATOR\x10\x0c\x12\x0b\n\x07THERMAL\x10\r\x12\x0c\n\x08TV_INPUT\x10\x0e\x12\n\n\x06TV_CEC\x10\x0f\x12\x0b\n\x07SENSORS\x10\x10\x12\x0b\n\x07VEHICLE\x10\x11\x12\x06\n\x02VR\x10\x12\x12\x16\n\x12GRAPHICS_ALLOCATOR\x10\x13\x12\x13\n\x0fGRAPHICS_MAPPER\x10\x14\x12\t\n\x05RADIO\x10\x15\x12\x0e\n\nCONTEXTHUB\x10\x16\x12\x15\n\x11GRAPHICS_COMPOSER\x10\x17\x12\r\n\tMEDIA_OMX\x10\x18\x12\x10\n\x0b\x42IONIC_LIBM\x10\xe9\x07\x12\x10\n\x0b\x42IONIC_LIBC\x10\xea\x07\x12\x13\n\x0eVNDK_LIBCUTILS\x10\xcd\x08\x12\x0c\n\x07SYSCALL\x10\xd1\x0f*\x9e\x03\n\x0cVariableType\x12\x19\n\x15UNKNOWN_VARIABLE_TYPE\x10\x00\x12\x13\n\x0fTYPE_PREDEFINED\x10\x01\x12\x0f\n\x0bTYPE_SCALAR\x10\x02\x12\x0f\n\x0bTYPE_STRING\x10\x03\x12\r\n\tTYPE_ENUM\x10\x04\x12\x0e\n\nTYPE_ARRAY\x10\x05\x12\x0f\n\x0bTYPE_VECTOR\x10\x06\x12\x0f\n\x0bTYPE_STRUCT\x10\x07\x12\x19\n\x15TYPE_FUNCTION_POINTER\x10\x08\x12\r\n\tTYPE_VOID\x10\t\x12\x16\n\x12TYPE_HIDL_CALLBACK\x10\n\x12\x12\n\x0eTYPE_SUBMODULE\x10\x0b\x12\x0e\n\nTYPE_UNION\x10\x0c\x12\x17\n\x13TYPE_HIDL_INTERFACE\x10\r\x12\x0f\n\x0bTYPE_HANDLE\x10\x0e\x12\r\n\tTYPE_MASK\x10\x0f\x12\x14\n\x10TYPE_HIDL_MEMORY\x10\x10\x12\x10\n\x0cTYPE_POINTER\x10\x11\x12\x11\n\rTYPE_FMQ_SYNC\x10\x12\x12\x13\n\x0fTYPE_FMQ_UNSYNC\x10\x13\x12\x0c\n\x08TYPE_REF\x10\x14*Q\n\nTargetArch\x12\x17\n\x13UNKNOWN_TARGET_ARCH\x10\x00\x12\x13\n\x0fTARGET_ARCH_ARM\x10\x01\x12\x15\n\x11TARGET_ARCH_ARM64\x10\x02*b\n\x06\x46\x64Type\x12\r\n\tFILE_TYPE\x10\x01\x12\x0c\n\x08\x44IR_TYPE\x10\x02\x12\x0c\n\x08\x44\x45V_TYPE\x10\x03\x12\r\n\tPIPE_TYPE\x10\x04\x12\x0f\n\x0bSOCKET_TYPE\x10\x05\x12\r\n\tLINK_TYPE\x10\x06\x42\x39\n\x15\x63om.android.vts.protoB VtsComponentSpecificationMessage')
_COMPONENTCLASS = _descriptor.EnumDescriptor(
name='ComponentClass',
@@ -61,8 +61,8 @@
],
containing_type=None,
options=None,
- serialized_start=4583,
- serialized_end=4784,
+ serialized_start=4663,
+ serialized_end=4864,
)
ComponentClass = enum_type_wrapper.EnumTypeWrapper(_COMPONENTCLASS)
@@ -191,8 +191,8 @@
],
containing_type=None,
options=None,
- serialized_start=4787,
- serialized_end=5211,
+ serialized_start=4867,
+ serialized_end=5291,
)
ComponentType = enum_type_wrapper.EnumTypeWrapper(_COMPONENTTYPE)
@@ -289,8 +289,8 @@
],
containing_type=None,
options=None,
- serialized_start=5214,
- serialized_end=5628,
+ serialized_start=5294,
+ serialized_end=5708,
)
VariableType = enum_type_wrapper.EnumTypeWrapper(_VARIABLETYPE)
@@ -315,8 +315,8 @@
],
containing_type=None,
options=None,
- serialized_start=5630,
- serialized_end=5711,
+ serialized_start=5710,
+ serialized_end=5791,
)
TargetArch = enum_type_wrapper.EnumTypeWrapper(_TARGETARCH)
@@ -353,8 +353,8 @@
],
containing_type=None,
options=None,
- serialized_start=5713,
- serialized_end=5811,
+ serialized_start=5793,
+ serialized_end=5891,
)
FdType = enum_type_wrapper.EnumTypeWrapper(_FDTYPE)
@@ -554,7 +554,7 @@
has_default_value=False, default_value="",
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
- options=None),
+ options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), '\030\001')),
_descriptor.FieldDescriptor(
name='component_name', full_name='android.vts.FunctionCallMessage.component_name', index=5,
number=24, type=12, cpp_type=9, label=1,
@@ -570,7 +570,21 @@
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
- name='api', full_name='android.vts.FunctionCallMessage.api', index=7,
+ name='component_type_version_major', full_name='android.vts.FunctionCallMessage.component_type_version_major', index=7,
+ number=26, type=13, cpp_type=3, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='component_type_version_minor', full_name='android.vts.FunctionCallMessage.component_type_version_minor', index=8,
+ number=27, type=13, cpp_type=3, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='api', full_name='android.vts.FunctionCallMessage.api', index=9,
number=100, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
@@ -586,7 +600,7 @@
is_extendable=False,
extension_ranges=[],
serialized_start=225,
- serialized_end=542,
+ serialized_end=622,
)
@@ -718,8 +732,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=545,
- serialized_end=1279,
+ serialized_start=625,
+ serialized_end=1359,
)
@@ -872,8 +886,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1282,
- serialized_end=1655,
+ serialized_start=1362,
+ serialized_end=1735,
)
@@ -928,8 +942,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1658,
- serialized_end=1867,
+ serialized_start=1738,
+ serialized_end=1947,
)
@@ -963,8 +977,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1869,
- serialized_end=1926,
+ serialized_start=1949,
+ serialized_end=2006,
)
@@ -1005,8 +1019,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1928,
- serialized_end=2050,
+ serialized_start=2008,
+ serialized_end=2130,
)
@@ -1040,8 +1054,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2052,
- serialized_end=2108,
+ serialized_start=2132,
+ serialized_end=2188,
)
@@ -1096,8 +1110,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2111,
- serialized_end=2258,
+ serialized_start=2191,
+ serialized_end=2338,
)
@@ -1152,8 +1166,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2261,
- serialized_end=2394,
+ serialized_start=2341,
+ serialized_end=2474,
)
@@ -1362,8 +1376,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=2397,
- serialized_end=3616,
+ serialized_start=2477,
+ serialized_end=3696,
)
@@ -1418,8 +1432,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3619,
- serialized_end=3870,
+ serialized_start=3699,
+ serialized_end=3950,
)
@@ -1467,8 +1481,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=3873,
- serialized_end=4119,
+ serialized_start=3953,
+ serialized_end=4199,
)
@@ -1565,8 +1579,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=4122,
- serialized_end=4580,
+ serialized_start=4202,
+ serialized_end=4660,
)
_FUNCTIONCALLMESSAGE.fields_by_name['component_class'].enum_type = _COMPONENTCLASS
@@ -1719,6 +1733,8 @@
DESCRIPTOR.has_options = True
DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), '\n\025com.android.vts.protoB VtsComponentSpecificationMessage')
+_FUNCTIONCALLMESSAGE.fields_by_name['component_type_version'].has_options = True
+_FUNCTIONCALLMESSAGE.fields_by_name['component_type_version']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), '\030\001')
_FUNCTIONSPECIFICATIONMESSAGE.fields_by_name['is_callback'].has_options = True
_FUNCTIONSPECIFICATIONMESSAGE.fields_by_name['is_callback']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), '\030\001')
# @@protoc_insertion_point(module_scope)
diff --git a/proto/VtsReportMessage.proto b/proto/VtsReportMessage.proto
index 3e83150..1137729 100644
--- a/proto/VtsReportMessage.proto
+++ b/proto/VtsReportMessage.proto
@@ -195,7 +195,7 @@
optional bytes revision = 13;
// i-th element gives the number of times i-th line is executed.
- repeated int32 line_coverage_vector = 23;
+ repeated int64 line_coverage_vector = 23;
// the number of source code lines that are instrumented for code coverage
// measurement.
diff --git a/proto/VtsReportMessage_pb2.py b/proto/VtsReportMessage_pb2.py
index cbfdb98..408adb1 100644
--- a/proto/VtsReportMessage_pb2.py
+++ b/proto/VtsReportMessage_pb2.py
@@ -14,7 +14,7 @@
DESCRIPTOR = _descriptor.FileDescriptor(
name='VtsReportMessage.proto',
package='android.vts',
- serialized_pb='\n\x16VtsReportMessage.proto\x12\x0b\x61ndroid.vts\"\xe0\x01\n\x18\x41ndroidDeviceInfoMessage\x12\x14\n\x0cproduct_type\x18\x01 \x01(\x0c\x12\x17\n\x0fproduct_variant\x18\x02 \x01(\x0c\x12\x14\n\x0c\x62uild_flavor\x18\x0b \x01(\x0c\x12\x10\n\x08\x62uild_id\x18\x0c \x01(\x0c\x12\x0e\n\x06\x62ranch\x18\x15 \x01(\x0c\x12\x13\n\x0b\x62uild_alias\x18\x16 \x01(\x0c\x12\x11\n\tapi_level\x18\x1f \x01(\x0c\x12\x10\n\x08\x61\x62i_name\x18\x33 \x01(\x0c\x12\x13\n\x0b\x61\x62i_bitness\x18\x34 \x01(\x0c\x12\x0e\n\x06serial\x18\x65 \x01(\x0c\"g\n\x10\x41ndroidBuildInfo\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x0b \x01(\x0c\x12\x12\n\nbuild_type\x18\x0c \x01(\x0c\x12\x0e\n\x06\x62ranch\x18\r \x01(\x0c\x12\x15\n\rbuild_summary\x18\x15 \x01(\x0c\"\x1f\n\x0bVtsHostInfo\x12\x10\n\x08hostname\x18\x01 \x01(\x0c\"\xd5\x02\n\x15TestCaseReportMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x30\n\x0btest_result\x18\x0b \x01(\x0e\x32\x1b.android.vts.TestCaseResult\x12\x17\n\x0fstart_timestamp\x18\x15 \x01(\x03\x12\x15\n\rend_timestamp\x18\x16 \x01(\x03\x12\x34\n\x08\x63overage\x18\x1f \x03(\x0b\x32\".android.vts.CoverageReportMessage\x12\x36\n\tprofiling\x18) \x03(\x0b\x32#.android.vts.ProfilingReportMessage\x12\x38\n\x08systrace\x18* \x03(\x0b\x32\".android.vts.SystraceReportMessageB\x02\x18\x01\x12$\n\x03log\x18\x65 \x03(\x0b\x32\x17.android.vts.LogMessage\"\xa0\x02\n\x16ProfilingReportMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12+\n\x04type\x18\x02 \x01(\x0e\x32\x1d.android.vts.VtsProfilingType\x12@\n\x0fregression_mode\x18\x03 \x01(\x0e\x32\'.android.vts.VtsProfilingRegressionMode\x12\x17\n\x0fstart_timestamp\x18\x0b \x01(\x03\x12\x15\n\rend_timestamp\x18\x0c \x01(\x03\x12\r\n\x05label\x18\x15 \x03(\x0c\x12\r\n\x05value\x18\x16 \x03(\x03\x12\x14\n\x0cx_axis_label\x18\x1f \x01(\x0c\x12\x14\n\x0cy_axis_label\x18 \x01(\x0c\x12\x0f\n\x07options\x18) \x03(\x0c\"H\n\x15SystraceReportMessage\x12\x14\n\x0cprocess_name\x18\x01 \x01(\x0c\x12\x0c\n\x04html\x18\x0b \x03(\x0c\x12\x0b\n\x03url\x18\x15 \x03(\x0c\"\xe5\x01\n\x15\x43overageReportMessage\x12\x11\n\tfile_path\x18\x0b \x01(\x0c\x12\x14\n\x0cproject_name\x18\x0c \x01(\x0c\x12\x10\n\x08revision\x18\r \x01(\x0c\x12\x1c\n\x14line_coverage_vector\x18\x17 \x03(\x05\x12\x18\n\x10total_line_count\x18\x65 \x01(\x05\x12\x1a\n\x12\x63overed_line_count\x18\x66 \x01(\x05\x12\x14\n\x08\x64ir_path\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x15\n\tfile_name\x18\x02 \x01(\x0c\x42\x02\x18\x01\x12\x10\n\x04html\x18\x03 \x01(\x0c\x42\x02\x18\x01\"8\n\nLogMessage\x12\x0b\n\x03url\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"@\n\x12UrlResourceMessage\x12\x0b\n\x03url\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"\x8b\x05\n\x11TestReportMessage\x12\x16\n\ntest_suite\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x0c\n\x04test\x18\x02 \x01(\x0c\x12+\n\ttest_type\x18\x03 \x01(\x0e\x32\x18.android.vts.VtsTestType\x12:\n\x0b\x64\x65vice_info\x18\x04 \x03(\x0b\x32%.android.vts.AndroidDeviceInfoMessage\x12\x31\n\nbuild_info\x18\x05 \x01(\x0b\x32\x1d.android.vts.AndroidBuildInfo\x12\x18\n\x10subscriber_email\x18\x06 \x03(\x0c\x12+\n\thost_info\x18\x07 \x01(\x0b\x32\x18.android.vts.VtsHostInfo\x12\x35\n\ttest_case\x18\x0b \x03(\x0b\x32\".android.vts.TestCaseReportMessage\x12\x36\n\tprofiling\x18\x15 \x03(\x0b\x32#.android.vts.ProfilingReportMessage\x12\x38\n\x08systrace\x18\x16 \x03(\x0b\x32\".android.vts.SystraceReportMessageB\x02\x18\x01\x12\x17\n\x0fstart_timestamp\x18\x65 \x01(\x03\x12\x15\n\rend_timestamp\x18\x66 \x01(\x03\x12\x34\n\x08\x63overage\x18g \x03(\x0b\x32\".android.vts.CoverageReportMessage\x12%\n\x03log\x18\xe9\x07 \x03(\x0b\x32\x17.android.vts.LogMessage\x12\x37\n\rlink_resource\x18\xf3\x07 \x03(\x0b\x32\x1f.android.vts.UrlResourceMessage\"\xa7\x01\n\x15TestPlanReportMessage\x12\x18\n\x10test_module_name\x18\x0b \x03(\t\x12#\n\x1btest_module_start_timestamp\x18\x0c \x03(\x03\x12\x16\n\x0etest_plan_name\x18\x15 \x01(\t\x12\x37\n\x0epartner_report\x18\x1f \x03(\x0b\x32\x1f.android.vts.UrlResourceMessage\"\x9f\x01\n\x14\x44\x61shboardPostMessage\x12\x14\n\x0c\x61\x63\x63\x65ss_token\x18\x01 \x01(\t\x12\x33\n\x0btest_report\x18\x02 \x03(\x0b\x32\x1e.android.vts.TestReportMessage\x12<\n\x10test_plan_report\x18\x03 \x03(\x0b\x32\".android.vts.TestPlanReportMessage*\xb3\x01\n\x0eTestCaseResult\x12\x12\n\x0eUNKNOWN_RESULT\x10\x00\x12\x19\n\x15TEST_CASE_RESULT_PASS\x10\x01\x12\x19\n\x15TEST_CASE_RESULT_FAIL\x10\x02\x12\x19\n\x15TEST_CASE_RESULT_SKIP\x10\x03\x12\x1e\n\x1aTEST_CASE_RESULT_EXCEPTION\x10\x04\x12\x1c\n\x18TEST_CASE_RESULT_TIMEOUT\x10\x05*\x9c\x01\n\x0bVtsTestType\x12\x18\n\x14UNKNOWN_VTS_TESTTYPE\x10\x00\x12\x1e\n\x1aVTS_HOST_DRIVEN_STRUCTURAL\x10\x01\x12\x1b\n\x17VTS_HOST_DRIVEN_FUZZING\x10\x02\x12\x19\n\x15VTS_TARGET_SIDE_GTEST\x10\x03\x12\x1b\n\x17VTS_TARGET_SIDE_FUZZING\x10\x04*\xa3\x01\n\x1aVtsProfilingRegressionMode\x12\x1b\n\x17UNKNOWN_REGRESSION_MODE\x10\x00\x12 \n\x1cVTS_REGRESSION_MODE_DISABLED\x10\x01\x12\"\n\x1eVTS_REGRESSION_MODE_INCREASING\x10\x02\x12\"\n\x1eVTS_REGRESSION_MODE_DECREASING\x10\x03*\xa4\x01\n\x10VtsProfilingType\x12\x1e\n\x1aUNKNOWN_VTS_PROFILING_TYPE\x10\x00\x12 \n\x1cVTS_PROFILING_TYPE_TIMESTAMP\x10\x01\x12%\n!VTS_PROFILING_TYPE_LABELED_VECTOR\x10\x02\x12\'\n#VTS_PROFILING_TYPE_UNLABELED_VECTOR\x10\x03\x42+\n\x15\x63om.android.vts.protoB\x10VtsReportMessageP\x00')
+ serialized_pb='\n\x16VtsReportMessage.proto\x12\x0b\x61ndroid.vts\"\xe0\x01\n\x18\x41ndroidDeviceInfoMessage\x12\x14\n\x0cproduct_type\x18\x01 \x01(\x0c\x12\x17\n\x0fproduct_variant\x18\x02 \x01(\x0c\x12\x14\n\x0c\x62uild_flavor\x18\x0b \x01(\x0c\x12\x10\n\x08\x62uild_id\x18\x0c \x01(\x0c\x12\x0e\n\x06\x62ranch\x18\x15 \x01(\x0c\x12\x13\n\x0b\x62uild_alias\x18\x16 \x01(\x0c\x12\x11\n\tapi_level\x18\x1f \x01(\x0c\x12\x10\n\x08\x61\x62i_name\x18\x33 \x01(\x0c\x12\x13\n\x0b\x61\x62i_bitness\x18\x34 \x01(\x0c\x12\x0e\n\x06serial\x18\x65 \x01(\x0c\"g\n\x10\x41ndroidBuildInfo\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x0b \x01(\x0c\x12\x12\n\nbuild_type\x18\x0c \x01(\x0c\x12\x0e\n\x06\x62ranch\x18\r \x01(\x0c\x12\x15\n\rbuild_summary\x18\x15 \x01(\x0c\"\x1f\n\x0bVtsHostInfo\x12\x10\n\x08hostname\x18\x01 \x01(\x0c\"\xd5\x02\n\x15TestCaseReportMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x30\n\x0btest_result\x18\x0b \x01(\x0e\x32\x1b.android.vts.TestCaseResult\x12\x17\n\x0fstart_timestamp\x18\x15 \x01(\x03\x12\x15\n\rend_timestamp\x18\x16 \x01(\x03\x12\x34\n\x08\x63overage\x18\x1f \x03(\x0b\x32\".android.vts.CoverageReportMessage\x12\x36\n\tprofiling\x18) \x03(\x0b\x32#.android.vts.ProfilingReportMessage\x12\x38\n\x08systrace\x18* \x03(\x0b\x32\".android.vts.SystraceReportMessageB\x02\x18\x01\x12$\n\x03log\x18\x65 \x03(\x0b\x32\x17.android.vts.LogMessage\"\xa0\x02\n\x16ProfilingReportMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12+\n\x04type\x18\x02 \x01(\x0e\x32\x1d.android.vts.VtsProfilingType\x12@\n\x0fregression_mode\x18\x03 \x01(\x0e\x32\'.android.vts.VtsProfilingRegressionMode\x12\x17\n\x0fstart_timestamp\x18\x0b \x01(\x03\x12\x15\n\rend_timestamp\x18\x0c \x01(\x03\x12\r\n\x05label\x18\x15 \x03(\x0c\x12\r\n\x05value\x18\x16 \x03(\x03\x12\x14\n\x0cx_axis_label\x18\x1f \x01(\x0c\x12\x14\n\x0cy_axis_label\x18 \x01(\x0c\x12\x0f\n\x07options\x18) \x03(\x0c\"H\n\x15SystraceReportMessage\x12\x14\n\x0cprocess_name\x18\x01 \x01(\x0c\x12\x0c\n\x04html\x18\x0b \x03(\x0c\x12\x0b\n\x03url\x18\x15 \x03(\x0c\"\xe5\x01\n\x15\x43overageReportMessage\x12\x11\n\tfile_path\x18\x0b \x01(\x0c\x12\x14\n\x0cproject_name\x18\x0c \x01(\x0c\x12\x10\n\x08revision\x18\r \x01(\x0c\x12\x1c\n\x14line_coverage_vector\x18\x17 \x03(\x03\x12\x18\n\x10total_line_count\x18\x65 \x01(\x05\x12\x1a\n\x12\x63overed_line_count\x18\x66 \x01(\x05\x12\x14\n\x08\x64ir_path\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x15\n\tfile_name\x18\x02 \x01(\x0c\x42\x02\x18\x01\x12\x10\n\x04html\x18\x03 \x01(\x0c\x42\x02\x18\x01\"8\n\nLogMessage\x12\x0b\n\x03url\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"@\n\x12UrlResourceMessage\x12\x0b\n\x03url\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"\x8b\x05\n\x11TestReportMessage\x12\x16\n\ntest_suite\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x0c\n\x04test\x18\x02 \x01(\x0c\x12+\n\ttest_type\x18\x03 \x01(\x0e\x32\x18.android.vts.VtsTestType\x12:\n\x0b\x64\x65vice_info\x18\x04 \x03(\x0b\x32%.android.vts.AndroidDeviceInfoMessage\x12\x31\n\nbuild_info\x18\x05 \x01(\x0b\x32\x1d.android.vts.AndroidBuildInfo\x12\x18\n\x10subscriber_email\x18\x06 \x03(\x0c\x12+\n\thost_info\x18\x07 \x01(\x0b\x32\x18.android.vts.VtsHostInfo\x12\x35\n\ttest_case\x18\x0b \x03(\x0b\x32\".android.vts.TestCaseReportMessage\x12\x36\n\tprofiling\x18\x15 \x03(\x0b\x32#.android.vts.ProfilingReportMessage\x12\x38\n\x08systrace\x18\x16 \x03(\x0b\x32\".android.vts.SystraceReportMessageB\x02\x18\x01\x12\x17\n\x0fstart_timestamp\x18\x65 \x01(\x03\x12\x15\n\rend_timestamp\x18\x66 \x01(\x03\x12\x34\n\x08\x63overage\x18g \x03(\x0b\x32\".android.vts.CoverageReportMessage\x12%\n\x03log\x18\xe9\x07 \x03(\x0b\x32\x17.android.vts.LogMessage\x12\x37\n\rlink_resource\x18\xf3\x07 \x03(\x0b\x32\x1f.android.vts.UrlResourceMessage\"\xa7\x01\n\x15TestPlanReportMessage\x12\x18\n\x10test_module_name\x18\x0b \x03(\t\x12#\n\x1btest_module_start_timestamp\x18\x0c \x03(\x03\x12\x16\n\x0etest_plan_name\x18\x15 \x01(\t\x12\x37\n\x0epartner_report\x18\x1f \x03(\x0b\x32\x1f.android.vts.UrlResourceMessage\"\x9f\x01\n\x14\x44\x61shboardPostMessage\x12\x14\n\x0c\x61\x63\x63\x65ss_token\x18\x01 \x01(\t\x12\x33\n\x0btest_report\x18\x02 \x03(\x0b\x32\x1e.android.vts.TestReportMessage\x12<\n\x10test_plan_report\x18\x03 \x03(\x0b\x32\".android.vts.TestPlanReportMessage*\xb3\x01\n\x0eTestCaseResult\x12\x12\n\x0eUNKNOWN_RESULT\x10\x00\x12\x19\n\x15TEST_CASE_RESULT_PASS\x10\x01\x12\x19\n\x15TEST_CASE_RESULT_FAIL\x10\x02\x12\x19\n\x15TEST_CASE_RESULT_SKIP\x10\x03\x12\x1e\n\x1aTEST_CASE_RESULT_EXCEPTION\x10\x04\x12\x1c\n\x18TEST_CASE_RESULT_TIMEOUT\x10\x05*\x9c\x01\n\x0bVtsTestType\x12\x18\n\x14UNKNOWN_VTS_TESTTYPE\x10\x00\x12\x1e\n\x1aVTS_HOST_DRIVEN_STRUCTURAL\x10\x01\x12\x1b\n\x17VTS_HOST_DRIVEN_FUZZING\x10\x02\x12\x19\n\x15VTS_TARGET_SIDE_GTEST\x10\x03\x12\x1b\n\x17VTS_TARGET_SIDE_FUZZING\x10\x04*\xa3\x01\n\x1aVtsProfilingRegressionMode\x12\x1b\n\x17UNKNOWN_REGRESSION_MODE\x10\x00\x12 \n\x1cVTS_REGRESSION_MODE_DISABLED\x10\x01\x12\"\n\x1eVTS_REGRESSION_MODE_INCREASING\x10\x02\x12\"\n\x1eVTS_REGRESSION_MODE_DECREASING\x10\x03*\xa4\x01\n\x10VtsProfilingType\x12\x1e\n\x1aUNKNOWN_VTS_PROFILING_TYPE\x10\x00\x12 \n\x1cVTS_PROFILING_TYPE_TIMESTAMP\x10\x01\x12%\n!VTS_PROFILING_TYPE_LABELED_VECTOR\x10\x02\x12\'\n#VTS_PROFILING_TYPE_UNLABELED_VECTOR\x10\x03\x42+\n\x15\x63om.android.vts.protoB\x10VtsReportMessageP\x00')
_TESTCASERESULT = _descriptor.EnumDescriptor(
name='TestCaseResult',
@@ -585,7 +585,7 @@
options=None),
_descriptor.FieldDescriptor(
name='line_coverage_vector', full_name='android.vts.CoverageReportMessage.line_coverage_vector', index=3,
- number=23, type=5, cpp_type=1, label=3,
+ number=23, type=3, cpp_type=2, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
diff --git a/utils/python/retry/__init__.py b/runners/adapters/__init__.py
similarity index 100%
copy from utils/python/retry/__init__.py
copy to runners/adapters/__init__.py
diff --git a/utils/python/retry/__init__.py b/runners/adapters/acts/__init__.py
similarity index 100%
copy from utils/python/retry/__init__.py
copy to runners/adapters/acts/__init__.py
diff --git a/runners/adapters/acts/acts_adapter.py b/runners/adapters/acts/acts_adapter.py
new file mode 100644
index 0000000..53f247a
--- /dev/null
+++ b/runners/adapters/acts/acts_adapter.py
@@ -0,0 +1,205 @@
+#
+# Copyright (C) 2017 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.
+#
+
+import importlib
+import json
+import logging
+import os
+import subprocess
+import sys
+import time
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test
+from vts.runners.host import config_parser
+from vts.runners.host import records
+from vts.runners.host import test_runner
+from vts.utils.python.io import capture_printout
+from vts.utils.python.io import file_util
+
+ACTS_TEST_MODULE = 'ACTS_TEST_MODULE'
+LIST_TEST_OUTPUT_START = '==========> '
+LIST_TEST_OUTPUT_END = ' <=========='
+# Temp directory inside python log path. The name is required to be
+# 'temp' for the Java framework to skip reading contents as regular test logs.
+TEMP_DIR_NAME = 'temp'
+CONFIG_FILE_NAME = 'acts_config.txt'
+RESULT_FILE_NAME = 'test_run_summary.json'
+
+CONFIG_TEXT = '''{{
+ "_description": "VTS acts tests",
+ "testbed":
+ [
+ {{
+ "_description": "ACTS test bed",
+ "name": "{module_name}",
+ "AndroidDevice":
+ [
+ {serials}
+ ]
+ }}
+ ],
+ "logpath": "{log_path}",
+ "testpaths":
+ [
+ "{src_path}"
+ ]
+}}
+'''
+
+
+class ActsAdapter(base_test.BaseTestClass):
+ '''Template class for running acts test cases.
+
+ Attributes:
+ test_type: string, name of test type this adapter is for
+ result_path: string, test result directory for the adaptor
+ config_path: string, test config file path
+ module_name: string, ACTS module name
+ test_path: string, ACTS module source directory
+ '''
+ test_type = 'ACTS'
+
+ def setUpClass(self):
+ '''Set up result directory, generate configuration file, and list tests.'''
+ self.result_path = os.path.join(logging.log_path, TEMP_DIR_NAME,
+ self.test_type, str(time.time()))
+ file_util.Makedirs(self.result_path)
+ logging.debug('Result path for %s: %s' % (self.test_type,
+ self.result_path))
+ self.test_path, self.module_name = self.getUserParam(
+ ACTS_TEST_MODULE).rsplit('/', 1)
+
+ self.config_path = os.path.join(self.result_path, CONFIG_FILE_NAME)
+ self.GenerateConfigFile()
+
+ testcases = self.ListTestCases()
+ logging.debug('ACTS Test cases: %s', testcases)
+
+ def tearDownClass(self):
+ '''Clear the result path.'''
+ file_util.Rmdirs(self.result_path, ignore_errors=True)
+
+ def GenerateConfigFile(self):
+ '''Generate test configuration file.'''
+ serials = []
+ for ad in self.android_devices:
+ serials.append('{"serial":"%s"}' % ad.serial)
+
+ config_text = CONFIG_TEXT.format(
+ module_name=self.module_name,
+ serials=','.join(serials),
+ log_path=self.result_path,
+ src_path=self.test_path)
+
+ with open(self.config_path, 'w') as f:
+ f.write(config_text)
+
+ def ListTestCases(self):
+ '''List test cases.
+
+ Returns:
+ List of string, test names.
+ '''
+ # TODO use ACTS runner to list test cases and add requested record.
+ # This step is optional but desired. To be implemented later
+
+ def Run(self):
+ '''Execute test cases.'''
+ # acts.py is installed to user bin by ACTS setup script.
+ # In the future, it is preferred to use the source code
+ # from repo directory.
+ bin = 'acts/bin/act.py'
+
+ cmd = '{bin} -c {config} -tb {module_name} -tc {module_name}'.format(
+ bin=bin, config=self.config_path, module_name=self.module_name)
+ logging.debug('cmd is: %s', cmd)
+
+ # Calling through subprocess is required because ACTS requires python3
+ # while VTS is currently using python2. In the future, ACTS runner
+ # can be invoked through importing when VTS upgrades to python3.
+
+ # A "hack" to call python3 outside of python2 virtualenv created by
+ # VTS framework
+ environ = {
+ key: val
+ for key, val in os.environ.iteritems() if 'virtualenv' not in val
+ }
+
+ # TODO(yuexima): disable buffer
+ p = subprocess.Popen(
+ cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ env=environ)
+
+ for line in iter(p.stdout.readline, b''):
+ print line.rstrip()
+
+ p.communicate()
+ if p.returncode:
+ asserts.fail('Subprocess of ACTS command failed. Return code: %s' %
+ p.returncode)
+
+ def ParseResults(self):
+ '''Get module run results and put in vts results.'''
+ file_path = file_util.FindFile(self.result_path, RESULT_FILE_NAME)
+
+ if file_path:
+ logging.debug('ACTS test result path: %s', file_path)
+ self.ParseJsonResults(file_path)
+ else:
+ logging.error('Cannot find result file name %s in %s',
+ RESULT_FILE_NAME, self.result_path)
+
+ def generateAllTests(self):
+ '''Run the test module and parse results.'''
+ self.Run()
+ self.ParseResults()
+
+ def ParseJsonResults(self, result_path):
+ '''Parse test json result.
+
+ Args:
+ result_path: string, result json file path.
+ '''
+ with open(result_path, 'r') as f:
+ summary = json.load(f)
+
+ results = summary['Results']
+ for result in results:
+ logging.debug('Adding result for %s' %
+ result[records.TestResultEnums.RECORD_NAME])
+ record = records.TestResultRecord(
+ result[records.TestResultEnums.RECORD_NAME])
+ record.test_class = result[records.TestResultEnums.RECORD_CLASS]
+ record.begin_time = result[
+ records.TestResultEnums.RECORD_BEGIN_TIME]
+ record.end_time = result[records.TestResultEnums.RECORD_END_TIME]
+ record.result = result[records.TestResultEnums.RECORD_RESULT]
+ record.uid = result[records.TestResultEnums.RECORD_UID]
+ record.extras = result[records.TestResultEnums.RECORD_EXTRAS]
+ record.details = result[records.TestResultEnums.RECORD_DETAILS]
+ record.extra_errors = result[
+ records.TestResultEnums.RECORD_EXTRA_ERRORS]
+
+ self.results.addRecord(record)
+
+ # TODO(yuexima): parse new result types
+
+if __name__ == "__main__":
+ test_runner.main()
diff --git a/runners/host/base_test.py b/runners/host/base_test.py
index 3c1e158..fd8c38e 100644
--- a/runners/host/base_test.py
+++ b/runners/host/base_test.py
@@ -28,11 +28,13 @@
from vts.runners.host import records
from vts.runners.host import signals
from vts.runners.host import utils
+from vts.utils.python.controllers import adb
from vts.utils.python.controllers import android_device
from vts.utils.python.common import filter_utils
from vts.utils.python.common import list_utils
from vts.utils.python.coverage import coverage_utils
from vts.utils.python.coverage import sancov_utils
+from vts.utils.python.precondition import precondition_utils
from vts.utils.python.profiling import profiling_utils
from vts.utils.python.reporting import log_uploading_utils
from vts.utils.python.systrace import systrace_utils
@@ -49,7 +51,22 @@
_REPORT_MESSAGE_FILE_NAME = "report_proto.msg"
_BUG_REPORT_FILE_PREFIX = "bugreport"
_BUG_REPORT_FILE_EXTENSION = ".zip"
+_LOGCAT_FILE_PREFIX = "logcat"
+_LOGCAT_FILE_EXTENSION = ".txt"
_ANDROID_DEVICES = '_android_devices'
+_REASON_TO_SKIP_ALL_TESTS = '_reason_to_skip_all_tests'
+# the name of a system property which tells whether to stop properly configured
+# native servers where properly configured means a server's init.rc is
+# configured to stop when that property's value is 1.
+SYSPROP_VTS_NATIVE_SERVER = "vts.native_server.on"
+
+LOGCAT_BUFFERS = [
+ 'radio',
+ 'events',
+ 'main',
+ 'system',
+ 'crash'
+]
class BaseTestClass(object):
@@ -64,9 +81,9 @@
Attributes:
android_devices: A list of AndroidDevice object, representing android
devices.
+ test_module_name: A string representing the test module name.
tests: A list of strings, each representing a test case name.
- TAG: A string used to refer to a test class. Default is the test class
- name.
+ log: A logger object used for logging.
results: A records.TestResult object for aggregating test results from
the execution of test cases.
_current_record: A records.TestResultRecord object for the test case
@@ -81,23 +98,24 @@
web: WebFeature, object storing web feature util for test run
coverage: CoverageFeature, object storing coverage feature util for test run
sancov: SancovFeature, object storing sancov feature util for test run
+ start_vts_agents: whether to start vts agents when registering new
+ android devices.
profiling: ProfilingFeature, object storing profiling feature util for test run
- _skip_all_testcases: A boolean, can be set by a subclass in
- setUpClass() to skip all test cases.
_bug_report_on_failure: bool, whether to catch bug report at the end
- of failed test cases.
+ of failed test cases. Default is False
+ _logcat_on_failure: bool, whether to dump logcat at the end
+ of failed test cases. Default is True
test_filter: Filter object to filter test names.
"""
- TAG = None
+ start_vts_agents = True
def __init__(self, configs):
self.tests = []
- if not self.TAG:
- self.TAG = self.__class__.__name__
# Set all the controller objects and params.
for name, value in configs.items():
setattr(self, name, value)
self.results = records.TestResult()
+ self.log = logger.LoggerProxy()
self._current_record = None
# Setup test filters
@@ -122,8 +140,10 @@
list_utils.ItemsToStr(self.exclude_filter), ',')
exclude_over_include = self.getUserParam(
keys.ConfigKeys.KEY_EXCLUDE_OVER_INCLUDE, default_value=None)
- self.test_module_name = self.getUserParam(keys.ConfigKeys.KEY_TESTBED_NAME,
- default_value=None)
+ self.test_module_name = self.getUserParam(
+ keys.ConfigKeys.KEY_TESTBED_NAME,
+ warn_if_not_found=True,
+ default_value=self.__class__.__name__)
self.test_filter = filter_utils.Filter(
self.include_filter,
self.exclude_filter,
@@ -131,9 +151,9 @@
exclude_over_include=exclude_over_include,
enable_negative_pattern=True,
enable_module_name_prefix_matching=True,
- module_name=self.test_module_name)
- self.test_filter.ExpandBitness()
- logging.info('Test filter: %s' % self.test_filter)
+ module_name=self.test_module_name,
+ expand_bitness=True)
+ logging.debug('Test filter: %s' % self.test_filter)
# TODO: get abi information differently for multi-device support.
# Set other optional parameters
@@ -158,20 +178,24 @@
self.user_params, web=self.web)
self.log_uploading = log_uploading_utils.LogUploadingFeature(
self.user_params, web=self.web)
+ self.collect_tests_only = self.getUserParam(
+ keys.ConfigKeys.IKEY_COLLECT_TESTS_ONLY, default_value=False)
self.run_as_vts_self_test = self.getUserParam(
keys.ConfigKeys.RUN_AS_VTS_SELFTEST, default_value=False)
self.run_as_compliance_test = self.getUserParam(
keys.ConfigKeys.RUN_AS_COMPLIANCE_TEST, default_value=False)
- self._skip_all_testcases = False
self._bug_report_on_failure = self.getUserParam(
keys.ConfigKeys.IKEY_BUG_REPORT_ON_FAILURE, default_value=False)
+ self._logcat_on_failure = self.getUserParam(
+ keys.ConfigKeys.IKEY_LOGCAT_ON_FAILURE, default_value=True)
@property
def android_devices(self):
"""Returns a list of AndroidDevice objects"""
if not hasattr(self, _ANDROID_DEVICES):
setattr(self, _ANDROID_DEVICES,
- self.registerController(android_device))
+ self.registerController(android_device,
+ start_services=self.start_vts_agents))
return getattr(self, _ANDROID_DEVICES)
@android_devices.setter
@@ -216,7 +240,7 @@
setattr(self, name, self.user_params[name])
for name in opt_param_names:
if name not in self.user_params:
- logging.info(("Missing optional user param '%s' in "
+ logging.debug(("Missing optional user param '%s' in "
"configuration, continue."), name)
else:
setattr(self, name, self.user_params[name])
@@ -224,13 +248,15 @@
def getUserParam(self,
param_name,
error_if_not_found=False,
- log_warning_and_continue_if_not_found=False,
+ warn_if_not_found=False,
default_value=None,
to_str=False):
"""Get the value of a single user parameter.
This method returns the value of specified user parameter.
- Note: this method will not automatically set attribute using the parameter name and value.
+
+ Note: unlike getUserParams(), this method will not automatically set
+ attribute using the parameter name and value.
Args:
param_name: string or list of string, denoting user parameter names. If provided
@@ -238,18 +264,21 @@
If provided multiple strings,
self.user_params["<param_name1>"]["<param_name2>"]["<param_name3>"]...
will be accessed.
- error_if_not_found: bool, whether to raise error if parameter not exists. Default:
- False
- log_warning_and_continue_if_not_found: bool, log a warning message if parameter value
- not found.
- default_value: object, default value to return if not found. If error_if_not_found is
- True, this parameter has no effect. Default: None
- to_str: boolean, whether to convert the result object to string if not None.
- Note, strings passing in from java json config are usually unicode.
+ error_if_not_found: bool, whether to raise error if parameter not
+ exists. Default: False
+ warn_if_not_found: bool, log a warning message if parameter value
+ not found. Default: False
+ default_value: object, default value to return if not found.
+ If error_if_not_found is true, this parameter has no
+ effect. Default: None
+ to_str: boolean, whether to convert the result object to string if
+ not None.
+ Note, strings passing in from java json config are often
+ unicode.
Returns:
object, value of the specified parameter name chain if exists;
- <default_value> if not exists.
+ <default_value> otherwise.
"""
def ToStr(return_value):
@@ -270,20 +299,143 @@
curr_obj = self.user_params
for param in param_name:
if param not in curr_obj:
- msg = "Missing user param '%s' in test configuration." % param_name
+ msg = ("Missing user param '%s' in test configuration.\n"
+ "User params: %s") % (param_name, self.user_params)
if error_if_not_found:
raise errors.BaseTestError(msg)
- elif log_warning_and_continue_if_not_found:
+ elif warn_if_not_found:
logging.warn(msg)
return ToStr(default_value)
curr_obj = curr_obj[param]
return ToStr(curr_obj)
+ def _getUserConfig(self,
+ config_type,
+ key,
+ default_value=None,
+ error_if_not_found=False,
+ warn_if_not_found=False,
+ to_str=False):
+ """Get the value of a user config given the key.
+
+ This method returns the value of specified user config type.
+
+ Args:
+ config_type: string, type of user config
+ key: string, key of the value string in string config map.
+ default_value: object, default value to return if not found.
+ If error_if_not_found is true, this parameter has no
+ effect. Default: None
+ error_if_not_found: bool, whether to raise error if parameter not
+ exists. Default: False
+ warn_if_not_found: bool, log a warning message if parameter value
+ not found. Default: False
+ to_str: boolean, whether to apply str() method to result value
+ if result is not None.
+ Note, strings passing in from java json config are ofen
+ unicode.
+
+ Returns:
+ Value in config matching the given key and type if exists;
+ <default_value> otherwise.
+ """
+ dic = self.getUserParam(config_type,
+ error_if_not_found=False,
+ warn_if_not_found=False,
+ default_value=None,
+ to_str=False)
+
+ if dic is None or key not in dic:
+ msg = ("Config key %s not found in user config type %s.\n"
+ "User params: %s") % (key, config_type, self.user_params)
+ if error_if_not_found:
+ raise errors.BaseTestError(msg)
+ elif warn_if_not_found:
+ logging.warn(msg)
+
+ return default_value
+
+ return dic[key] if not to_str else str(dic[key])
+
+ def getUserConfigStr(self, key, **kwargs):
+ """Get the value of a user config string given the key.
+
+ See _getUserConfig method for more details.
+ """
+ kwargs["to_str"] = True
+ return self._getUserConfig(keys.ConfigKeys.IKEY_USER_CONFIG_STR,
+ key,
+ **kwargs)
+
+ def getUserConfigInt(self, key, **kwargs):
+ """Get the value of a user config int given the key.
+
+ See _getUserConfig method for more details.
+ """
+ return self._getUserConfig(keys.ConfigKeys.IKEY_USER_CONFIG_INT,
+ key,
+ **kwargs)
+
+ def getUserConfigBool(self, key, **kwargs):
+ """Get the value of a user config bool given the key.
+
+ See _getUserConfig method for more details.
+ """
+ return self._getUserConfig(keys.ConfigKeys.IKEY_USER_CONFIG_BOOL,
+ key,
+ **kwargs)
+
def _setUpClass(self):
"""Proxy function to guarantee the base implementation of setUpClass
is called.
"""
+ if not precondition_utils.MeetFirstApiLevelPrecondition(self):
+ self.skipAllTests("The device's first API level doesn't meet the "
+ "precondition.")
+
+ if (self.getUserParam(keys.ConfigKeys.IKEY_DISABLE_FRAMEWORK,
+ default_value=False) or
+ # @Deprecated Legacy configuration option name.
+ self.getUserParam(keys.ConfigKeys.IKEY_BINARY_TEST_DISABLE_FRAMEWORK,
+ default_value=False)):
+ # Disable the framework if requested.
+ for device in self.android_devices:
+ device.stop()
+ else:
+ # Enable the framework if requested.
+ for device in self.android_devices:
+ device.start()
+
+ if (self.getUserParam(keys.ConfigKeys.IKEY_STOP_NATIVE_SERVERS,
+ default_value=False) or
+ # @Deprecated Legacy configuration option name.
+ self.getUserParam(keys.ConfigKeys.IKEY_BINARY_TEST_STOP_NATIVE_SERVERS,
+ default_value=False)):
+ for device in self.android_devices:
+ logging.debug("Stops all properly configured native servers "
+ "on device %s", device.serial)
+ results = device.setProp(SYSPROP_VTS_NATIVE_SERVER, "1")
+ native_server_process_names = self.getUserParam(
+ keys.ConfigKeys.IKEY_NATIVE_SERVER_PROCESS_NAME,
+ default_value=[])
+ if native_server_process_names:
+ for native_server_process_name in native_server_process_names:
+ while True:
+ logging.info("Checking process %s",
+ native_server_process_name)
+ cmd_result = device.shell.Execute("ps -A")
+ if cmd_result[const.EXIT_CODE][0] != 0:
+ logging.error("ps command failed (exit code: %s",
+ cmd_result[const.EXIT_CODE][0])
+ break
+ if (native_server_process_name not in cmd_result[
+ const.STDOUT][0]):
+ logging.debug("Process %s not running",
+ native_server_process_name)
+ break
+ time.sleep(1)
+
return self.setUpClass()
def setUpClass(self):
@@ -315,11 +467,21 @@
_REPORT_MESSAGE_FILE_NAME)
if message_b:
- logging.info('Result proto message path: %s', report_proto_path)
+ logging.debug('Result proto message path: %s', report_proto_path)
with open(report_proto_path, "wb") as f:
f.write(message_b)
+ if getattr(self, keys.ConfigKeys.IKEY_BINARY_TEST_STOP_NATIVE_SERVERS,
+ False):
+ logging.debug("Restarts all properly configured native servers.")
+ for device in self.android_devices:
+ try:
+ self.device.setProp(SYSPROP_VTS_NATIVE_SERVER, "0")
+ except adb.AdbError:
+ logging.error("failed to restore native servers for device "
+ + device.serial)
+
return ret
def tearDownClass(self):
@@ -391,7 +553,9 @@
self.web.SetTestResult(ReportMsg.TEST_CASE_RESULT_FAIL)
self.onFail(record.test_name, begin_time)
if self._bug_report_on_failure:
- self.CatchBugReport('%s-%s' % (self.TAG, record.test_name))
+ self.DumpBugReport(ecord.test_name)
+ if self._logcat_on_failure:
+ self.DumpLogcat(record.test_name)
def onFail(self, test_name, begin_time):
"""A function that is executed upon a test case failure.
@@ -412,7 +576,7 @@
begin_time = logger.epochToLogLineTimestamp(record.begin_time)
msg = record.details
if msg:
- logging.info(msg)
+ logging.debug(msg)
logging.info(RESULT_LINE_TEMPLATE, test_name, record.result)
if self.web.enabled:
self.web.SetTestResult(ReportMsg.TEST_CASE_RESULT_PASS)
@@ -436,7 +600,7 @@
test_name = record.test_name
begin_time = logger.epochToLogLineTimestamp(record.begin_time)
logging.info(RESULT_LINE_TEMPLATE, test_name, record.result)
- logging.info("Reason to skip: %s", record.details)
+ logging.debug("Reason to skip: %s", record.details)
if self.web.enabled:
self.web.SetTestResult(ReportMsg.TEST_CASE_RESULT_SKIP)
self.onSkip(test_name, begin_time)
@@ -484,7 +648,9 @@
self.web.SetTestResult(ReportMsg.TEST_CASE_RESULT_EXCEPTION)
self.onException(test_name, begin_time)
if self._bug_report_on_failure:
- self.CatchBugReport('%s-%s' % (self.TAG, record.test_name))
+ self.DumpBugReport(ecord.test_name)
+ if self._logcat_on_failure:
+ self.DumpLogcat(record.test_name)
def onException(self, test_name, begin_time):
"""A function that is executed upon an unhandled exception from a test
@@ -544,9 +710,8 @@
if include filter is empty, only tests not in exclude filter will be
executed.
- The second layer of filter is checking _skip_all_testcases flag:
- the subclass may set _skip_all_testcases to True in its implementation
- of setUpClass. If the flag is set, this method raises signals.TestSkip.
+ The second layer of filter is checking whether skipAllTests method is
+ called. If the flag is set, this method raises signals.TestSkip.
The third layer of filter is checking abi bitness:
if a test has a suffix indicating the intended architecture bitness,
@@ -583,8 +748,8 @@
if not test_filter.Filter(test_name):
raise signals.TestSilent("Test case '%s' did not pass filters.")
- if self._skip_all_testcases:
- raise signals.TestSkip("All test cases skipped.")
+ if self.isSkipAllTests():
+ raise signals.TestSkip(self.getSkipAllTestsReason())
def _filterOneTestThroughAbiBitness(self, test_name):
"""Check test filter for the given test name.
@@ -620,7 +785,7 @@
kwargs: Extra kwargs.
"""
is_silenced = False
- tr_record = records.TestResultRecord(test_name, self.TAG)
+ tr_record = records.TestResultRecord(test_name, self.test_module_name)
tr_record.testBegin()
logging.info("%s %s", TEST_CASE_TOKEN, test_name)
verdict = None
@@ -630,6 +795,9 @@
asserts.assertTrue(ret is not False,
"Setup test entry for %s failed." % test_name)
self.filterOneTest(test_name)
+ if self.collect_tests_only:
+ asserts.explicitPass("Collect tests only.")
+
try:
ret = self._setUp(test_name)
asserts.assertTrue(ret is not False,
@@ -743,24 +911,36 @@
args = args or ()
kwargs = kwargs or {}
failed_settings = []
- for s in settings:
- test_name = "{} {}".format(tag, s)
+
+ def GenerateTestName(setting):
+ test_name = "{} {}".format(tag, setting)
if name_func:
try:
- test_name = name_func(s, *args, **kwargs)
+ test_name = name_func(setting, *args, **kwargs)
except:
logging.exception(("Failed to get test name from "
"test_func. Fall back to default %s"),
test_name)
- tr_record = records.TestResultRecord(test_name, self.TAG)
- self.results.requested.append(tr_record)
if len(test_name) > utils.MAX_FILENAME_LEN:
test_name = test_name[:utils.MAX_FILENAME_LEN]
+
+ return test_name
+
+ for setting in settings:
+ test_name = GenerateTestName(setting)
+
+ tr_record = records.TestResultRecord(test_name, self.test_module_name)
+ self.results.requested.append(tr_record)
+
+ for setting in settings:
+ test_name = GenerateTestName(setting)
previous_success_cnt = len(self.results.passed)
- self.execOneTest(test_name, test_func, (s, ) + args, **kwargs)
+
+ self.execOneTest(test_name, test_func, (setting, ) + args, **kwargs)
if len(self.results.passed) - previous_success_cnt != 1:
- failed_settings.append(s)
+ failed_settings.append(setting)
+
return failed_settings
def _exec_func(self, func, *args):
@@ -783,7 +963,7 @@
raise signals.TestAbortAll, e, sys.exc_info()[2]
except:
logging.exception("Exception happened when executing %s in %s.",
- func.__name__, self.TAG)
+ func.__name__, self.test_module_name)
return False
def _get_all_test_names(self):
@@ -819,8 +999,8 @@
test_funcs = []
for test_name in test_names:
if not hasattr(self, test_name):
- logging.warning("%s does not have test case %s.", self.TAG,
- test_name)
+ logging.warning("%s does not have test case %s.",
+ self.test_module_name, test_name)
elif (test_name.startswith(STR_TEST) or
test_name.startswith(STR_GENERATE)):
test_funcs.append((test_name, getattr(self, test_name)))
@@ -831,6 +1011,91 @@
return test_funcs
+ def getTests(self, test_names=None):
+ """Get the test cases within a test class.
+
+ Args:
+ test_names: A list of string that are test case names requested in
+ cmd line.
+
+ Returns:
+ A list of tuples of (string, function). String is the test case
+ name, function is the actual test case function.
+ """
+ if not test_names:
+ if self.tests:
+ # Specified by run list in class.
+ test_names = list(self.tests)
+ else:
+ # No test case specified by user, execute all in the test class
+ test_names = self._get_all_test_names()
+
+ tests = self._get_test_funcs(test_names)
+ return tests
+
+ def runTests(self, tests):
+ """Run tests and collect test results.
+
+ Args:
+ tests: A list of tests to be run.
+
+ Returns:
+ The test results object of this class.
+ """
+ # Setup for the class.
+ try:
+ if self._setUpClass() is False:
+ raise signals.TestFailure(
+ "Failed to setup %s." % self.test_module_name)
+ except Exception as e:
+ logging.exception("Failed to setup %s.", self.test_module_name)
+ self.results.failClass(self.test_module_name, e)
+ self._exec_func(self._tearDownClass)
+ return self.results
+
+ # Run tests in order.
+ try:
+ # Check if module is running in self test mode.
+ if self.run_as_vts_self_test:
+ logging.debug('setUpClass function was executed successfully.')
+ self.results.passClass(self.test_module_name)
+ return self.results
+
+ for test_name, test_func in tests:
+ if test_name.startswith(STR_GENERATE):
+ logging.debug(
+ "Executing generated test trigger function '%s'",
+ test_name)
+ test_func()
+ logging.debug("Finished '%s'", test_name)
+ else:
+ self.execOneTest(test_name, test_func, None)
+ if self.isSkipAllTests() and not self.results.executed:
+ self.results.skipClass(
+ self.test_module_name,
+ "All test cases skipped; unable to find any test case.")
+ return self.results
+ except (signals.TestAbortClass, acts_signals.TestAbortClass):
+ logging.error("Received TestAbortClass signal")
+ return self.results
+ except (signals.TestAbortAll, acts_signals.TestAbortAll) as e:
+ logging.error("Received TestAbortAll signal")
+ # Piggy-back test results on this exception object so we don't lose
+ # results from this test class.
+ setattr(e, "results", self.results)
+ raise signals.TestAbortAll, e, sys.exc_info()[2]
+ except Exception as e:
+ # Exception happened during test.
+ logging.exception(e)
+ raise e
+ finally:
+ self._exec_func(self._tearDownClass)
+ if self.web.enabled:
+ name, timestamp = self.web.GetTestModuleKeys()
+ self.results.setTestModuleKeys(name, timestamp)
+ logging.info("Summary for test class %s: %s",
+ self.test_module_name, self.results.summary())
+
def run(self, test_names=None):
"""Runs test cases within a test class by the order they appear in the
execution list.
@@ -851,75 +1116,16 @@
Returns:
The test results object of this class.
"""
- logging.info("==========> %s <==========", self.TAG)
+ logging.info("==========> %s <==========", self.test_module_name)
# Devise the actual test cases to run in the test class.
- if not test_names:
- if self.tests:
- # Specified by run list in class.
- test_names = list(self.tests)
- else:
- # No test case specified by user, execute all in the test class
- test_names = self._get_all_test_names()
+ tests = self.getTests(test_names)
if not self.run_as_vts_self_test:
self.results.requested = [
- records.TestResultRecord(test_name, self.TAG)
- for test_name in test_names if test_name.startswith(STR_TEST)
+ records.TestResultRecord(test_name, self.test_module_name)
+ for test_name,_ in tests if test_name.startswith(STR_TEST)
]
- tests = self._get_test_funcs(test_names)
-
- # Setup for the class.
- try:
- if self._setUpClass() is False:
- raise signals.TestFailure("Failed to setup %s." % self.TAG)
- except Exception as e:
- logging.exception("Failed to setup %s.", self.TAG)
- self.results.failClass(self.TAG, e)
- self._exec_func(self._tearDownClass)
- return self.results
-
- # Run tests in order.
- try:
- # Check if module is running in self test mode.
- if self.run_as_vts_self_test:
- logging.info('setUpClass function was executed successfully.')
- self.results.passClass(self.TAG)
- return self.results
-
- for test_name, test_func in tests:
- if test_name.startswith(STR_GENERATE):
- logging.info(
- "Executing generated test trigger function '%s'",
- test_name)
- test_func()
- logging.info("Finished '%s'", test_name)
- else:
- self.execOneTest(test_name, test_func, None)
- if self._skip_all_testcases and not self.results.executed:
- self.results.skipClass(
- self.TAG,
- "All test cases skipped; unable to find any test case.")
- return self.results
- except (signals.TestAbortClass, acts_signals.TestAbortClass):
- logging.info("Received TestAbortClass signal")
- return self.results
- except (signals.TestAbortAll, acts_signals.TestAbortAll) as e:
- logging.info("Received TestAbortAll signal")
- # Piggy-back test results on this exception object so we don't lose
- # results from this test class.
- setattr(e, "results", self.results)
- raise signals.TestAbortAll, e, sys.exc_info()[2]
- except Exception as e:
- # Exception happened during test.
- logging.exception(e)
- raise e
- finally:
- self._exec_func(self._tearDownClass)
- if self.web.enabled:
- name, timestamp = self.web.GetTestModuleKeys()
- self.results.setTestModuleKeys(name, timestamp)
- logging.info("Summary for test class %s: %s", self.TAG,
- self.results.summary())
+ return self.runTests(tests)
def cleanUp(self):
"""A function that is executed upon completion of all tests cases
@@ -929,7 +1135,7 @@
user.
"""
- def CatchBugReport(self, prefix=''):
+ def DumpBugReport(self, prefix=''):
"""Get device bugreport through adb command.
Args:
@@ -939,12 +1145,78 @@
if prefix:
prefix = re.sub('[^\w\-_\. ]', '_', prefix) + '_'
- for i in range(len(self.android_devices)):
- device = self.android_devices[i]
- bug_report_file_name = prefix + _BUG_REPORT_FILE_PREFIX + str(
- i) + _BUG_REPORT_FILE_EXTENSION
- bug_report_file_path = os.path.join(logging.log_path,
- bug_report_file_name)
+ for device in self.android_devices:
+ file_name = (_BUG_REPORT_FILE_PREFIX
+ + prefix
+ + '_%s' % device.serial
+ + _BUG_REPORT_FILE_EXTENSION)
- logging.info('Catching bugreport %s' % bug_report_file_path)
- device.adb.bugreport(bug_report_file_path)
+ file_path = os.path.join(logging.log_path,
+ file_name)
+
+ logging.info('Dumping bugreport %s...' % file_path)
+ device.adb.bugreport(file_path)
+
+ def skipAllTests(self, msg):
+ """Skip all test cases.
+
+ This method is usually called in setup functions when a precondition
+ to the test module is not met.
+
+ Args:
+ msg: string, reason why tests are skipped. If set to None or empty
+ string, a default message will be used (not recommended)
+ """
+ if not msg:
+ msg = "No reason provided."
+
+ setattr(self, _REASON_TO_SKIP_ALL_TESTS, msg)
+
+ def isSkipAllTests(self):
+ """Returns whether all tests are set to be skipped.
+
+ Note: If all tests are being skipped not due to skipAllTests
+ being called, or there is no tests defined, this method will
+ still return False (since skipAllTests is not called.)
+
+ Returns:
+ bool, True if skipAllTests has been called; False otherwise.
+ """
+ return self.getSkipAllTestsReason() is not None
+
+ def getSkipAllTestsReason(self):
+ """Returns the reason why all tests are skipped.
+
+ Note: If all tests are being skipped not due to skipAllTests
+ being called, or there is no tests defined, this method will
+ still return None (since skipAllTests is not called.)
+
+ Returns:
+ String, reason why tests are skipped. None if skipAllTests
+ is not called.
+ """
+ return getattr(self, _REASON_TO_SKIP_ALL_TESTS, None)
+
+ def DumpLogcat(self, prefix=''):
+ """Dumps device logcat outputs to log directory.
+
+ Args:
+ prefix: string, file name prefix. Usually in format of
+ <test_module>-<test_case>
+ """
+ if prefix:
+ prefix = re.sub('[^\w\-_\. ]', '_', prefix) + '_'
+
+ for device in self.android_devices:
+ for buffer in LOGCAT_BUFFERS:
+ file_name = (_LOGCAT_FILE_PREFIX
+ + prefix
+ + '_%s_' % buffer
+ + device.serial
+ + _LOGCAT_FILE_EXTENSION)
+
+ file_path = os.path.join(logging.log_path,
+ file_name)
+
+ logging.info('Dumping logcat %s...' % file_path)
+ device.adb.logcat('-b', buffer, '-d', '>', file_path)
diff --git a/runners/host/keys.py b/runners/host/keys.py
index b9e75fb..37f4e90 100644
--- a/runners/host/keys.py
+++ b/runners/host/keys.py
@@ -30,7 +30,6 @@
KEY_TESTBED_NAME = "name"
KEY_TEST_PATHS = "test_paths"
KEY_TEST_SUITE = "test_suite"
- KEY_TEST_MAX_TIMEOUT = "test_max_timeout"
# Keys in test suite
KEY_INCLUDE_FILTER = "include_filter"
@@ -43,11 +42,16 @@
IKEY_BINARY_TEST_ENVP = "binary_test_envp"
IKEY_BINARY_TEST_ARGS = "binary_test_args"
IKEY_BINARY_TEST_LD_LIBRARY_PATH = "binary_test_ld_library_path"
- IKEY_BINARY_TEST_DISABLE_FRAMEWORK = "binary_test_disable_framework"
- IKEY_BINARY_TEST_STOP_NATIVE_SERVERS = "binary_test_stop_native_servers"
IKEY_NATIVE_SERVER_PROCESS_NAME = "native_server_process_name"
IKEY_GTEST_BATCH_MODE = "gtest_batch_mode"
+ # @Deprecated use IKEY_DISABLE_FRAMEWORK
+ IKEY_BINARY_TEST_DISABLE_FRAMEWORK = "binary_test_disable_framework"
+ IKEY_DISABLE_FRAMEWORK = "DISABLE_FRAMEWORK"
+ # @Deprecated use IKEY_STOP_NATIVE_SERVERS
+ IKEY_BINARY_TEST_STOP_NATIVE_SERVERS = "binary_test_stop_native_servers"
+ IKEY_STOP_NATIVE_SERVERS = "STOP_NATIVE_SERVERS"
+
# Internal keys, used internally, not exposed to user's config files.
IKEY_USER_PARAM = "user_params"
IKEY_TESTBED_NAME = "testbed_name"
@@ -58,11 +62,13 @@
IKEY_SKIP_ON_32BIT_ABI = "skip_on_32bit_abi"
IKEY_SKIP_ON_64BIT_ABI = "skip_on_64bit_abi"
IKEY_SKIP_IF_THERMAL_THROTTLING = "skip_if_thermal_throttling"
+ IKEY_DISABLE_CPU_FREQUENCY_SCALING = "disable_cpu_frequency_scaling"
IKEY_BUILD = "build"
IKEY_DATA_FILE_PATH = "data_file_path"
- IKEY_BUG_REPORT_ON_FAILURE = "bug_report_on_failure"
+ IKEY_BUG_REPORT_ON_FAILURE = "BUG_REPORT_ON_FAILURE"
+ IKEY_LOGCAT_ON_FAILURE = "LOGCAT_ON_FAILURE"
# sub fields of test_bed
IKEY_ANDROID_DEVICE = "AndroidDevice"
@@ -103,12 +109,16 @@
IKEY_GLOBAL_COVERAGE = "global_coverage"
IKEY_SANCOV_RESOURCES_PATH = "sancov_resources_path"
IKEY_GCOV_RESOURCES_PATH = "gcov_resources_path"
+ IKEY_COVERAGE_REPORT_PATH = "coverage_report_path"
+ IKEY_EXCLUDE_COVERAGE_PATH = "exclude_coverage_path"
# Keys for the HAL HIDL GTest type (see VtsMultiDeviceTest.java).
IKEY_PRECONDITION_HWBINDER_SERVICE = "precondition_hwbinder_service"
IKEY_PRECONDITION_FEATURE = "precondition_feature"
IKEY_PRECONDITION_FILE_PATH_PREFIX = "precondition_file_path_prefix"
+ IKEY_PRECONDITION_FIRST_API_LEVEL = "precondition_first_api_level"
IKEY_PRECONDITION_LSHAL = "precondition_lshal"
+ IKEY_PRECONDITION_SYSPROP = "precondition_sysprop"
IKEY_PRECONDITION_VINTF = "precondition_vintf"
# Keys for toggle passthrough mode
@@ -127,12 +137,21 @@
IKEY_LOG_UPLOADING_USE_DATE_DIRECTORY = "log_uploading_use_date_directory"
IKEY_LOG_UPLOADING_URL_PREFIX = "log_uploading_url_prefix"
+ # Keys for general user config types
+ IKEY_USER_CONFIG_STR = 'CONFIG_STR'
+ IKEY_USER_CONFIG_INT = 'CONFIG_INT'
+ IKEY_USER_CONFIG_BOOL = 'CONFIG_BOOL'
+
# A list of keys whose values in configs should not be passed to test
# classes without unpacking first.
RESERVED_KEYS = (KEY_TESTBED, KEY_LOG_PATH, KEY_TEST_PATHS)
- # Vts self test related keys
+ # Keys for special run modes
+ IKEY_COLLECT_TESTS_ONLY = "collect_tests_only"
RUN_AS_VTS_SELFTEST = "run_as_vts_self_test"
# Vts compliance test related keys
RUN_AS_COMPLIANCE_TEST = "run_as_compliance_test"
+
+ # Mobly test related keys
+ MOBLY_TEST_MODULE = "MOBLY_TEST_MODULE"
diff --git a/runners/host/logger.py b/runners/host/logger.py
index a043d17..293b114 100755
--- a/runners/host/logger.py
+++ b/runners/host/logger.py
@@ -39,6 +39,7 @@
"DEBUG": logging.DEBUG,
}
+
def _parse_logline_timestamp(t):
"""Parses a logline timestamp into a tuple.
@@ -137,13 +138,16 @@
filename: Name of the log file. The default is the time the logger
is requested.
log_severity: string, set the log severity level, default is INFO.
+ This value affects console stream log handler and the python runner
+ part of TradeFed host_log.
"""
log = logging.getLogger()
# Clean up any remaining handlers.
killTestLogger(log)
log.propagate = False
- log.setLevel(log_severity_map.get(log_severity, logging.INFO))
+ log.setLevel(logging.DEBUG)
+
# Log info to stream
terminal_format = log_line_format
if prefix:
@@ -152,17 +156,25 @@
ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(c_formatter)
ch.setLevel(log_severity_map.get(log_severity, logging.INFO))
+ log.addHandler(ch)
+
# Log everything to file
f_formatter = logging.Formatter(log_line_format, log_line_time_format)
+
# All the logs of this test class go into one directory
if filename is None:
filename = getLogFileTimestamp()
utils.create_dir(log_path)
- fh = logging.FileHandler(os.path.join(log_path, 'test_run_details.txt'))
- fh.setFormatter(f_formatter)
- fh.setLevel(log_severity_map.get(log_severity, logging.INFO))
- log.addHandler(ch)
- log.addHandler(fh)
+
+ default_log_levels = ('ERROR', 'INFO', 'DEBUG')
+ for level in default_log_levels:
+ idx = filename.rfind('.')
+ if idx < 0:
+ idx = len(filename)
+ addLogFile(log_path=log_path,
+ filename=filename[:idx] + '_' + level + filename[idx:],
+ log_severity=level)
+
log.log_path = log_path
logging.log_path = log_path
@@ -200,21 +212,53 @@
os.symlink(actual_path, link_path)
-def setupTestLogger(log_path, prefix=None, filename=None, log_severity="INFO"):
+def setupTestLogger(log_path,
+ prefix=None,
+ filename=None,
+ log_severity="INFO",
+ create_symlink=True):
"""Customizes the root logger for a test run.
Args:
log_path: Location of the report file.
prefix: A prefix for each log line in terminal.
filename: Name of the files. The default is the time the objects
- are requested.
+ are requested.
+ create_symlink: bool. determines whether to create the symlink or not.
+ set to True as default.
+
+ Returns:
+ A string, abs path to the created log file.
"""
if filename is None:
filename = getLogFileTimestamp()
utils.create_dir(log_path)
logger = _initiateTestLogger(log_path, prefix, filename, log_severity)
- if isSymlinkSupported():
+ if create_symlink and isSymlinkSupported():
createLatestLogAlias(log_path)
+ return os.path.join(log_path, filename)
+
+
+def addLogFile(log_path, filename=None, log_severity="INFO"):
+ """Creates a log file and adds the handler to the root logger.
+
+ Args:
+ log_path: Location of the report file.
+ filename: Name of the log file. The default is the time the logger
+ is requested.
+
+ Returns:
+ A string, abs path to the created log file.
+ logging.FileHandler instance which is added to the logger.
+ """
+ if filename is None:
+ filename = getLogFileTimestamp()
+ f_formatter = logging.Formatter(log_line_format, log_line_time_format)
+ fh = logging.FileHandler(os.path.join(log_path, filename))
+ fh.setFormatter(f_formatter)
+ fh.setLevel(log_severity_map.get(log_severity, logging.INFO))
+ logging.getLogger().addHandler(fh)
+ return os.path.join(log_path, filename), fh
def normalizeLogLineTimestamp(log_line_timestamp):
diff --git a/runners/host/signals.py b/runners/host/signals.py
index ed23bfd..aa2e49b 100644
--- a/runners/host/signals.py
+++ b/runners/host/signals.py
@@ -18,6 +18,7 @@
import functools
import json
+import logging
def GeneratedTest(func):
@@ -40,15 +41,24 @@
class TestSignalError(Exception):
"""Raised when an error occurs inside a test signal."""
-
class TestSignal(Exception):
- """Base class for all test result control signals."""
+ """Base class for all test result control signals.
+
+ Attributes:
+ details: A string that describes the reason for raising this signal.
+ extras: A json-serializable data type to convey extra information about
+ a test result.
+ """
def __init__(self, details, extras=None):
- if not isinstance(details, str):
- raise TestSignalError("Message has to be a string.")
super(TestSignal, self).__init__(details)
- self.details = details
+ try:
+ self.details = str(details)
+ except UnicodeEncodeError:
+ # TODO: remove when we stop supporting Python 2
+ logging.warning(u"Details contain non-ASCII characters: %s",
+ details)
+ self.details = details.encode("utf-8")
try:
json.dumps(extras)
self.extras = extras
diff --git a/runners/host/tcp_client/vts_tcp_client.py b/runners/host/tcp_client/vts_tcp_client.py
index 44a6a20..eec0aa1 100755
--- a/runners/host/tcp_client/vts_tcp_client.py
+++ b/runners/host/tcp_client/vts_tcp_client.py
@@ -175,10 +175,10 @@
target_component_name=None,
hw_binder_service_name=None):
"""RPC to LAUNCH_DRIVER_SERVICE."""
- logging.info("service_name: %s", service_name)
- logging.info("file_path: %s", file_path)
- logging.info("bits: %s", bits)
- logging.info("driver_type: %s", driver_type)
+ logging.debug("service_name: %s", service_name)
+ logging.debug("file_path: %s", file_path)
+ logging.debug("bits: %s", bits)
+ logging.debug("driver_type: %s", driver_type)
self.SendCommand(
SysMsg_pb2.LAUNCH_DRIVER_SERVICE,
driver_type=driver_type,
@@ -192,7 +192,7 @@
target_component_name=target_component_name,
hw_binder_service_name=hw_binder_service_name)
resp = self.RecvResponse()
- logging.info("resp for LAUNCH_DRIVER_SERVICE: %s", resp)
+ logging.debug("resp for LAUNCH_DRIVER_SERVICE: %s", resp)
if driver_type == SysMsg_pb2.VTS_DRIVER_TYPE_HAL_HIDL \
or driver_type == SysMsg_pb2.VTS_DRIVER_TYPE_HAL_CONVENTIONAL \
or driver_type == SysMsg_pb2.VTS_DRIVER_TYPE_HAL_LEGACY:
@@ -207,7 +207,7 @@
"""RPC to LIST_APIS."""
self.SendCommand(SysMsg_pb2.LIST_APIS)
resp = self.RecvResponse()
- logging.info("resp for LIST_APIS: %s", resp)
+ logging.debug("resp for LIST_APIS: %s", resp)
if (resp.response_code == SysMsg_pb2.SUCCESS):
return resp.spec
return None
@@ -298,12 +298,12 @@
logging.exception(e)
logging.error("Paring error\n%s", resp.result)
if result.return_type.type == CompSpecMsg_pb2.TYPE_SUBMODULE:
- logging.info("returned a submodule spec")
- logging.info("spec: %s", result.return_type_submodule_spec)
+ logging.debug("returned a submodule spec")
+ logging.debug("spec: %s", result.return_type_submodule_spec)
return mirror_object.MirrorObject(
self, result.return_type_submodule_spec, None)
- logging.info("result: %s", result.return_type_hidl)
+ logging.debug("result: %s", result.return_type_hidl)
if len(result.return_type_hidl) == 1:
result_value = self.GetPythonDataOfVariableSpecMsg(
result.return_type_hidl[0])
@@ -344,8 +344,8 @@
logging.exception(e)
logging.error("Paring error\n%s", resp.result)
if result.return_type.type == CompSpecMsg_pb2.TYPE_SUBMODULE:
- logging.info("returned a submodule spec")
- logging.info("spec: %s", result.return_type_submodule_spec)
+ logging.debug("returned a submodule spec")
+ logging.debug("spec: %s", result.return_type_submodule_spec)
return mirror_object.MirrorObject(
self, result.return_type_submodule_spec, None)
elif result.return_type.type == CompSpecMsg_pb2.TYPE_SCALAR:
@@ -432,7 +432,7 @@
"""
self.SendCommand(SysMsg_pb2.PING)
resp = self.RecvResponse()
- logging.info("resp for PING: %s", resp)
+ logging.debug("resp for PING: %s", resp)
if resp is not None and resp.response_code == SysMsg_pb2.SUCCESS:
return True
return False
@@ -459,9 +459,9 @@
target_version=target_version,
target_package=target_package)
resp = self.RecvResponse(retries=2)
- logging.info("resp for VTS_AGENT_COMMAND_EXECUTE_READ_INTERFACE: %s",
+ logging.debug("resp for VTS_AGENT_COMMAND_EXECUTE_READ_INTERFACE: %s",
resp)
- logging.info("proto: %s", resp.result)
+ logging.debug("proto: %s", resp.result)
result = CompSpecMsg_pb2.ComponentSpecificationMessage()
if resp.result == "error":
raise errors.VtsTcpCommunicationError(
@@ -521,10 +521,10 @@
command_msg = SysMsg_pb2.AndroidSystemControlCommandMessage()
command_msg.command_type = command_type
- logging.info("sending a command (type %s)",
+ logging.debug("sending a command (type %s)",
COMMAND_TYPE_NAME[command_type])
if command_type == 202:
- logging.info("target API: %s", arg)
+ logging.debug("target API: %s", arg)
if target_class is not None:
command_msg.target_class = target_class
@@ -577,7 +577,7 @@
else:
command_msg.shell_command.append(shell_command)
- logging.info("command %s" % command_msg)
+ logging.debug("command %s" % command_msg)
message = command_msg.SerializeToString()
message_len = len(message)
logging.debug("sending %d bytes", message_len)
@@ -598,7 +598,7 @@
logging.info("retrying...")
header = self.channel.readline().strip("\n")
length = int(header) if header else 0
- logging.info("resp %d bytes", length)
+ logging.debug("resp %d bytes", length)
data = self.channel.read(length)
response_msg = SysMsg_pb2.AndroidSystemControlResponseMessage()
response_msg.ParseFromString(data)
diff --git a/runners/host/tcp_server/callback_server.py b/runners/host/tcp_server/callback_server.py
index f61c19e..cdb23e2 100644
--- a/runners/host/tcp_server/callback_server.py
+++ b/runners/host/tcp_server/callback_server.py
@@ -167,7 +167,7 @@
server_thread = threading.Thread(target=self._server.serve_forever)
server_thread.daemon = True
server_thread.start()
- logging.info('TcpServer %s started (%s:%s)', server_thread.name,
+ logging.debug('TcpServer %s started (%s:%s)', server_thread.name,
self._ip, self._port)
return self._ip, self._port
except (RuntimeError, IOError, socket.error) as e:
diff --git a/runners/host/tcp_server/callback_server_test.py b/runners/host/tcp_server/callback_server_test.py
index ca66573..3edc1b4 100644
--- a/runners/host/tcp_server/callback_server_test.py
+++ b/runners/host/tcp_server/callback_server_test.py
@@ -116,7 +116,7 @@
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
host = self._callback_server.ip
port = self._callback_server.port
- logging.info('Sending Request to host %s using port %s', host, port)
+ logging.debug('Sending Request to host %s using port %s', host, port)
try:
# Connect to server and send request_message
@@ -124,12 +124,12 @@
message = request_message.SerializeToString()
sock.sendall(str(len(message)) + "\n" + message)
- logging.info("Sent: %s", message)
+ logging.debug("Sent: %s", message)
# Receive request_message from the server and shut down
received_message = sock.recv(1024)
response_message.ParseFromString(received_message)
- logging.info('Received: %s', received_message)
+ logging.debug('Received: %s', received_message)
except socket_error as e:
logging.error(e)
raise errors.TcpServerConnectionError('Exception occurred.')
diff --git a/runners/host/test_runner.py b/runners/host/test_runner.py
index 3a9c9b0..4980a02 100644
--- a/runners/host/test_runner.py
+++ b/runners/host/test_runner.py
@@ -106,14 +106,6 @@
test_identifiers = [(test_cls_name, None)]
for config in test_configs:
- if keys.ConfigKeys.KEY_TEST_MAX_TIMEOUT in config:
- timeout_sec = int(config[
- keys.ConfigKeys.KEY_TEST_MAX_TIMEOUT]) / 1000.0
- else:
- timeout_sec = 60 * 60 * 3
- logging.warning("%s unspecified. Set timeout to %s seconds.",
- keys.ConfigKeys.KEY_TEST_MAX_TIMEOUT, timeout_sec)
-
watcher_enabled = threading.Event()
def watchStdin():
@@ -199,7 +191,10 @@
self.log_severity = self.test_configs.get(
keys.ConfigKeys.KEY_LOG_SEVERITY, "INFO").upper()
logger.setupTestLogger(
- self.log_path, self.testbed_name, log_severity=self.log_severity)
+ self.log_path,
+ self.testbed_name,
+ filename="test_run_details.txt",
+ log_severity=self.log_severity)
self.controller_registry = {}
self.controller_destructors = {}
self.run_list = run_list
@@ -310,7 +305,7 @@
ControllerError is raised if no corresponding config can be found,
or if the controller module has already been registered.
"""
- logging.info("cwd: %s", os.getcwd())
+ logging.debug("cwd: %s", os.getcwd())
logging.info("adb devices: %s", module.list_adb_devices())
self.verifyControllerModule(module)
module_ref_name = module.__name__.split('.')[-1]
@@ -335,7 +330,7 @@
for config in controller_config:
if isinstance(config, dict):
config["log_severity"] = self.log_severity
- logging.info("controller_config: %s", controller_config)
+ logging.debug("controller_config: %s", controller_config)
if "use_vts_agent" not in self.testbed_configs:
objects = create(controller_config, start_services)
else:
diff --git a/runners/host/utils.py b/runners/host/utils.py
index 834ef1b..972d991 100755
--- a/runners/host/utils.py
+++ b/runners/host/utils.py
@@ -221,10 +221,10 @@
pypath = os.environ['PYTHONPATH']
if pypath:
for base_path in pypath.split(':'):
- logging.info('checking %s', base_path)
+ logging.debug('checking base_path %s', base_path)
new_path = os.path.join(base_path, file_full_path)
if os.path.isfile(new_path):
- logging.info('found')
+ logging.debug('new_path %s found', new_path)
file_full_path = new_path
break
@@ -362,6 +362,36 @@
return os.name == "nt"
+def kill_process_group(proc, signal_no=signal.SIGTERM):
+ """Sends signal to a process group.
+
+ Logs when there is an OSError or PermissionError. The latter one only
+ happens on Mac.
+
+ On Windows, SIGABRT, SIGINT, and SIGTERM are replaced with CTRL_BREAK_EVENT
+ so as to kill every subprocess in the group.
+
+ Args:
+ proc: The Popen object whose pid is the group id.
+ signal_no: The signal sent to the subprocess group.
+ """
+ pid = proc.pid
+ try:
+ if not is_on_windows():
+ os.killpg(pid, signal_no)
+ else:
+ if signal_no in [signal.SIGABRT,
+ signal.SIGINT,
+ signal.SIGTERM]:
+ windows_signal_no = signal.CTRL_BREAK_EVENT
+ else:
+ windows_signal_no = signal_no
+ os.kill(pid, windows_signal_no)
+ except (OSError, PermissionError) as e:
+ logging.exception("Cannot send signal %s to process group %d: %s",
+ signal_no, pid, str(e))
+
+
def start_standing_subprocess(cmd, check_health_delay=0):
"""Starts a long-running subprocess.
@@ -403,38 +433,19 @@
return proc
-def stop_standing_subprocess(proc, kill_signal=signal.SIGTERM):
+def stop_standing_subprocess(proc, signal_no=signal.SIGTERM):
"""Stops a subprocess started by start_standing_subprocess.
Before killing the process, we check if the process is running, if it has
terminated, VTSUtilsError is raised.
- Catches and logs the PermissionError which only happens on Macs.
-
- On Windows, SIGABRT, SIGINT, and SIGTERM are replaced with CTRL_BREAK_EVENT
- so as to kill every subprocess in the group.
-
Args:
proc: Subprocess to terminate.
- kill_signal: The signal sent to the subprocess group.
+ signal_no: The signal sent to the subprocess group.
"""
- pid = proc.pid
- logging.debug("Stop standing subprocess %d", pid)
+ logging.debug("Stop standing subprocess %d", proc.pid)
_assert_subprocess_running(proc)
- if not is_on_windows():
- try:
- os.killpg(pid, kill_signal)
- except PermissionError as e:
- logging.warning("os.killpg(%d, %s) PermissionError: %s",
- pid, str(kill_signal), str(e))
- else:
- if kill_signal in [signal.SIGABRT,
- signal.SIGINT,
- signal.SIGTERM]:
- windows_signal = signal.CTRL_BREAK_EVENT
- else:
- windows_signal = kill_signal
- os.kill(pid, windows_signal)
+ kill_process_group(proc, signal_no)
def wait_for_standing_subprocess(proc, timeout=None):
diff --git a/runners/target/vts_hal_hidl_target/Android.bp b/runners/target/vts_hal_hidl_target/Android.bp
index c74582f..cda56ff 100644
--- a/runners/target/vts_hal_hidl_target/Android.bp
+++ b/runners/target/vts_hal_hidl_target/Android.bp
@@ -25,14 +25,18 @@
cflags: ["-Wall", "-Werror"],
shared_libs: [
- "libbase",
"libhidlbase",
"liblog",
- "libutils",
"libcutils",
],
- static_libs : ["libgtest"],
+ static_libs : [
+ "libgtest",
+ "libutils",
+ ],
export_include_dirs: ["."],
- export_static_lib_headers: ["libgtest"],
+ export_static_lib_headers: [
+ "libgtest",
+ "libutils",
+ ],
}
diff --git a/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestBase.h b/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestBase.h
index 8214630..dafeca2 100644
--- a/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestBase.h
+++ b/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestBase.h
@@ -17,11 +17,11 @@
#ifndef __VTS_HAL_HIDL_TARGET_TEST_BASE_H
#define __VTS_HAL_HIDL_TARGET_TEST_BASE_H
+#include <VtsHalHidlTargetTestEnvBase.h>
#include <gtest/gtest.h>
#include <hidl/HidlSupport.h>
-#include <utils/Log.h>
+#include <log/log.h>
#include <utils/RefBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#define VTS_HAL_HIDL_GET_STUB "VTS_HAL_HIDL_GET_STUB"
diff --git a/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestEnvBase.cpp b/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestEnvBase.cpp
index 6b6b6a1..cd96fbc 100644
--- a/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestEnvBase.cpp
+++ b/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestEnvBase.cpp
@@ -20,7 +20,7 @@
#include <string>
-#include <utils/Log.h>
+#include <log/log.h>
static constexpr const char* kListFlag = "--list_registered_services";
static constexpr const char* kServiceInstanceFlag = "--hal_service_instance";
@@ -125,6 +125,7 @@
for (string service : registeredHalServices_) {
printf("hal_service: %s\n", service.c_str());
}
+ printf("service_comb_mode: %d\n", mode_);
}
} // namespace testing
diff --git a/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestEnvBase.h b/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestEnvBase.h
index 9fb44e5..4a554b9 100644
--- a/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestEnvBase.h
+++ b/runners/target/vts_hal_hidl_target/VtsHalHidlTargetTestEnvBase.h
@@ -25,6 +25,22 @@
namespace testing {
+// Enum class indicates the required combination mode for registered services.
+enum HalServiceCombMode {
+ // Get the full permutation of all the registered service instances.
+ // E.g. Hal service s1 with instances (n1, n2) and s2 with instances (n3, n4),
+ // Return combination (s1/n1, s2/n3), (s1/n1, s2/n4), (s1/n2, s2/n3),
+ // (s1/n2, s2/n4).
+ FULL_PERMUTATION = 0,
+ // Get the registered service instances with the same service name.
+ // E.g. Hal service s1 with instances (n1, n2) and s2 with instances (n1, n2),
+ // Return combination (s1/n1, s2/n1), (s1/n2, s2/n2).
+ NAME_MATCH,
+ // Do not return the service instance combinations. This is used in cases when
+ // the test logic specifically handles the testing instances. E.g. drm tests.
+ NO_COMBINATION,
+};
+
// A class for test environment setup
class VtsHalHidlTargetTestEnvBase : public ::testing::Environment {
public:
@@ -78,6 +94,8 @@
return getServiceName(T::descriptor, defaultName);
}
+ void setServiceCombMode(HalServiceCombMode mode) { mode_ = mode; }
+
private:
/*
* Parses VTS specific flags, currently support two flags:
@@ -119,6 +137,8 @@
bool listService_ = false;
// Flag whether init is called.
bool inited_ = false;
+ // Required combination mode for hal service instances.
+ HalServiceCombMode mode_ = HalServiceCombMode::FULL_PERMUTATION;
};
} // namespace testing
diff --git a/script/create-test-project.py b/script/create-test-project.py
index 471dbe0..87f4788 100755
--- a/script/create-test-project.py
+++ b/script/create-test-project.py
@@ -42,16 +42,19 @@
build_top: string, equal to environment variable ANDROID_BUILD_TOP
test_dir: string, test case absolute directory
test_name: string, test case name in UpperCamel
+ test_plan: string, the plan that the test belongs to
test_type: test type, such as HidlHalTest, HostDrivenTest, etc
current_year: current year
vts_test_case_dir: absolute dir of vts testcases directory
'''
- def __init__(self, test_name, test_dir_under_testcases, test_type):
+ def __init__(self, test_name, test_plan, test_dir_under_testcases,
+ test_type):
'''Initialize class attributes.
Args:
test_name: string, test case name in UpperCamel
+ test_plan: string, the plan that the test belongs to
test_dir_under_testcases: string, test case relative directory under
test/vts/testcases.
'''
@@ -66,6 +69,11 @@
sys.exit(4)
self.test_name = test_name
+ if not test_plan:
+ self.test_plan = 'vts-misc'
+ else:
+ self.test_plan = test_plan
+
if not test_type:
self.test_type = 'HidlHalTest'
else:
@@ -178,6 +186,7 @@
f.write(
ANDROID_TEST_XML_TEMPLATE.format(
test_name=self.test_name,
+ test_plan=self.test_plan,
test_type=self.test_type,
test_path_under_vts=self.test_dir[
len(os.path.join(self.build_top, VTS_PATH)) + 1:],
@@ -202,6 +211,11 @@
required=True,
help='Test case name in UpperCamel. Example: VtsKernelLtp')
parser.add_argument(
+ '--plan',
+ dest='test_plan',
+ required=False,
+ help='The plan that the test belongs to. Example: vts-kernel')
+ parser.add_argument(
'--dir',
dest='test_dir',
required=True,
@@ -213,8 +227,8 @@
help='Test type, such as HidlHalTest, HostDrivenTest, etc.')
args = parser.parse_args()
- test_case_creater = TestCaseCreator(args.test_name, args.test_dir,
- args.test_type)
+ test_case_creater = TestCaseCreator(args.test_name, args.test_plan,
+ args.test_dir, args.test_type)
test_case_creater.InitTestCaseDir()
@@ -271,11 +285,10 @@
'''
ANDROID_TEST_XML_TEMPLATE = '''<configuration description="Config for VTS {test_name} test cases">
+ <option name="config-descriptor:metadata" key="plan" value="{test_plan}" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="{test_type}.push" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="{test_name}" />
<option name="test-case-path" value="vts/{test_path_under_vts}/{test_case_file_without_extension}" />
diff --git a/script/cts_test_list.txt b/script/cts_test_list.txt
index 2fbf521..1af7d8a 100644
--- a/script/cts_test_list.txt
+++ b/script/cts_test_list.txt
@@ -40,7 +40,6 @@
CtsDisplayTestCases
CtsDpiTestCases
CtsDpiTestCases2
-CtsDramTestCases
CtsDreamsTestCases
CtsDrmTestCases
CtsDumpsysHostTestCases
@@ -70,7 +69,6 @@
CtsKeystoreTestCases
CtsLeanbackJankTestCases
CtsLibcoreFileIOTestCases
-CtsLibcoreJavaUtilCollectionsTestCases
CtsLibcoreJsr166TestCases
CtsLibcoreLegacy22TestCases
CtsLibcoreOjTestCases
diff --git a/script/diagnose.py b/script/diagnose.py
old mode 100644
new mode 100755
index 6a6b976..479c987
--- a/script/diagnose.py
+++ b/script/diagnose.py
@@ -51,6 +51,9 @@
# Get target device info with adb
runCommand('adb shell getprop ro.build.fingerprint', 'Target device info [ro.build.fingerprint]')
+ runCommand('adb shell lshal --init-vintf', 'Read HAL Info')
+ runCommand('adb shell cat /vendor/manifest.xml', 'Read vendor/manifest.xml')
+
if __name__ == "__main__":
main()
diff --git a/script/monitor-runner-output.py b/script/monitor-runner-output.py
deleted file mode 100755
index 243cb64..0000000
--- a/script/monitor-runner-output.py
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2016 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.
-#
-
-import os
-import sys
-import time
-
-LOG_DIR = '/tmp'
-
-
-def GetLatestLog():
- '''Find the latest vts runner log folder in log directory and return its content.
-
- Returns:
- (string, string), returns the latest log file path and log content
- '''
- folders = [os.path.join(LOG_DIR, folder_name)
- for folder_name in os.listdir(LOG_DIR)
- if os.path.isdir(os.path.join(LOG_DIR, folder_name)) and
- folder_name.startswith('vts-runner-log')]
-
- try:
- folders.sort(
- lambda folder1, folder2: int(os.path.getmtime(folder1) - os.path.getmtime(folder2)))
- folder_latest = folders[-1]
- log_path_latest = os.path.join(folder_latest,
- os.listdir(folder_latest)[0], 'latest',
- 'test_run_details.txt')
- with open(log_path_latest, 'r') as log_latest:
- return (log_path_latest, log_latest.read())
- except Exception as e:
- return (None, None)
-
-
-def StartMonitoring(path_only):
- '''Pull the latest vts runner log in a loop, and print out any new contents.
-
- Args:
- path_only: bool, only print out the latest log path in temporary directory.
- '''
- is_first_time = True
- last_log_path = None
- last_text = ''
- while True:
- log_path_latest, text_latest = GetLatestLog()
-
- if path_only:
- print log_path_latest
- return
-
- if log_path_latest is None: # Case: cannot find any runner log
- time.sleep(2)
- continue
-
- if last_log_path == log_path_latest:
- text_new = text_latest[len(last_text):]
- last_text = text_latest
- if text_new: # Case: runner log file changed
- if is_first_time:
- is_first_time = False
- print text_new
- continue
- lines = text_new.split('\n')
- for l in lines:
- print l
- time.sleep(0.6 / len(lines))
- else: # Case: runner log file didn't change
- time.sleep(1)
- else: # Case: found a new runner log file
- last_text = ''
- last_log_path = log_path_latest
- print '\n' * 6 + '=' * 24 + 'new file' + '=' * 24 + '\n' * 6
- time.sleep(1)
-
-
-def PrintUsage():
- print 'A script to read VTS Runner\'s log from temporary directory.'
- print 'Usage:'
- print ' -h, --help: print usage.'
- print ' -p, --path-only: print path to the latest runner file only.'
- print ' You may pipe the result to vim for searching.'
- print ' Example: script/monitor-runner-output.py --path-only | xargs gedit'
- print ' -m, --monitor: print VTS runner\'s output in close to real time'
- print ' If no argument is provided, this script will keep pulling the latest log and print it out.'
-
-
-if __name__ == "__main__":
- argv = sys.argv
- path_only = False
- if len(argv) == 1 or argv[1] == '-h' or argv[1] == '--help':
- PrintUsage()
- exit()
- elif argv[1] == '-p' or argv[1] == '--path-only':
- path_only = True
- elif argv[1] == '-m' or argv[1] == '--monitor':
- path_only = False
- StartMonitoring(path_only)
diff --git a/script/pip_requirements.txt b/script/pip_requirements.txt
index 90dd6bd..d89e230 100644
--- a/script/pip_requirements.txt
+++ b/script/pip_requirements.txt
@@ -18,3 +18,6 @@
# Required packages for Kernel tests
parse
ply
+
+# Required packages for USB gadget tests
+libusb1
diff --git a/script/run-unittest.sh b/script/run-unittest.sh
index d4346ea..3943e51 100755
--- a/script/run-unittest.sh
+++ b/script/run-unittest.sh
@@ -17,6 +17,11 @@
pushd ${ANDROID_BUILD_TOP}/test/vts
PYTHONPATH=$PYTHONPATH:.. python -m vts.runners.host.tcp_server.callback_server_test
PYTHONPATH=$PYTHONPATH:.. python -m vts.utils.python.coverage.coverage_report_test
-PYTHONPATH=$PYTHONPATH:.. python -m vts.harnesses.host_controller.build.pab_client_test
+PYTHONPATH=$PYTHONPATH:.. python -m vts.harnesses.host_controller.build.build_provider_pab_test
+PYTHONPATH=$PYTHONPATH:.. python -m vts.utils.python.controllers.android_device_test
+PYTHONPATH=$PYTHONPATH:.. python -m vts.utils.python.controllers.customflasher_test
+PYTHONPATH=$PYTHONPATH:..:../framework/harnesses/ python -m host_controller.build.build_flasher_test
+PYTHONPATH=$PYTHONPATH:..:../framework/harnesses/ python -m host_controller.build.build_provider_test
+PYTHONPATH=$PYTHONPATH:..:../framework/harnesses/ python -m host_controller.console_test
+PYTHONPATH=$PYTHONPATH:.. python -m vts.utils.python.io.file_util_test
popd
-
diff --git a/script/run_cts_with_profiling.sh b/script/run_cts_with_profiling.sh
index d64158c..07cc8c7 100755
--- a/script/run_cts_with_profiling.sh
+++ b/script/run_cts_with_profiling.sh
@@ -14,89 +14,70 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# allow write to /system partition
-adb root
-adb disable-verity
-adb reboot
-adb wait-for-device
-adb root
-adb remount
+serial_no=$1
+if [ -z "$serial_no" ]
+then
+ echo "Must provide serial number of the testing device."
+ exit
+fi
+
+local_trace_dir=$2
+if [ -z "$local_trace_dir" ]
+then
+ local_trace_dir=/usr/local/backup/cts-traces
+fi
+
+test_list=$3
+if [ -z "$test_list" ]
+then
+ test_list=${ANDROID_BUILD_TOP}/test/vts/script/cts_test_list.txt
+fi
+
+# allow write to /vendor partition
+adb -s $serial_no root
+adb -s $serial_no disable-verity
+adb -s $serial_no reboot
+adb -s $serial_no wait-for-device
+adb -s $serial_no root
+adb -s $serial_no remount
+adb -s $serial_no shell setenforce 0
+adb -s $serial_no shell chmod 777 -R data/local/tmp
# push profiler libs
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.audio@2.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.audio.common@2.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.audio.effect@2.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.automotive.vehicle@2.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.automotive.vehicle@2.1-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.biometrics.fingerprint@2.1-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.bluetooth@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.boot@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.broadcastradio@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.camera.common@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.camera.device@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.camera.device@3.2-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.camera.metadata@3.2-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.camera.provider@2.4-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.configstore@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.contexthub@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.drm@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.dumpstate@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.gatekeeper@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.gnss@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.graphics.allocator@2.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.graphics.common@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.graphics.composer@2.1-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.graphics.mapper@2.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.health@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.ir@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.keymaster@3.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.light@2.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.media.omx@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.memtrack@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.nfc@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.power@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.radio@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.sensors@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.soundtrigger@2.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.thermal@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.tv.cec@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.tv.input@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.usb@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.vibrator@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.vr@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.wifi@1.0-vts.profiler.so system/lib64/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/android.hardware.wifi.supplicant@1.0-vts.profiler.so system/lib64/
+adb -s $serial_no push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/*-vts.profiler.so vendor/lib64/
+adb -s $serial_no push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib/*-vts.profiler.so vendor/lib/
+adb -s $serial_no push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib64/libvts_* vendor/lib64/
+adb -s $serial_no push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/lib/libvts_* vendor/lib/
-adb push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/bin/vts_profiling_configure /data/local/tmp/
+# push vts_profiling_configure
+adb -s $serial_no push ${ANDROID_BUILD_TOP}/out/host/linux-x86/vts/android-vts/testcases/DATA/bin/vts_profiling_configure /data/local/tmp/
# get cts testcases
tests=()
while read -r test
do
tests+=($test)
-done < "${ANDROID_BUILD_TOP}/test/vts/script/cts_test_list.txt"
+done < "$test_list"
# run cts testcases
-DATE=`date +%Y-%m-%d`
for i in ${tests[@]}
do
echo Running $i
- adb shell rm /data/local/tmp/*.vts.trace
- adb reboot
- adb wait-for-device
- adb root
- sleep 5
- adb shell setenforce 0
- adb shell chmod 777 -R data/local/tmp
- adb shell ./data/local/tmp/vts_profiling_configure enable /system/lib64/
- cts-tradefed run commandAndExit cts --skip-device-info --skip-system-status-check com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker --skip-system-status-check com.android.tradefed.suite.checker.KeyguardStatusChecker -m $i
- adb shell ls /data/local/tmp/*.vts.trace > temp
- trace_path=$1/cts-traces/$DATE/$i
+ adb -s $serial_no shell rm /data/local/tmp/*.vts.trace
+ adb -s $serial_no shell ./data/local/tmp/vts_profiling_configure enable /vendor/lib/ /vendor/lib64/
+ cts-tradefed run commandAndExit cts -s $serial_no --primary-abi-only --skip-device-info \
+ --skip-system-status-check com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker \
+ --skip-system-status-check com.android.tradefed.suite.checker.KeyguardStatusChecker -m $i
+ # In case device restart during the test run.
+ adb -s $serial_no root
+ adb -s $serial_no shell setenforce 0
+ adb -s $serial_no shell ls /data/local/tmp/*.vts.trace > temp
+ trace_path=$local_trace_dir/$i
rm -rf $trace_path
mkdir -p $trace_path
while read -r trace
do
- adb pull $trace $trace_path
+ adb -s $serial_no pull $trace $trace_path
done < "temp"
done
diff --git a/script/setup.sh b/script/setup.sh
index 7ca29e8..dec3adb 100755
--- a/script/setup.sh
+++ b/script/setup.sh
@@ -27,8 +27,12 @@
sudo apt-get -y install python-pip
sudo apt-get -y install python3-pip
sudo apt-get -y install python-virtualenv
+sudo apt-get -y install build-essential
echo "Install packages for Camera ITS tests"
sudo apt-get -y install python-tk
sudo apt-get -y install libjpeg-dev
sudo apt-get -y install libtiff-dev
+
+echo "Install packaged for usb gadget tests"
+sudo pip install --upgrade libusb1
diff --git a/script/target/vts_adapter.sh b/script/target/vts_adapter.sh
new file mode 100755
index 0000000..d22240d
--- /dev/null
+++ b/script/target/vts_adapter.sh
@@ -0,0 +1,4 @@
+#!/system/bin/sh
+echo "start $1 -p $2 $3 $4"
+nohup $1 -p $2 $3 $4 &>/dev/null &
+echo "done"
diff --git a/testcases/Android.bp b/testcases/Android.bp
new file mode 100644
index 0000000..cb54aaa
--- /dev/null
+++ b/testcases/Android.bp
@@ -0,0 +1,18 @@
+// Copyright (C) 2018 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.
+
+subdirs = [
+ "manual_tests/flaky_test",
+ "manual_tests/zero_testcase_binary_test",
+]
diff --git a/testcases/codelab/hello_world/Android.mk b/testcases/codelab/hello_world/Android.mk
index f5e9f5b..112126d 100644
--- a/testcases/codelab/hello_world/Android.mk
+++ b/testcases/codelab/hello_world/Android.mk
@@ -17,5 +17,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := VtsCodelabHelloWorldTest
-VTS_CONFIG_SRC_DIR := testcases/codelab/hello_world
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/codelab/hello_world/AndroidTest.xml b/testcases/codelab/hello_world/AndroidTest.xml
index 54188b9..31ea20d 100644
--- a/testcases/codelab/hello_world/AndroidTest.xml
+++ b/testcases/codelab/hello_world/AndroidTest.xml
@@ -14,11 +14,10 @@
limitations under the License.
-->
<configuration description="Config for VTS CodeLab HelloWorld test case">
+ <option name="config-descriptor:metadata" key="plan" value="vts-codelab" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="VtsCodelabHelloWorldTest"/>
<option name="test-case-path" value="vts/testcases/codelab/hello_world/VtsCodelabHelloWorldTest" />
diff --git a/tools/vts-hc/Android.mk b/testcases/codelab/hello_world_multi/Android.mk
similarity index 85%
rename from tools/vts-hc/Android.mk
rename to testcases/codelab/hello_world_multi/Android.mk
index 7733142..6ef6730 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/codelab/hello_world_multi/Android.mk
@@ -1,3 +1,4 @@
+#
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsCodelabHelloWorldMultiDeviceTest
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/codelab/hello_world_multi/AndroidTest.xml b/testcases/codelab/hello_world_multi/AndroidTest.xml
new file mode 100644
index 0000000..f123c20
--- /dev/null
+++ b/testcases/codelab/hello_world_multi/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for VTS CodeLab HelloWorld test case">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
+
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsCodelabHelloWorldMultiDeviceTest"/>
+ <option name="test-case-path" value="vts/testcases/codelab/hello_world_multi/VtsCodelabHelloWorldMultiDeviceTest" />
+ </test>
+
+</configuration>
diff --git a/testcases/codelab/hello_world_multi/VtsCodelabHelloWorldMultiDeviceTest.py b/testcases/codelab/hello_world_multi/VtsCodelabHelloWorldMultiDeviceTest.py
new file mode 100644
index 0000000..39c2434
--- /dev/null
+++ b/testcases/codelab/hello_world_multi/VtsCodelabHelloWorldMultiDeviceTest.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 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.
+#
+
+import logging
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test
+from vts.runners.host import const
+from vts.runners.host import test_runner
+
+
+class VtsCodelabHelloWorldTest(base_test.BaseTestClass):
+ '''Two hello world test cases which use the shell driver.'''
+
+ def setUpClass(self):
+ logging.info('number of device: %s', self.android_devices)
+
+ asserts.assertEqual(
+ len(self.android_devices), 2, 'number of device is wrong.')
+
+ self.dut1 = self.android_devices[0]
+ self.dut2 = self.android_devices[1]
+ self.shell1 = self.dut1.shell
+ self.shell2 = self.dut2.shell
+
+ def testHelloWorld(self):
+ '''A simple testcase which sends a hello world command.'''
+ command = 'echo Hello World!'
+
+ res1 = self.shell1.Execute(command)
+ res2 = self.shell2.Execute(command)
+
+ asserts.assertFalse(
+ any(res1[const.EXIT_CODE]),
+ 'command for device 1 failed: %s' % res1) # checks the exit code
+ asserts.assertFalse(
+ any(res2[const.EXIT_CODE]),
+ 'command for device 2 failed: %s' % res2) # checks the exit code
+
+ def testSerialNotEqual(self):
+ '''Checks serial number from two device not being equal.'''
+ command = 'getprop | grep ro.serial'
+
+ res1 = self.shell1.Execute(command)
+ res2 = self.shell2.Execute(command)
+
+ asserts.assertFalse(
+ any(res1[const.EXIT_CODE]),
+ 'command for device 1 failed: %s' % res1) # checks the exit code
+ asserts.assertFalse(
+ any(res2[const.EXIT_CODE]),
+ 'command for device 2 failed: %s' % res2) # checks the exit code
+
+ def getSerial(output):
+ '''Get serial from getprop query'''
+ return output.strip().split(' ')[-1][1:-1]
+
+ serial1 = getSerial(res1[const.STDOUT][0])
+ serial2 = getSerial(res2[const.STDOUT][0])
+
+ logging.info('Serial number of device 1: %s', serial1)
+ logging.info('Serial number of device 2: %s', serial2)
+
+ asserts.assertNotEqual(
+ serial1, serial2,
+ 'serials from two devices should not be the same')
+
+
+if __name__ == '__main__':
+ test_runner.main()
diff --git a/harnesses/host_controller/__init__.py b/testcases/codelab/hello_world_multi/__init__.py
similarity index 100%
copy from harnesses/host_controller/__init__.py
copy to testcases/codelab/hello_world_multi/__init__.py
diff --git a/testcases/codelab/hello_world_sl4a/Android.mk b/testcases/codelab/hello_world_sl4a/Android.mk
index 9842223..f84424f 100644
--- a/testcases/codelab/hello_world_sl4a/Android.mk
+++ b/testcases/codelab/hello_world_sl4a/Android.mk
@@ -17,5 +17,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := VtsCodelabHelloWorldSl4aTest
-VTS_CONFIG_SRC_DIR := testcases/codelab/hello_world_sl4a
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/codelab/hello_world_sl4a/AndroidTest.xml b/testcases/codelab/hello_world_sl4a/AndroidTest.xml
index ad22896..83111f9 100644
--- a/testcases/codelab/hello_world_sl4a/AndroidTest.xml
+++ b/testcases/codelab/hello_world_sl4a/AndroidTest.xml
@@ -17,8 +17,6 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="test-file-name" value="DATA/app/sl4a/sl4a.apk" />
<option name="cleanup-apks" value="true" />
@@ -26,6 +24,6 @@
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="VtsCodelabHelloWorldSl4aTest"/>
<option name="test-case-path" value="vts/testcases/codelab/hello_world_sl4a/VtsCodelabHelloWorldSl4aTest" />
- <option name="test-config-path" value="vts/testcases/codelab/hello_world_sl4a/VtsCodelabHelloWorldSl4aTest.config" />
+ <option name="test-config-path" value="vts/testcases/codelab/hello_world_sl4a/VtsCodelabHelloWorldSl4aTest.runner_conf" />
</test>
</configuration>
diff --git a/testcases/codelab/hello_world_sl4a/VtsCodelabHelloWorldSl4aTest.config b/testcases/codelab/hello_world_sl4a/VtsCodelabHelloWorldSl4aTest.runner_conf
similarity index 100%
rename from testcases/codelab/hello_world_sl4a/VtsCodelabHelloWorldSl4aTest.config
rename to testcases/codelab/hello_world_sl4a/VtsCodelabHelloWorldSl4aTest.runner_conf
diff --git a/testcases/codelab/hello_world_staging/Android.mk b/testcases/codelab/hello_world_staging/Android.mk
index 7214323..331c7ec 100644
--- a/testcases/codelab/hello_world_staging/Android.mk
+++ b/testcases/codelab/hello_world_staging/Android.mk
@@ -19,5 +19,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := VtsCodelabHelloWorldStagingTest
-VTS_CONFIG_SRC_DIR := testcases/codelab/hello_world_staging
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/codelab/hello_world_staging/AndroidTest.xml b/testcases/codelab/hello_world_staging/AndroidTest.xml
index c22a03d..39f536f 100644
--- a/testcases/codelab/hello_world_staging/AndroidTest.xml
+++ b/testcases/codelab/hello_world_staging/AndroidTest.xml
@@ -14,11 +14,10 @@
limitations under the License.
-->
<configuration description="Config for VTS CodeLab HelloWorld Staging test case">
+ <option name="config-descriptor:metadata" key="plan" value="vts-codelab" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="VtsCodelabHelloWorldStagingTest" />
<option name="test-case-path" value="vts/testcases/codelab/hello_world/VtsCodelabHelloWorldTest" />
diff --git a/testcases/codelab/host_multi_hal/Android.mk b/testcases/codelab/host_multi_hal/Android.mk
index 61b4dba..67e6405 100644
--- a/testcases/codelab/host_multi_hal/Android.mk
+++ b/testcases/codelab/host_multi_hal/Android.mk
@@ -19,5 +19,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := VtsCodelabHostDrivenMultiHalTest
-VTS_CONFIG_SRC_DIR := testcases/codelab/host_multi_hal
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/codelab/host_multi_hal/AndroidTest.xml b/testcases/codelab/host_multi_hal/AndroidTest.xml
index 73be01b..f8dba0b 100644
--- a/testcases/codelab/host_multi_hal/AndroidTest.xml
+++ b/testcases/codelab/host_multi_hal/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for VtsCodelabHostDrivenMultiHalTest test case">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
<option name="push" value="spec/hardware/interfaces/thermal/1.0/vts/Thermal.vts->/data/local/tmp/spec/android/hardware/thermal/1.0/Theraml.vts"/>
@@ -25,8 +26,6 @@
<option name="push" value="DATA/lib/android.hardware.light@2.0-vts.driver.so->/data/local/tmp/32/android.hardware.light@2.0-vts.driver.so"/>
<option name="push" value="DATA/lib64/android.hardware.light@2.0-vts.driver.so->/data/local/tmp/64/android.hardware.light@2.0-vts.driver.so"/>
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="VtsCodelabHostDrivenMultiHalTest" />
<option name="test-case-path" value="vts/testcases/codelab/host_multi_hal/VtsCodelabHostMultiHalTest" />
diff --git a/testcases/codelab/target_binary/Android.mk b/testcases/codelab/target_binary/Android.mk
index fe5ba4b..b46364d 100644
--- a/testcases/codelab/target_binary/Android.mk
+++ b/testcases/codelab/target_binary/Android.mk
@@ -26,5 +26,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := VtsCodelabTargetBinary
-VTS_CONFIG_SRC_DIR := testcases/codelab/target_binary
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/codelab/target_binary/AndroidTest.xml b/testcases/codelab/target_binary/AndroidTest.xml
index b399a36..bd5120f 100644
--- a/testcases/codelab/target_binary/AndroidTest.xml
+++ b/testcases/codelab/target_binary/AndroidTest.xml
@@ -14,12 +14,14 @@
limitations under the License.
-->
<configuration description="Config for VTS Target-Side Binary Codelab test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-codelab" />
+ <option name="config-descriptor:metadata" key="plan" value="vts-staging-selftest" />
+
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
<option name="push" value="DATA/nativetest/vts_codelab_target_binary->/data/nativetest/vts_codelab_target_binary" />
<option name="push" value="DATA/nativetest64/vts_codelab_target_binary->/data/nativetest64/vts_codelab_target_binary" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="VtsCodelabTargetBinary" />
<option name="binary-test-source" value="_32bit::DATA/nativetest/vts_codelab_target_binary/vts_codelab_target_binary->/data/nativetest/vts_codelab_target_binary/vts_codelab_target_binary" />
diff --git a/testcases/codelab/target_binary/vts_codelab_target_binary.c b/testcases/codelab/target_binary/vts_codelab_target_binary.c
index 3f15d8e..3b2038e 100644
--- a/testcases/codelab/target_binary/vts_codelab_target_binary.c
+++ b/testcases/codelab/target_binary/vts_codelab_target_binary.c
@@ -17,7 +17,7 @@
#include <stdio.h>
#define LOG_TAG "VtsCodelabTargetBinary"
-#include <utils/Log.h>
+#include <log/log.h>
int main() {
printf("hello Android");
diff --git a/testcases/fuzz/lib_bionic/LibBionicLibmFuzzTest.config b/testcases/fuzz/lib_bionic/LibBionicLibmFuzzTest.runner_conf
similarity index 100%
rename from testcases/fuzz/lib_bionic/LibBionicLibmFuzzTest.config
rename to testcases/fuzz/lib_bionic/LibBionicLibmFuzzTest.runner_conf
diff --git a/testcases/host/camera_its/Android.mk b/testcases/host/camera_its/Android.mk
index d29f058..addbe82 100644
--- a/testcases/host/camera_its/Android.mk
+++ b/testcases/host/camera_its/Android.mk
@@ -18,5 +18,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := CameraITSTest
-VTS_CONFIG_SRC_DIR := testcases/host/camera_its
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/host/camera_its/AndroidTest.xml b/testcases/host/camera_its/AndroidTest.xml
index 0973b6e..cb849c7 100644
--- a/testcases/host/camera_its/AndroidTest.xml
+++ b/testcases/host/camera_its/AndroidTest.xml
@@ -14,21 +14,23 @@
limitations under the License.
-->
<configuration description="Config for VTS CameraITS test case">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
<option name="cleanup" value="true" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
+ <multi_target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
<option name="dep-module" value="numpy" />
<option name="dep-module" value="scipy" />
<option name="dep-module" value="matplotlib" />
<option name="dep-module" value="Pillow" />
- </target_preparer>
+ </multi_target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="test-file-name" value="DATA/app/CtsVerifier/CtsVerifier.apk" />
<option name="cleanup-apks" value="true" />
</target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="CameraITSTest" />
<option name="test-case-path" value="vts/testcases/host/camera_its/CameraITSTest" />
</test>
</configuration>
diff --git a/testcases/host/reboot/RebootRootRemountTest/Android.mk b/testcases/host/reboot/RebootRootRemountTest/Android.mk
index 40d167e..1356c5e 100644
--- a/testcases/host/reboot/RebootRootRemountTest/Android.mk
+++ b/testcases/host/reboot/RebootRootRemountTest/Android.mk
@@ -18,5 +18,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := RebootRootRemountTest
-VTS_CONFIG_SRC_DIR := testcases/host/reboot/RebootRootRemountTest
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/host/reboot/RebootRootRemountTest/AndroidTest.xml b/testcases/host/reboot/RebootRootRemountTest/AndroidTest.xml
index a4873ef..08dfe24 100644
--- a/testcases/host/reboot/RebootRootRemountTest/AndroidTest.xml
+++ b/testcases/host/reboot/RebootRootRemountTest/AndroidTest.xml
@@ -14,11 +14,10 @@
limitations under the License.
-->
<configuration description="Config for VTS HAL shell test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="RebootRootRemountTest" />
<option name="test-case-path" value="vts/testcases/host/reboot/RebootRootRemountTest/RebootRootRemountTest" />
diff --git a/testcases/host/reboot/RebootTest/Android.mk b/testcases/host/reboot/RebootTest/Android.mk
index dbd8e9f..0c24451 100644
--- a/testcases/host/reboot/RebootTest/Android.mk
+++ b/testcases/host/reboot/RebootTest/Android.mk
@@ -18,5 +18,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := RebootTest
-VTS_CONFIG_SRC_DIR := testcases/host/reboot/RebootTest
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/host/reboot/RebootTest/AndroidTest.xml b/testcases/host/reboot/RebootTest/AndroidTest.xml
index b520088..33606e1 100644
--- a/testcases/host/reboot/RebootTest/AndroidTest.xml
+++ b/testcases/host/reboot/RebootTest/AndroidTest.xml
@@ -14,11 +14,10 @@
limitations under the License.
-->
<configuration description="Config for VTS HAL shell test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="RebootTest" />
<option name="test-case-path" value="vts/testcases/host/reboot/RebootTest/RebootTest" />
diff --git a/testcases/host/shell/Android.mk b/testcases/host/shell/Android.mk
index c150da6..13ffbd0 100644
--- a/testcases/host/shell/Android.mk
+++ b/testcases/host/shell/Android.mk
@@ -18,5 +18,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := SampleShellTest
-VTS_CONFIG_SRC_DIR := testcases/host/shell
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/host/shell/AndroidTest.xml b/testcases/host/shell/AndroidTest.xml
index 4da0c4e..859a795 100644
--- a/testcases/host/shell/AndroidTest.xml
+++ b/testcases/host/shell/AndroidTest.xml
@@ -14,12 +14,13 @@
limitations under the License.
-->
<configuration description="Config for VTS HAL shell test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-host" />
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="SampleShellTest" />
<option name="test-case-path" value="vts/testcases/host/shell/SampleShellTest" />
</test>
</configuration>
diff --git a/testcases/host/shell/SampleShellTest.py b/testcases/host/shell/SampleShellTest.py
index cc1424c..32bfca2 100644
--- a/testcases/host/shell/SampleShellTest.py
+++ b/testcases/host/shell/SampleShellTest.py
@@ -30,12 +30,12 @@
REPEAT_COUNT = 10
def setUpClass(self):
- self.dut = self.registerController(android_device)[0]
+ self.dut = self.android_devices[0]
def testOneCommand(self):
"""A simple testcase which just emulates a normal usage pattern."""
self.dut.shell.InvokeTerminal("my_shell1")
- results = self.dut.shell.my_shell1.Execute("which ls")
+ results = self.dut.shell.Execute("which ls")
logging.info(str(results[const.STDOUT]))
asserts.assertEqual(len(results[const.STDOUT]), 1)
asserts.assertEqual(results[const.STDOUT][0].strip(), "/system/bin/ls")
diff --git a/testcases/host/shell_binary_crash_test/Android.mk b/testcases/host/shell_binary_crash_test/Android.mk
index c11f739..5dd74ef 100644
--- a/testcases/host/shell_binary_crash_test/Android.mk
+++ b/testcases/host/shell_binary_crash_test/Android.mk
@@ -37,6 +37,25 @@
include $(CLEAR_VARS)
+LOCAL_MODULE := vts_test_binary_seg_fault
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ seg_fault.c \
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libcutils \
+ liblog \
+
+LOCAL_C_INCLUDES += \
+ bionic \
+
+LOCAL_CFLAGS := -Werror -Wall
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
LOCAL_MODULE := ShellBinaryCrashTest
-VTS_CONFIG_SRC_DIR := testcases/host/shell_binary_crash_test
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/host/shell_binary_crash_test/AndroidTest.xml b/testcases/host/shell_binary_crash_test/AndroidTest.xml
index c15c668..d7540e8 100644
--- a/testcases/host/shell_binary_crash_test/AndroidTest.xml
+++ b/testcases/host/shell_binary_crash_test/AndroidTest.xml
@@ -14,16 +14,16 @@
limitations under the License.
-->
<configuration description="Config for VTS HAL shell binary crash test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-host" />
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
<option name="cleanup" value="true" />
- <option name="push" value="DATA/bin/vts_test_binary_crash_app->/data/local/tmp/64/vts_test_binary_crash_app" />
- <option name="push" value="DATA/nativetest64/ltp/testcases/bin/connect01->/data/local/tmp/64/connect01" />
- <option name="push" value="DATA/nativetest/ltp/testcases/bin/connect01->/data/local/tmp/32/connect01" />
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
+ <option name="push" value="DATA/bin/vts_test_binary_crash_app->/data/local/tmp/vts_test_binary_crash_app" />
+ <option name="push" value="DATA/bin/vts_test_binary_seg_fault->/data/local/tmp/vts_test_binary_seg_fault" />
</target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="ShellBinaryCrashTest" />
<option name="test-case-path" value="vts/testcases/host/shell_binary_crash_test/ShellBinaryCrashTest" />
</test>
</configuration>
diff --git a/testcases/host/shell_binary_crash_test/ShellBinaryCrashTest.py b/testcases/host/shell_binary_crash_test/ShellBinaryCrashTest.py
index 2cac12f..8244d71 100644
--- a/testcases/host/shell_binary_crash_test/ShellBinaryCrashTest.py
+++ b/testcases/host/shell_binary_crash_test/ShellBinaryCrashTest.py
@@ -31,12 +31,12 @@
EXIT_CODE_SEGFAULT = 139
def setUpClass(self):
- self.dut = self.registerController(android_device)[0]
+ self.dut = self.android_devices[0]
def testCrashBinary(self):
"""Tests whether the agent survives when a called binary crashes."""
self.dut.shell.InvokeTerminal("my_shell1")
- target = "/data/local/tmp/64/vts_test_binary_crash_app"
+ target = "/data/local/tmp/vts_test_binary_crash_app"
results = self.dut.shell.my_shell1.Execute(
["chmod 755 %s" % target, target])
logging.info(str(results[const.STDOUT]))
@@ -51,7 +51,7 @@
def testSegmentFaultBinary(self):
"""Tests whether the agent survives when a binary leads to segfault."""
self.dut.shell.InvokeTerminal("my_shell1")
- target = "/data/local/tmp/32/connect01"
+ target = "/data/local/tmp/vts_test_binary_seg_fault"
results = self.dut.shell.my_shell1.Execute(
["chmod 755 %s" % target, target])
logging.info(str(results[const.STDOUT]))
diff --git a/testcases/host/shell_binary_crash_test/crash_app.c b/testcases/host/shell_binary_crash_test/crash_app.c
index 2b2a79c..32e827c 100644
--- a/testcases/host/shell_binary_crash_test/crash_app.c
+++ b/testcases/host/shell_binary_crash_test/crash_app.c
@@ -16,7 +16,7 @@
#include <stdio.h>
#define LOG_TAG "VtsTestBinary"
-#include <utils/Log.h>
+#include <log/log.h>
int main() {
char* pt = 0;
diff --git a/testcases/host/shell_binary_crash_test/seg_fault.c b/testcases/host/shell_binary_crash_test/seg_fault.c
new file mode 100644
index 0000000..6f84efb
--- /dev/null
+++ b/testcases/host/shell_binary_crash_test/seg_fault.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 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 <signal.h>
+#include <stdio.h>
+
+#define LOG_TAG "VtsSegFaultTestBinary"
+#include <log/log.h>
+
+int main() {
+ printf("seg_fault_bin: start");
+ ALOGI("seg_fault_bin: start");
+ raise(SIGSEGV); // causes a segmentation fault
+ printf("seg_fault_bin: end");
+ ALOGI("seg_fault_bin: end");
+ return 0;
+}
diff --git a/tools/vts-hc/Android.mk b/testcases/host/verify_boot_header/Android.mk
similarity index 78%
copy from tools/vts-hc/Android.mk
copy to testcases/host/verify_boot_header/Android.mk
index 7733142..4a0b3c0 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/host/verify_boot_header/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsFirmwareBootHeaderVerification
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/host/verify_boot_header/AndroidTest.xml b/testcases/host/verify_boot_header/AndroidTest.xml
new file mode 100644
index 0000000..a29a5fa
--- /dev/null
+++ b/testcases/host/verify_boot_header/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VTS Boot Header Verification Test">
+ <option name="config-descriptor:metadata" key="plan" value="vts-firmware" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ <option name="cleanup" value="true" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsFirmwareBootHeaderVerification"/>
+ <option name="test-case-path" value="vts/testcases/host/verify_boot_header/VtsFirmwareBootHeaderVerification" />
+ <option name="precondition-first-api-level" value="28" />
+ </test>
+</configuration>
diff --git a/testcases/host/verify_boot_header/VtsFirmwareBootHeaderVerification.py b/testcases/host/verify_boot_header/VtsFirmwareBootHeaderVerification.py
new file mode 100644
index 0000000..c7a9c65
--- /dev/null
+++ b/testcases/host/verify_boot_header/VtsFirmwareBootHeaderVerification.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 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.
+#
+"""VTS tests to verify boot/recovery image header versions."""
+
+import logging
+import os
+import shutil
+from struct import unpack
+import tempfile
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test
+from vts.runners.host import test_runner
+from vts.utils.python.android import api
+from vts.utils.python.file import target_file_utils
+
+BLOCK_DEV_PATH = "/dev/block/platform" # path to platform block devices
+PROPERTY_SLOT_SUFFIX = "ro.boot.slot_suffix" # indicates current slot suffix for A/B devices
+BOOT_HEADER_DTBO_SIZE_OFFSET = 1632 # offset of recovery dtbo size in boot header of version 1.
+
+
+class VtsFirmwareBootHeaderVerificationTest(base_test.BaseTestClass):
+ """Verifies boot/recovery image header.
+
+ Attributes:
+ temp_dir: The temporary directory on host.
+ slot_suffix: The current slot suffix for A/B devices.
+ """
+
+ def setUpClass(self):
+ """Initializes the DUT and creates temporary directories."""
+ self.dut = self.android_devices[0]
+ self.shell = self.dut.shell
+ self.adb = self.dut.adb
+ self.temp_dir = tempfile.mkdtemp()
+ logging.info("Create %s", self.temp_dir)
+ self.slot_suffix = self.dut.getProp(PROPERTY_SLOT_SUFFIX)
+ if self.slot_suffix is None:
+ self.slot_suffix = ""
+ logging.info("current slot suffix: %s", self.slot_suffix)
+
+ def setUp(self):
+ """Checks if the the preconditions to run the test are met."""
+ asserts.skipIf("x86" in self.dut.cpu_abi, "Skipping test for x86 ABI")
+
+ def CheckImageHeader(self, boot_image, is_recovery=False):
+ """Verifies the boot image header version, header size and recovery dtbo size.
+
+ Args:
+ boot_image: Path to the boot image.
+ is_recovery: Indicates that the image is recovery if true.
+ """
+ try:
+ with open(boot_image, "rb") as image_file:
+ image_file.read(8) # read boot magic
+ host_image_header_version = unpack("10I",
+ image_file.read(10 * 4))[8]
+ asserts.assertEqual(
+ host_image_header_version, 1,
+ "Device does not have boot image of version 1")
+ image_file.seek(BOOT_HEADER_DTBO_SIZE_OFFSET)
+ recovery_dtbo_size = unpack("I", image_file.read(4))[0]
+ image_file.read(8) # ignore recovery dtbo load address
+ if is_recovery:
+ asserts.assertNotEqual(
+ recovery_dtbo_size, 0,
+ "recovery partition for non-A/B devices must contain the recovery DTBO"
+ )
+ boot_header_size = unpack("I", image_file.read(4))[0]
+ expected_header_size = image_file.tell()
+ asserts.assertEqual(
+ boot_header_size, expected_header_size,
+ "Test failure due to boot header size mismatch. Expected %s Actual %s"
+ % (expected_header_size, boot_header_size))
+ except IOError as e:
+ logging.exception(e)
+ asserts.fail("Unable to open boot image file")
+
+ def testBootImageHeader(self):
+ """Validates boot image header."""
+ current_boot_partition = "boot" + str(self.slot_suffix)
+ boot_path = target_file_utils.FindFiles(
+ self.shell, BLOCK_DEV_PATH, current_boot_partition, "-type l")
+ logging.info("Boot path %s", boot_path)
+ if not boot_path:
+ asserts.fail("Unable to find path to boot image on device.")
+ host_boot_path = os.path.join(self.temp_dir, "boot.img")
+ self.adb.pull("%s %s" % (boot_path[0], host_boot_path))
+ self.CheckImageHeader(host_boot_path)
+
+ def testRecoveryImageHeader(self):
+ """Validates recovery image header."""
+ asserts.skipIf(self.slot_suffix,
+ "A/B devices do not have a separate recovery partition")
+ recovery_path = target_file_utils.FindFiles(self.shell, BLOCK_DEV_PATH,
+ "recovery", "-type l")
+ logging.info("recovery path %s", recovery_path)
+ if not recovery_path:
+ asserts.fail("Unable to find path to recovery image on device.")
+ host_recovery_path = os.path.join(self.temp_dir, "recovery.img")
+ self.adb.pull("%s %s" % (recovery_path[0], host_recovery_path))
+ self.CheckImageHeader(host_recovery_path, True)
+
+ def tearDownClass(self):
+ """Deletes temporary directories."""
+ shutil.rmtree(self.temp_dir)
+
+
+if __name__ == "__main__":
+ test_runner.main()
diff --git a/harnesses/host_controller/__init__.py b/testcases/host/verify_boot_header/__init__.py
similarity index 100%
rename from harnesses/host_controller/__init__.py
rename to testcases/host/verify_boot_header/__init__.py
diff --git a/tools/vts-hc/Android.mk b/testcases/host/verify_dtbo/Android.mk
similarity index 79%
copy from tools/vts-hc/Android.mk
copy to testcases/host/verify_dtbo/Android.mk
index 7733142..1145048 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/host/verify_dtbo/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsFirmwareDtboVerification
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/host/verify_dtbo/AndroidTest.xml b/testcases/host/verify_dtbo/AndroidTest.xml
new file mode 100644
index 0000000..f0ee1cd
--- /dev/null
+++ b/testcases/host/verify_dtbo/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VTS DTBO Verification Test">
+ <option name="config-descriptor:metadata" key="plan" value="vts-firmware" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ <option name="cleanup" value="true" />
+ <option name="push" value="DATA/nativetest64/ufdt_verify_overlay/ufdt_verify_overlay->/data/local/tmp/64/ufdt_verify_overlay" />
+ <option name="push" value="DATA/nativetest/ufdt_verify_overlay/ufdt_verify_overlay->/data/local/tmp/32/ufdt_verify_overlay" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsFirmwareDtboVerification"/>
+ <option name="test-case-path" value="vts/testcases/host/verify_dtbo/VtsFirmwareDtboVerification" />
+ <option name="precondition-first-api-level" value="28" />
+ </test>
+</configuration>
diff --git a/testcases/host/verify_dtbo/VtsFirmwareDtboVerification.py b/testcases/host/verify_dtbo/VtsFirmwareDtboVerification.py
new file mode 100644
index 0000000..47ed998
--- /dev/null
+++ b/testcases/host/verify_dtbo/VtsFirmwareDtboVerification.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 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.
+#
+"""VTS tests to verify DTBO partition/DT overlay application."""
+
+import logging
+import os
+import shutil
+import subprocess
+import tempfile
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test
+from vts.runners.host import const
+from vts.runners.host import test_runner
+from vts.utils.python.android import api
+from vts.utils.python.file import target_file_utils
+from vts.utils.python.os import path_utils
+
+BLOCK_DEV_PATH = "/dev/block/platform" # path to platform block devices
+DEVICE_TEMP_DIR = "/data/local/tmp/" # temporary dir in device.
+FDT_PATH = "/sys/firmware/fdt" # path to device tree.
+PROPERTY_SLOT_SUFFIX = "ro.boot.slot_suffix" # indicates current slot suffix for A/B devices
+
+
+class VtsFirmwareDtboVerification(base_test.BaseTestClass):
+ """Validates DTBO partition and DT overlay application.
+
+ Attributes:
+ temp_dir: The temporary directory on host.
+ device_path: The temporary directory on device.
+ """
+
+ def setUpClass(self):
+ """Initializes the DUT and creates temporary directories."""
+ self.dut = self.android_devices[0]
+ self.shell = self.dut.shell
+ self.adb = self.dut.adb
+ self.temp_dir = tempfile.mkdtemp()
+ logging.info("Create %s", self.temp_dir)
+ self.device_path = str(
+ path_utils.JoinTargetPath(DEVICE_TEMP_DIR, self.abi_bitness))
+ self.shell.Execute("mkdir %s -p" % self.device_path)
+
+ def setUp(self):
+ """Checks if the the preconditions to run the test are met."""
+ asserts.skipIf("x86" in self.dut.cpu_abi, "Skipping test for x86 ABI")
+
+ def testCheckDTBOPartition(self):
+ """Validates DTBO partition using mkdtboimg.py."""
+ try:
+ slot_suffix = str(self.dut.getProp(PROPERTY_SLOT_SUFFIX))
+ except ValueError as e:
+ logging.exception(e)
+ slot_suffix = ""
+ current_dtbo_partition = "dtbo" + slot_suffix
+ dtbo_path = target_file_utils.FindFiles(
+ self.shell, BLOCK_DEV_PATH, current_dtbo_partition, "-type l")
+ logging.info("DTBO path %s", dtbo_path)
+ if not dtbo_path:
+ asserts.fail("Unable to find path to dtbo image on device.")
+ host_dtbo_image = os.path.join(self.temp_dir, "dtbo")
+ self.adb.pull("%s %s" % (dtbo_path[0], host_dtbo_image))
+ mkdtboimg_bin_path = os.path.join("host", "bin", "mkdtboimg.py")
+ unpacked_dtbo_path = os.path.join(self.temp_dir, "dumped_dtbo")
+ dtbo_dump_cmd = [
+ "python", "%s" % mkdtboimg_bin_path, "dump",
+ "%s" % host_dtbo_image, "-b",
+ "%s" % unpacked_dtbo_path
+ ]
+ try:
+ subprocess.check_call(dtbo_dump_cmd)
+ except Exception as e:
+ logging.exception(e)
+ logging.error('dtbo_dump_cmd is: %s', dtbo_dump_cmd)
+ asserts.fail("Invalid DTBO Image")
+
+ def testVerifyOverlay(self):
+ """Verifies application of DT overlays."""
+ overlay_idx_string = self.adb.shell(
+ "cat /proc/cmdline | "
+ "grep -o \"androidboot.dtbo_idx=[^ ]*\" |"
+ "cut -d \"=\" -f 2")
+ asserts.assertNotEqual(
+ len(overlay_idx_string), 0,
+ "Kernel command line missing androidboot.dtbo_idx")
+ overlay_idx_list = overlay_idx_string.split(",")
+ overlay_arg = []
+ for idx in overlay_idx_list:
+ overlay_file = "dumped_dtbo." + idx.rstrip()
+ overlay_path = os.path.join(self.temp_dir, overlay_file)
+ self.adb.push(overlay_path, self.device_path)
+ overlay_arg.append(overlay_file)
+ final_dt_path = path_utils.JoinTargetPath(self.device_path, "final_dt")
+ self.shell.Execute("cp %s %s" % (FDT_PATH, final_dt_path))
+ verification_test_path = path_utils.JoinTargetPath(
+ self.device_path, "ufdt_verify_overlay")
+ chmod_cmd = "chmod 755 %s" % verification_test_path
+ results = self.shell.Execute(chmod_cmd)
+ asserts.assertEqual(results[const.EXIT_CODE][0], 0, "Unable to chmod")
+ cd_cmd = "cd %s" % (self.device_path)
+ verify_cmd = "./ufdt_verify_overlay final_dt %s" % (
+ " ".join(overlay_arg))
+ cmd = str("%s && %s" % (cd_cmd, verify_cmd))
+ logging.info(cmd)
+ results = self.shell.Execute(cmd)
+ asserts.assertEqual(results[const.EXIT_CODE][0], 0,
+ "Incorrect Overlay Application")
+
+ def tearDownClass(self):
+ """Deletes temporary directories."""
+ shutil.rmtree(self.temp_dir)
+ self.shell.Execute("rm -rf %s" % self.device_path)
+
+
+if __name__ == "__main__":
+ test_runner.main()
diff --git a/harnesses/host_controller/__init__.py b/testcases/host/verify_dtbo/__init__.py
similarity index 100%
copy from harnesses/host_controller/__init__.py
copy to testcases/host/verify_dtbo/__init__.py
diff --git a/testcases/library/bionic_unit_tests/Android.mk b/testcases/library/bionic_unit_tests/Android.mk
index dae52b1..6cfa830 100644
--- a/testcases/library/bionic_unit_tests/Android.mk
+++ b/testcases/library/bionic_unit_tests/Android.mk
@@ -18,5 +18,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := BionicUnitTests
-VTS_CONFIG_SRC_DIR := testcases/library/bionic_unit_tests
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/library/bionic_unit_tests/AndroidTest.xml b/testcases/library/bionic_unit_tests/AndroidTest.xml
index 5205da1..35ce12d 100644
--- a/testcases/library/bionic_unit_tests/AndroidTest.xml
+++ b/testcases/library/bionic_unit_tests/AndroidTest.xml
@@ -14,12 +14,12 @@
limitations under the License.
-->
<configuration description="Config for VTS BionicUnitTests test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-library" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
<option name="push" value="DATA/nativetest/bionic-loader-test-libs->/data/nativetest/bionic-loader-test-libs" />
<option name="push" value="DATA/nativetest64/bionic-loader-test-libs->/data/nativetest64/bionic-loader-test-libs" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="BionicUnitTests" />
<option name="binary-test-source" value="_32bit::DATA/nativetest/bionic-unit-tests/bionic-unit-tests->/data/nativetest/bionic-unit-tests/bionic-unit-tests" />
diff --git a/testcases/library/bionic_unit_tests_static/Android.mk b/testcases/library/bionic_unit_tests_static/Android.mk
index 3dade34..5a8af70 100644
--- a/testcases/library/bionic_unit_tests_static/Android.mk
+++ b/testcases/library/bionic_unit_tests_static/Android.mk
@@ -18,5 +18,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := BionicUnitTestsStatic
-VTS_CONFIG_SRC_DIR := testcases/library/bionic_unit_tests_static
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/library/bionic_unit_tests_static/AndroidTest.xml b/testcases/library/bionic_unit_tests_static/AndroidTest.xml
index 07f73b6..df6fbb4 100644
--- a/testcases/library/bionic_unit_tests_static/AndroidTest.xml
+++ b/testcases/library/bionic_unit_tests_static/AndroidTest.xml
@@ -14,12 +14,12 @@
limitations under the License.
-->
<configuration description="Config for VTS BionicUnitTestsStatic test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-library" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
<option name="push" value="DATA/nativetest/bionic-loader-test-libs->/data/nativetest/bionic-loader-test-libs" />
<option name="push" value="DATA/nativetest64/bionic-loader-test-libs->/data/nativetest64/bionic-loader-test-libs" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="BionicUnitTestsStatic" />
<option name="binary-test-source" value="_32bit::DATA/nativetest/bionic-unit-tests-static/bionic-unit-tests-static->/data/nativetest/bionic-unit-tests-static/bionic-unit-tests-static" />
diff --git a/tools/vts-hc/Android.mk b/testcases/system/device_health/Android.mk
similarity index 79%
copy from tools/vts-hc/Android.mk
copy to testcases/system/device_health/Android.mk
index 7733142..f8dbf60 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/system/device_health/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,11 @@
# 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.
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsDeviceHealth
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/system/device_health/AndroidTest.xml b/testcases/system/device_health/AndroidTest.xml
new file mode 100644
index 0000000..e5faa62
--- /dev/null
+++ b/testcases/system/device_health/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VTS VtsDeviceHalth test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-device-health" />
+
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="DeviceHealthTests.apk" />
+ <option name="cleanup-apks" value="true" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.devicehealth.tests" />
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/testcases/system/libc/Android.mk b/testcases/system/libc/Android.mk
index 90529da..e3367e3 100644
--- a/testcases/system/libc/Android.mk
+++ b/testcases/system/libc/Android.mk
@@ -18,5 +18,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := LibcTest
-VTS_CONFIG_SRC_DIR := testcases/system/libc
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/system/libc/AndroidTest.xml b/testcases/system/libc/AndroidTest.xml
index 48425aa..6eb6a78 100644
--- a/testcases/system/libc/AndroidTest.xml
+++ b/testcases/system/libc/AndroidTest.xml
@@ -14,14 +14,14 @@
limitations under the License.
-->
<configuration description="Config for VTS libc basic file and socket IO testing">
+ <option name="config-descriptor:metadata" key="plan" value="vts-library" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
<option name="cleanup" value="true" />
<option name="push" value="spec/test/vts/specification/lib/ndk/bionic/1.0/libcV1.vts->/data/local/tmp/spec/lib/ndk/bionic/1.0/libcV1.vts" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="LibcTest" />
<option name="test-case-path" value="vts/testcases/system/libc/LibcTest" />
</test>
</configuration>
diff --git a/testcases/system/qtaguid/sample/AndroidTest.xml b/testcases/system/qtaguid/sample/AndroidTest.xml
index c97481d..4d4015f 100644
--- a/testcases/system/qtaguid/sample/AndroidTest.xml
+++ b/testcases/system/qtaguid/sample/AndroidTest.xml
@@ -14,12 +14,12 @@
limitations under the License.
-->
<configuration description="Config for VTS system sample qtaguid test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
<option name="push" value="spec/test/vts/specification/lib/ndk/bionic/1.0/libcutilsV1.vts->/data/local/tmp/spec/lib/bionic/ndk/libcutilsV1.vts" />
<option name="cleanup" value="true" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-case-path" value="vts/testcases/system/qtaguid/sample/SampleQtaguidTest" />
</test>
diff --git a/testcases/target/hal_lights/AndroidTest.xml b/testcases/target/hal_lights/AndroidTest.xml
index d429e92..4523f58 100644
--- a/testcases/target/hal_lights/AndroidTest.xml
+++ b/testcases/target/hal_lights/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for VTS HAL Lights test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="cleanup" value="true" />
<option name="push" value="VtsHalLightsTestCases->/data/local/tmp/VtsHalLightsTestCases" />
diff --git a/testcases/target/hal_power/AndroidTest.xml b/testcases/target/hal_power/AndroidTest.xml
index 517b4c3..8b31176 100644
--- a/testcases/target/hal_power/AndroidTest.xml
+++ b/testcases/target/hal_power/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for VTS HAL Power test cases">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="cleanup" value="true" />
<option name="push" value="VtsHalPowerTestCases->/data/local/tmp/VtsHalPowerTestCases" />
diff --git a/testcases/target/hal_power/hal_power_basic_test.cpp b/testcases/target/hal_power/hal_power_basic_test.cpp
index 3103ed7..c6eaeac 100644
--- a/testcases/target/hal_power/hal_power_basic_test.cpp
+++ b/testcases/target/hal_power/hal_power_basic_test.cpp
@@ -20,7 +20,7 @@
#include <hardware/hardware.h>
#include <hardware/power.h>
-#include <utils/Log.h>
+#include <log/log.h>
#include <iostream>
diff --git a/testcases/template/binary_test/binary_test.py b/testcases/template/binary_test/binary_test.py
index ed47053..ba7dd31 100644
--- a/testcases/template/binary_test/binary_test.py
+++ b/testcases/template/binary_test/binary_test.py
@@ -47,14 +47,7 @@
tags: all the tags that appeared in binary list
DEVICE_TMP_DIR: string, temp location for storing binary
TAG_DELIMITER: string, separator used to separate tag and path
- SYSPROP_VTS_NATIVE_SERVER: string, the name of a system property which
- tells whether to stop properly configured
- native servers where properly configured
- means a server's init.rc is configured to
- stop when that property's value is 1.
'''
- SYSPROP_VTS_NATIVE_SERVER = "vts.native_server.on"
-
DEVICE_TMP_DIR = '/data/local/tmp'
TAG_DELIMITER = '::'
PUSH_DELIMITER = '->'
@@ -77,10 +70,9 @@
keys.ConfigKeys.IKEY_BINARY_TEST_ARGS,
keys.ConfigKeys.IKEY_BINARY_TEST_LD_LIBRARY_PATH,
keys.ConfigKeys.IKEY_BINARY_TEST_PROFILING_LIBRARY_PATH,
- keys.ConfigKeys.IKEY_BINARY_TEST_DISABLE_FRAMEWORK,
- keys.ConfigKeys.IKEY_BINARY_TEST_STOP_NATIVE_SERVERS,
keys.ConfigKeys.IKEY_NATIVE_SERVER_PROCESS_NAME,
keys.ConfigKeys.IKEY_PRECONDITION_FILE_PATH_PREFIX,
+ keys.ConfigKeys.IKEY_PRECONDITION_SYSPROP,
]
self.getUserParams(
req_param_names=required_params, opt_param_names=opt_params)
@@ -89,7 +81,7 @@
self.getUserParam(
keys.ConfigKeys.KEY_TESTBED_NAME, error_if_not_found=True)
- logging.info("%s: %s", keys.ConfigKeys.IKEY_DATA_FILE_PATH,
+ logging.debug("%s: %s", keys.ConfigKeys.IKEY_DATA_FILE_PATH,
self.data_file_path)
self.binary_test_source = self.getUserParam(
@@ -204,11 +196,11 @@
self.envp[tag] = coverage_utils.COVERAGE_TEST_ENV
self.testcases = []
-
- ret = precondition_utils.CanRunHidlHalTest(self, self._dut,
- self.shell, self.run_as_compliance_test)
- if not ret:
- self._skip_all_testcases = True
+ if not precondition_utils.CheckSysPropPrecondition(
+ self, self._dut, self.shell):
+ logging.warn('Precondition sysprop not met; '
+ 'all tests skipped.')
+ self.skipAllTests('precondition sysprop not met')
self.tags = set()
self.CreateTestCases()
@@ -220,41 +212,6 @@
logging.error('Failed to set permission to some of the binaries:\n'
'%s\n%s', cmd, cmd_results)
- stop_requested = False
-
- if getattr(self, keys.ConfigKeys.IKEY_BINARY_TEST_DISABLE_FRAMEWORK,
- False):
- # Stop Android runtime to reduce interference.
- logging.debug("Stops the Android framework.")
- self._dut.stop()
- stop_requested = True
-
- if getattr(self, keys.ConfigKeys.IKEY_BINARY_TEST_STOP_NATIVE_SERVERS,
- False):
- logging.debug("Stops all properly configured native servers.")
- results = self._dut.setProp(self.SYSPROP_VTS_NATIVE_SERVER, "1")
- stop_requested = True
-
- if stop_requested:
- native_server_process_names = getattr(
- self, keys.ConfigKeys.IKEY_NATIVE_SERVER_PROCESS_NAME, [])
- if native_server_process_names:
- for native_server_process_name in native_server_process_names:
- while True:
- cmd_result = self.shell.Execute("ps -A")
- if cmd_result[const.EXIT_CODE][0] != 0:
- logging.error("ps command failed (exit code: %s",
- cmd_result[const.EXIT_CODE][0])
- break
- if (native_server_process_name not in cmd_result[
- const.STDOUT][0]):
- logging.info("Process %s not running",
- native_server_process_name)
- break
- logging.info("Checking process %s",
- native_server_process_name)
- time.sleep(1)
-
def CreateTestCases(self):
'''Push files to device and create test case objects.'''
source_list = list(map(self.ParseTestSource, self.binary_test_source))
@@ -282,31 +239,35 @@
if (tag.endswith(const.SUFFIX_32BIT) and self.abi_bitness == '64'
) or (tag.endswith(const.SUFFIX_64BIT) and
self.abi_bitness == '32'):
- logging.info('Bitness of test source, %s, does not match the '
- 'abi_bitness, %s, of test run.', str(source[0]),
+ logging.debug('Bitness of test source, %s, does not match the '
+ 'abi_bitness, %s, of test run. Skipping',
+ str(source[0]),
self.abi_bitness)
return False
return True
source_list = filter(isValidSource, source_list)
- logging.info('Parsed test sources: %s', source_list)
+ logging.debug('Parsed test sources: %s', source_list)
# Push source files first
for src, dst, tag in source_list:
if src:
if os.path.isdir(src):
src = os.path.join(src, '.')
- logging.info('Pushing from %s to %s.', src, dst)
+ logging.debug('Pushing from %s to %s.', src, dst)
self._dut.adb.push('{src} {dst}'.format(src=src, dst=dst))
self.shell.Execute('ls %s' % dst)
+ if not hasattr(self, 'testcases'):
+ self.testcases = []
+
# Then create test cases
for src, dst, tag in source_list:
if tag is not None:
# tag not being None means to create a test case
self.tags.add(tag)
- logging.info('Creating test case from %s with tag %s', dst,
+ logging.debug('Creating test case from %s with tag %s', dst,
tag)
testcase = self.CreateTestCase(dst, tag)
if not testcase:
@@ -317,8 +278,8 @@
else:
self.testcases.append(testcase)
- if type(self.testcases) is not list or len(self.testcases) == 0:
- asserts.fail("No test case is found or generated.")
+ if not self.testcases:
+ logging.warn("No test case is found or generated.")
def PutTag(self, name, tag):
'''Put tag on name and return the resulting string.
@@ -359,24 +320,13 @@
def tearDownClass(self):
'''Perform clean-up tasks'''
- if getattr(self, keys.ConfigKeys.IKEY_BINARY_TEST_STOP_NATIVE_SERVERS,
- False):
- logging.debug("Restarts all properly configured native servers.")
- results = self._dut.setProp(self.SYSPROP_VTS_NATIVE_SERVER, "0")
-
- # Restart Android runtime.
- if getattr(self, keys.ConfigKeys.IKEY_BINARY_TEST_DISABLE_FRAMEWORK,
- False):
- logging.debug("Starts the Android framework.")
- self._dut.start()
-
# Retrieve coverage if applicable
if self.coverage.enabled and self.coverage.global_coverage:
- if not self._skip_all_testcases:
+ if not self.isSkipAllTests():
self.coverage.SetCoverageData(dut=self._dut, isGlobal=True)
# Clean up the pushed binaries
- logging.info('Start class cleaning up jobs.')
+ logging.debug('Start class cleaning up jobs.')
# Delete pushed files
sources = [
@@ -399,10 +349,10 @@
if not cmd_results or any(cmd_results[const.EXIT_CODE]):
logging.warning('Failed to remove: %s', cmd_results)
- if not self._skip_all_testcases and self.profiling.enabled:
+ if not self.isSkipAllTests() and self.profiling.enabled:
self.profiling.ProcessAndUploadTraceData()
- logging.info('Finished class cleaning up jobs.')
+ logging.debug('Finished class cleaning up jobs.')
def ParseTestSource(self, source):
'''Convert host side binary path to device side path.
@@ -529,7 +479,7 @@
test_case.profiling_library_path)
cmd = test_case.GetRunCommand()
- logging.info("Executing binary test command: %s", cmd)
+ logging.debug("Executing binary test command: %s", cmd)
command_results = self.shell.Execute(cmd)
self.VerifyTestResult(test_case, command_results)
diff --git a/testcases/template/binary_test/binary_test_case.py b/testcases/template/binary_test/binary_test_case.py
index c69882f..335658f 100644
--- a/testcases/template/binary_test/binary_test_case.py
+++ b/testcases/template/binary_test/binary_test_case.py
@@ -49,6 +49,9 @@
envp: string, environment veriable. shoud be in format 'name1=value1 name2=value2...'
Will be called using 'env <envp> <cmd> <args>'
args: string, arguments following cmd.
+ name_appendix: string, appendix attached to the test name in display,
+ typically contains info of parameters used in the test,
+ e.e. service name used for hal hidl test.
'''
def __init__(self,
@@ -62,7 +65,8 @@
profiling_library_path=None,
cmd='',
envp='',
- args=''):
+ args='',
+ name_appendix=''):
self.test_suite = test_suite
self.test_name = test_name
self.path = path
@@ -74,9 +78,27 @@
self.cmd = cmd
self.envp = envp
self.args = args
+ self.name_appendix = name_appendix
def __str__(self):
- return self.put_tag_func(self.full_name, self.tag)
+ return self._GenerateDisplayName()
+
+ def _GenerateDisplayName(self):
+ '''Get a string of test name for display.
+
+ The display name contains three parts: the original full test name, the
+ name appendix which includes more info about the test run, and the
+ tag(s) used by the test.
+ '''
+ return self.put_tag_func(self.full_name + self.name_appendix, self.tag)
+
+ @property
+ def name_appendix(self):
+ return self._name_appendix
+
+ @name_appendix.setter
+ def name_appendix(self, name_appendix):
+ self._name_appendix = name_appendix
@property
def full_name(self):
diff --git a/testcases/template/cts_test/cts_test.py b/testcases/template/cts_test/cts_test.py
index 18a7dbf..2821c5e 100644
--- a/testcases/template/cts_test/cts_test.py
+++ b/testcases/template/cts_test/cts_test.py
@@ -39,9 +39,8 @@
]
def setUpClass(self):
- self.dut = self.registerController(android_device)[0]
- self.dut.shell.InvokeTerminal("one")
- self.dut.shell.one.Execute("setenforce 0") # SELinux permissive mode
+ self.dut = self.android_devices[0]
+ self.dut.shell.Execute("setenforce 0") # SELinux permissive mode
self.testcases = []
self.CreateTestCases()
@@ -55,7 +54,7 @@
def CreateTestCases(self):
'''Create test configs.'''
for testcase in self.CTS_TESTS:
- logging.info('Creating test case %s.', testcase["name"])
+ logging.debug('Creating test case %s.', testcase["name"])
self.testcases.append(testcase)
def RunTestCase(self, test_case):
diff --git a/testcases/template/gtest_binary_test/gtest_binary_test.py b/testcases/template/gtest_binary_test/gtest_binary_test.py
index e5ccab7..7856c9c 100644
--- a/testcases/template/gtest_binary_test/gtest_binary_test.py
+++ b/testcases/template/gtest_binary_test/gtest_binary_test.py
@@ -45,10 +45,18 @@
# @Override
def setUpClass(self):
'''Prepare class, push binaries, set permission, create test cases.'''
+ self.collect_tests_only = self.getUserParam(
+ keys.ConfigKeys.IKEY_COLLECT_TESTS_ONLY, default_value=False)
self.batch_mode = self.getUserParam(
keys.ConfigKeys.IKEY_GTEST_BATCH_MODE, default_value=False)
+
if self.batch_mode:
- self._gtest_results = []
+ if self.collect_tests_only:
+ self.batch_mode = False
+ logging.debug("Disable batch mode when collecting tests.")
+ else:
+ self._gtest_results = []
+
super(GtestBinaryTest, self).setUpClass()
# @Override
@@ -113,7 +121,7 @@
test_suite, test_name, path, tag, self.PutTag,
working_directory, ld_library_path, profiling_library_path,
envp=envp, args=args)
- logging.info('Gtest test case: %s' % test_case)
+ logging.debug('Gtest test case: %s' % test_case)
test_cases.append(test_case)
else: # Test suite name
test_suite = line.strip()
@@ -174,20 +182,28 @@
self._ParseBatchResults(test_case, xml_str)
return
- for stdout in command_results[const.STDOUT]:
- if stdout and stdout.strip():
- for line in stdout.split('\n'):
- logging.info(line)
-
asserts.assertFalse(
command_results[const.EXIT_CODE][1],
'Failed to show Gtest XML output: %s' % command_results)
root = xml.etree.ElementTree.fromstring(xml_str)
asserts.assertEqual(root.get('tests'), '1', 'No tests available')
+ success = True
if root.get('errors') != '0' or root.get('failures') != '0':
messages = [x.get('message') for x in root.findall('.//failure')]
+ success = False
+
+ for stdout in command_results[const.STDOUT]:
+ if stdout and stdout.strip():
+ for line in stdout.split('\n'):
+ if success:
+ logging.debug(line)
+ else:
+ logging.error(line)
+
+ if not success:
asserts.fail('\n'.join([x for x in messages if x]))
+
asserts.skipIf(root.get('disabled') == '1', 'Gtest test case disabled')
def _ParseBatchResults(self, test_case_original, xml_str):
@@ -200,12 +216,14 @@
root = xml.etree.ElementTree.fromstring(xml_str)
for test_suite in root:
- print test_suite.tag, test_suite.attrib
+ logging.debug('Test tag: %s, attribute: %s',
+ test_suite.tag,
+ test_suite.attrib)
for test_case in test_suite:
result = gtest_test_case.GtestTestCase(
test_suite.get('name'),
test_case.get('name'), '', test_case_original.tag,
- self.PutTag)
+ self.PutTag, name_appendix=test_case_original.name_appendix)
failure_message = None
for sub in test_case:
diff --git a/testcases/template/gtest_binary_test/gtest_test_case.py b/testcases/template/gtest_binary_test/gtest_test_case.py
index 1f4a5c4..88a7ece 100644
--- a/testcases/template/gtest_binary_test/gtest_test_case.py
+++ b/testcases/template/gtest_binary_test/gtest_test_case.py
@@ -88,12 +88,12 @@
output_base_name = '{}.xml'.format(uuid.uuid4())
output_file_path = path_utils.JoinTargetPath(
output_dir_name, output_base_name)
- logging.info('Output file path is set as "%s".', output_file_path)
+ logging.debug('Output file path is set as "%s".', output_file_path)
if len(output_file_path) > utils.MAX_PATH_LEN:
logging.warn('File path of output file "{}" is longer than {}.'.
format(output_file_path, utils.MAX_PATH_LEN))
output_file_path = output_base_name
- logging.info('Output file path is set as "%s".', output_file_path)
+ logging.debug('Output file path is set as "%s".', output_file_path)
self._output_file_path = output_file_path
diff --git a/testcases/template/hal_hidl_gtest/hal_hidl_gtest.py b/testcases/template/hal_hidl_gtest/hal_hidl_gtest.py
index 038c19b..5d0d5a5 100644
--- a/testcases/template/hal_hidl_gtest/hal_hidl_gtest.py
+++ b/testcases/template/hal_hidl_gtest/hal_hidl_gtest.py
@@ -24,10 +24,14 @@
from vts.testcases.template.gtest_binary_test import gtest_test_case
from vts.utils.python.cpu import cpu_frequency_scaling
from vts.utils.python.hal import hal_service_name_utils
+from vts.utils.python.precondition import precondition_utils
+# The pattern indicating a full hal test name including the service name info.
+# e.g. TM.TC(default)_32bit
+_HAL_TEST_NAME_PATTERN = ".*\(.*\).*"
class HidlHalGTest(gtest_binary_test.GtestBinaryTest):
- '''Base class to run a VTS target-side HIDL HAL test.
+ """Base class to run a VTS target-side HIDL HAL test.
Attributes:
DEVICE_TEST_DIR: string, temp location for storing binary
@@ -36,44 +40,48 @@
testcases: list of GtestTestCase objects, list of test cases to run
_cpu_freq: CpuFrequencyScalingController instance of a target device.
_dut: AndroidDevice, the device under test as config
- _hal_precondition: String, the name of the HAL preconditioned
- '''
+ _target_hals: List of String, the targeting hal service of the test.
+ e.g (["android.hardware.foo@1.0::IFoo"])
+ """
def setUpClass(self):
"""Checks precondition."""
super(HidlHalGTest, self).setUpClass()
+ if not hasattr(self, "_target_hals"):
+ self._target_hals = []
- opt_params = [keys.ConfigKeys.IKEY_SKIP_IF_THERMAL_THROTTLING]
+ opt_params = [keys.ConfigKeys.IKEY_SKIP_IF_THERMAL_THROTTLING,
+ keys.ConfigKeys.IKEY_DISABLE_CPU_FREQUENCY_SCALING]
self.getUserParams(opt_param_names=opt_params)
self._skip_if_thermal_throttling = self.getUserParam(
keys.ConfigKeys.IKEY_SKIP_IF_THERMAL_THROTTLING,
default_value=False)
+ self._disable_cpu_frequency_scaling = self.getUserParam(
+ keys.ConfigKeys.IKEY_DISABLE_CPU_FREQUENCY_SCALING,
+ default_value=True)
- if not self._skip_all_testcases:
- logging.info("Disable CPU frequency scaling")
+ if not self.isSkipAllTests():
self._cpu_freq = cpu_frequency_scaling.CpuFrequencyScalingController(
self._dut)
- self._cpu_freq.DisableCpuScaling()
+ if self._disable_cpu_frequency_scaling:
+ logging.debug("Disabling CPU frequency scaling")
+ self._cpu_freq.DisableCpuScaling()
else:
self._cpu_freq = None
- self._hal_precondition = None
- if hasattr(self, keys.ConfigKeys.IKEY_PRECONDITION_LSHAL):
- self._hal_precondition = getattr(
- self, keys.ConfigKeys.IKEY_PRECONDITION_LSHAL)
- elif hasattr(self, keys.ConfigKeys.IKEY_PRECONDITION_VINTF):
- self._hal_precondition = getattr(
- self, keys.ConfigKeys.IKEY_PRECONDITION_VINTF)
- elif hasattr(self, keys.ConfigKeys.IKEY_PRECONDITION_HWBINDER_SERVICE):
- self._hal_precondition = getattr(
- self, keys.ConfigKeys.IKEY_PRECONDITION_HWBINDER_SERVICE)
+ if not self.isSkipAllTests():
+ ret = precondition_utils.CanRunHidlHalTest(
+ self, self._dut, self.shell, self.run_as_compliance_test)
+ if not ret:
+ self.skipAllTests("HIDL HAL precondition check failed.")
- if self.sancov.enabled and self._hal_precondition is not None:
+ if self.sancov.enabled and self._target_hals:
self.sancov.InitializeDeviceCoverage(self._dut,
- self._hal_precondition)
- if self.coverage.enabled and self._hal_precondition is not None:
- self.coverage.SetHalNames([self._hal_precondition])
+ self._target_hals)
+ if self.coverage.enabled and self._target_hals:
+ self.coverage.SetHalNames(self._target_hals)
+ self.coverage.SetCoverageReportFilePrefix(self.test_module_name + self.abi_bitness)
def CreateTestCases(self):
"""Create testcases and conditionally enable passthrough mode.
@@ -93,7 +101,7 @@
# @Override
def CreateTestCase(self, path, tag=''):
- '''Create a list of GtestTestCase objects from a binary path.
+ """Create a list of GtestTestCase objects from a binary path.
Support testing against different service names by first executing a
dummpy test case which lists all the registered hal services. Then
@@ -107,7 +115,7 @@
Returns:
A list of GtestTestCase objects.
- '''
+ """
initial_test_cases = super(HidlHalGTest, self).CreateTestCase(path,
tag)
if not initial_test_cases:
@@ -117,51 +125,71 @@
list_service_test_case.args += " --list_registered_services"
results = self.shell.Execute(list_service_test_case.GetRunCommand())
if (results[const.EXIT_CODE][0]):
- logging.error('Failed to list test cases from binary %s',
+ logging.error("Failed to list test cases from binary %s",
list_service_test_case.path)
# parse the results to get the registered service list.
registered_services = []
- for line in results[const.STDOUT][0].split('\n'):
+ comb_mode = hal_service_name_utils.CombMode.FULL_PERMUTATION
+ # TODO: consider to use a standard data format (e.g. json) instead of
+ # parsing the print output.
+ for line in results[const.STDOUT][0].split("\n"):
line = str(line)
- if line.startswith('hal_service: '):
- service = line[len('hal_service: '):]
+ if line.startswith("hal_service: "):
+ service = line[len("hal_service: "):]
registered_services.append(service)
+ if line.startswith("service_comb_mode: "):
+ comb_mode = int(line[len("service_comb_mode: "):])
# If no service registered, return the initial test cases directly.
if not registered_services:
+ logging.error("No hal service registered.")
return initial_test_cases
+ self._target_hals = copy.copy(registered_services)
+
# find the correponding service name(s) for each registered service and
# store the mapping in dict service_instances.
service_instances = {}
for service in registered_services:
- _, service_names = hal_service_name_utils.GetHalServiceName(
+ testable, service_names = hal_service_name_utils.GetHalServiceName(
self.shell, service, self.abi_bitness,
self.run_as_compliance_test)
+ if not testable:
+ self.skipAllTests("Hal: %s is not testable, "
+ "skip all tests." % service)
+ return initial_test_cases
if not service_names:
- logging.error("No service name found for: %s, skip all tests.",
- service)
- self._skip_all_testcases = True
+ self.skipAllTests("No service name found for: %s, skip all tests." % service)
# If any of the test services are not available, return the
# initial test cases directly.
return initial_test_cases
else:
service_instances[service] = service_names
- logging.info("registered service instances: %s", service_instances)
+ logging.debug("registered service instances: %s", service_instances)
+ logging.debug("service comb mode: %d", comb_mode)
+
+ # If request NO_COMBINATION mode, return the initial test cases directly.
+ if comb_mode == hal_service_name_utils.CombMode.NO_COMBINATION:
+ return initial_test_cases
# get all the combination of service instances.
service_instance_combinations = hal_service_name_utils.GetServiceInstancesCombinations(
- registered_services, service_instances)
+ registered_services, service_instances, comb_mode);
new_test_cases = []
- for test_case in initial_test_cases:
- for instance_combination in service_instance_combinations:
+ appendix_list = []
+ for instance_combination in service_instance_combinations:
+ for test_case in initial_test_cases:
new_test_case = copy.copy(test_case)
+ service_name_list = []
for instance in instance_combination:
new_test_case.args += " --hal_service_instance=" + instance
- new_test_case.tag = instance[instance.find(
- '/'):] + new_test_case.tag
+ service_name_list.append(instance[instance.find('/')+1:])
+ name_appendix = "({0})".format(",".join(service_name_list))
+ new_test_case.name_appendix = name_appendix
new_test_cases.append(new_test_case)
+ appendix_list.append(name_appendix)
+ self.test_filter.ExpandAppendix(appendix_list, _HAL_TEST_NAME_PATTERN)
return new_test_cases
def _EnablePassthroughMode(self):
@@ -199,14 +227,15 @@
def tearDownClass(self):
"""Turns off CPU frequency scaling."""
- if (not self._skip_all_testcases and getattr(self, "_cpu_freq", None)):
- logging.info("Enable CPU frequency scaling")
+ if (not self.isSkipAllTests() and getattr(self, "_cpu_freq", None)
+ and self._disable_cpu_frequency_scaling):
+ logging.debug("Enabling CPU frequency scaling")
self._cpu_freq.EnableCpuScaling()
- if self.sancov.enabled and self._hal_precondition is not None:
- self.sancov.FlushDeviceCoverage(self._dut, self._hal_precondition)
+ if self.sancov.enabled and self._target_hals:
+ self.sancov.FlushDeviceCoverage(self._dut, self._target_hals)
self.sancov.ProcessDeviceCoverage(self._dut,
- self._hal_precondition)
+ self._target_hals)
self.sancov.Upload()
super(HidlHalGTest, self).tearDownClass()
diff --git a/testcases/template/hal_hidl_host_test/hal_hidl_host_test.py b/testcases/template/hal_hidl_host_test/hal_hidl_host_test.py
index 476d21c..ff91d2b 100644
--- a/testcases/template/hal_hidl_host_test/hal_hidl_host_test.py
+++ b/testcases/template/hal_hidl_host_test/hal_hidl_host_test.py
@@ -13,16 +13,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
+import copy
import logging
from vts.runners.host import base_test
-from vts.runners.host import test_runner
+from vts.testcases.template.param_test import param_test
from vts.utils.python.controllers import android_device
+from vts.utils.python.hal import hal_service_name_utils
from vts.utils.python.precondition import precondition_utils
-class HalHidlHostTest(base_test.BaseTestClass):
+class HalHidlHostTest(param_test.ParamTestClass):
"""Base class to run a host-driver hidl hal test.
Attributes:
@@ -32,21 +33,25 @@
"""
TEST_HAL_SERVICES = set()
+ # @Override
+ def initParams(self):
+ """Get the service combination according to the registered test HAL."""
+ self.dut = self.android_devices[0]
+ self.shell = self.dut.shell
+ service_instance_combinations = self._GetServiceInstanceCombinations()
+ self.params = service_instance_combinations
+
+ # @Override
def setUpClass(self):
"""Basic setup process for host-side hidl hal tests.
- Register default device and shell mirror, set permission, check whether
- the test satisfy the precondition requirement, prepare for test
- profiling and coverage measurement if enabled.
+ Test precondition check, prepare for profiling and coverage measurement
+ if enabled.
"""
- self.dut = self.registerController(android_device)[0]
- self.shell = self.dut.shell
- self.shell.Execute("setenforce 0") # SELinux permissive mode
-
# Testability check.
if not precondition_utils.CanRunHidlHalTest(
self, self.dut, self.shell, self.run_as_compliance_test):
- self._skip_all_testcases = True
+ self.skipAllTests("precondition check for hidl hal tests didn't pass")
return
# Initialization for coverage measurement.
@@ -54,11 +59,13 @@
self.coverage.InitializeDeviceCoverage(self.dut)
if self.TEST_HAL_SERVICES:
self.coverage.SetHalNames(self.TEST_HAL_SERVICES)
+ self.coverage.SetCoverageReportFilePrefix(self.test_module_name + self.abi_bitness)
# Enable profiling.
if self.profiling.enabled:
self.profiling.EnableVTSProfiling(self.shell)
+ # @Override
def tearDownClass(self):
"""Basic cleanup process for host-side hidl hal tests.
@@ -67,7 +74,7 @@
If coverage is enabled for the test, collect the coverage data and
upload it to dashboard.
"""
- if self._skip_all_testcases:
+ if self.isSkipAllTests():
return
if self.coverage.enabled and self.coverage.global_coverage:
@@ -76,14 +83,80 @@
if self.profiling.enabled:
self.profiling.ProcessAndUploadTraceData()
+ # @Override
def setUp(self):
"""Setup process for each test case."""
if self.profiling.enabled:
self.profiling.EnableVTSProfiling(self.shell)
+ # @Override
def tearDown(self):
"""Cleanup process for each test case."""
if self.profiling.enabled:
self.profiling.ProcessTraceDataForTestCase(self.dut)
self.profiling.DisableVTSProfiling(self.shell)
+ # @Override
+ def getParamTag(self, param):
+ """Concatenate names for all services passed as the param test tag.
+
+ Args:
+ param: a list of service instances. e.g [s1/n1, s2/n2]
+
+ Returns:
+ a string of concatenated service names. e.g. n1/n2
+ """
+ names = map(lambda instance: instance.split("/")[1], param)
+ return "({})".format(",".join(names))
+
+ def getHalServiceName(self, hal_service):
+ """Get corresponding name for hal_service from the current parameter.
+
+ The current parameter should be a list of service instances with the
+ format [hal_service/name], e.g [s1/n1, s2/n2]
+
+ Args:
+ hal_service: string, hal@version e.g. foo@1.0
+
+ Returns:
+ Name for hal_service, "default" if could not find the hal_service in
+ the list of service instances.
+ """
+ for instance in self.cur_param:
+ service, name = instance.split("/")
+ if service == hal_service:
+ return str(name)
+ # In case could not find the name for given hal_service, fall back to
+ # use the "default" name.
+ logging.warning(
+ "Could not find the service name for %s, using default name instead",
+ hal_service)
+ return "default"
+
+ def _GetServiceInstanceCombinations(self):
+ """Create combinations of instances for registered HAL services.
+
+ Returns:
+ A list of instance combination for registered HAL.
+ """
+ registered_services = copy.copy(self.TEST_HAL_SERVICES)
+ service_instances = {}
+
+ for service in registered_services:
+ testable, service_names = hal_service_name_utils.GetHalServiceName(
+ self.shell, service, self.abi_bitness,
+ self.run_as_compliance_test)
+ if not testable:
+ self.skipAllTests("Hal: %s is not testable, "
+ "skip all tests." % service)
+ return []
+ if service_names:
+ service_instances[service] = service_names
+ else:
+ self.skipAllTests("No service name found for: %s, "
+ "skip all tests." % service)
+ return []
+ logging.info("registered service instances: %s", service_instances)
+
+ return hal_service_name_utils.GetServiceInstancesCombinations(
+ registered_services, service_instances)
diff --git a/testcases/template/hal_hidl_replay_test/hal_hidl_replay_test.py b/testcases/template/hal_hidl_replay_test/hal_hidl_replay_test.py
index f4ecf43..ecb263d 100644
--- a/testcases/template/hal_hidl_replay_test/hal_hidl_replay_test.py
+++ b/testcases/template/hal_hidl_replay_test/hal_hidl_replay_test.py
@@ -45,7 +45,7 @@
self._test_hal_services = set()
super(HalHidlReplayTest, self).setUpClass()
- if self._skip_all_testcases:
+ if self.isSkipAllTests():
return
if self.coverage.enabled and self._test_hal_services is not None:
@@ -64,7 +64,7 @@
self.abi_bitness = str(self.abi_bitness)
self.trace_paths = map(str, self.hal_hidl_replay_test_trace_paths)
- self.driver_binary_path = path_utils.JoinTargetPath(
+ self.replayer_binary_path = path_utils.JoinTargetPath(
self.DEVICE_TMP_DIR, self.abi_bitness,
"vts_hal_replayer%s" % self.abi_bitness)
self.custom_ld_library_path = path_utils.JoinTargetPath(
@@ -78,30 +78,49 @@
path_utils.JoinTargetPath(self.data_file_path,
"hal-hidl-trace", trace_path),
target_trace_path)
-
service_instance_combinations = self._GetServiceInstanceCombinations(
target_trace_path)
- for instance_combination in service_instance_combinations:
- test_case = super(HalHidlReplayTest, self).CreateTestCase(
- self.driver_binary_path, '')
- test_case.envp += "LD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH" % self.custom_ld_library_path
- test_case.args += " --spec_dir_path=" + self.DEVICE_VTS_SPEC_FILE_PATH
- test_case.test_name = "replay_test_" + trace_file_name
- for instance in instance_combination:
- test_case.args += " --hal_service_instance=" + instance
- test_case.args += " " + target_trace_path
- test_case.tag += instance[instance.find('/'):]
+ if service_instance_combinations:
+ for instance_combination in service_instance_combinations:
+ test_case = self.CreateReplayTestCase(
+ trace_file_name, target_trace_path)
+ service_name_list = []
+ for instance in instance_combination:
+ test_case.args += " --hal_service_instance=" + instance
+ service_name_list.append(
+ instance[instance.find('/') + 1:])
+ name_appendix = "({0})".format(",".join(service_name_list))
+ test_case.name_appendix = name_appendix
+ self.testcases.append(test_case)
+ else:
+ test_case = self.CreateReplayTestCase(trace_file_name,
+ target_trace_path)
self.testcases.append(test_case)
- def VerifyTestResult(self, test_case, command_results):
- '''Parse Gtest xml result output.
+ def CreateReplayTestCase(self, trace_file_name, target_trace_path):
+ """Create a replay test case object.
Args:
- test_case: GtestTestCase object, the test being run. This param
+ trace_file_name: string, name of the trace file used in the test.
+ target_trace_path: string, full path of the trace file or the target device.
+ """
+ test_case = super(HalHidlReplayTest, self).CreateTestCase(
+ self.replayer_binary_path, '')
+ test_case.envp += "LD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH" % self.custom_ld_library_path
+ test_case.args += " --spec_dir_path=" + self.DEVICE_VTS_SPEC_FILE_PATH
+ test_case.args += " " + target_trace_path
+ test_case.test_name = "replay_test_" + trace_file_name
+ return test_case
+
+ def VerifyTestResult(self, test_case, command_results):
+ """Parse Gtest xml result output.
+
+ Args:
+ test_case: BinaryTestCase object, the test being run. This param
is not currently used in this method.
command_results: dict of lists, shell command result
- '''
+ """
asserts.assertTrue(command_results, 'Empty command response.')
asserts.assertEqual(
len(command_results), 3, 'Abnormal command response.')
@@ -109,7 +128,7 @@
for stdout in command_results[const.STDOUT]:
if stdout and stdout.strip():
for line in stdout.split('\n'):
- logging.info(line)
+ logging.debug(line)
if any(command_results[const.EXIT_CODE]):
# print stderr only when test fails.
@@ -117,19 +136,20 @@
if stderr and stderr.strip():
for line in stderr.split('\n'):
logging.error(line)
- asserts.fail('Test {} failed with the following results: {}'.format(
+ asserts.fail(
+ 'Test {} failed with the following results: {}'.format(
test_case, command_results))
def tearDownClass(self):
"""Performs clean-up tasks."""
# Delete the pushed file.
- if not self._skip_all_testcases:
+ if not self.isSkipAllTests():
for trace_path in self.trace_paths:
trace_file_name = str(os.path.basename(trace_path))
target_trace_path = path_utils.JoinTargetPath(
self.DEVICE_TMP_DIR, "vts_replay_trace", trace_file_name)
- cmd_results = self.shell.Execute("rm -f %s" %
- target_trace_path)
+ cmd_results = self.shell.Execute(
+ "rm -f %s" % target_trace_path)
if not cmd_results or any(cmd_results[const.EXIT_CODE]):
logging.warning("Failed to remove: %s", cmd_results)
@@ -161,13 +181,17 @@
"""
registered_services = []
service_instances = {}
+ self.shell.Execute("chmod 755 %s" % self.replayer_binary_path)
results = self.shell.Execute(
"LD_LIBRARY_PATH=%s:$LD_LIBRARY_PATH %s --list_service %s" %
- (self.custom_ld_library_path, self.driver_binary_path, trace_path))
+ (self.custom_ld_library_path, self.replayer_binary_path,
+ trace_path))
- if (results[const.EXIT_CODE][0]):
- logging.error('Failed to list test cases.')
- return None
+ asserts.assertFalse(
+ results[const.EXIT_CODE][0],
+ 'Failed to list test cases. EXIT_CODE: %s\n STDOUT: %s\n STDERR: %s\n'
+ % (results[const.EXIT_CODE][0], results[const.STDOUT][0],
+ results[const.STDERR][0]))
# parse the results to get the registered service list.
for line in results[const.STDOUT][0].split('\n'):
@@ -177,12 +201,20 @@
registered_services.append(service)
for service in registered_services:
- _, service_names = hal_service_name_utils.GetHalServiceName(
+ testable, service_names = hal_service_name_utils.GetHalServiceName(
self.shell, service, self.abi_bitness,
self.run_as_compliance_test)
+ if not testable:
+ self.skipAllTests("Hal: %s is not testable, "
+ "skip all tests." % service)
+ return []
if service_names:
service_instances[service] = service_names
self._test_hal_services.add(service)
+ else:
+ self.skipAllTests("No service name found for: %s, "
+ "skip all tests." % service)
+ return []
logging.info("registered service instances: %s", service_instances)
service_instance_combinations = \
diff --git a/testcases/template/host_binary_test/host_binary_test.py b/testcases/template/host_binary_test/host_binary_test.py
index 9dcec41..4a63bdf 100644
--- a/testcases/template/host_binary_test/host_binary_test.py
+++ b/testcases/template/host_binary_test/host_binary_test.py
@@ -52,9 +52,9 @@
cmd_result = cmd_utils.ExecuteShellCommand(binary_path)
asserts.assertFalse(
- any(results[cmd_utils.EXIT_CODE]),
+ any(cmd_result[cmd_utils.EXIT_CODE]),
"Test failed with the following results:\n "
- "command result: %s" % results)
+ "command result: %s" % cmd_result)
if __name__ == "__main__":
diff --git a/testcases/template/llvmfuzzer_test/llvmfuzzer_test.py b/testcases/template/llvmfuzzer_test/llvmfuzzer_test.py
index 2440a4c..6216e75 100644
--- a/testcases/template/llvmfuzzer_test/llvmfuzzer_test.py
+++ b/testcases/template/llvmfuzzer_test/llvmfuzzer_test.py
@@ -36,7 +36,10 @@
Attributes:
_dut: AndroidDevice, the device under test as config
_testcases: string list, list of testcases to run
+ start_vts_agents: whether to start vts agents when registering new
+ android devices.
"""
+ start_vts_agents = False
def setUpClass(self):
"""Creates a remote shell instance, and copies data files."""
@@ -48,13 +51,13 @@
self._testcases = map(lambda x: str(x), self.fuzzer_configs.keys())
- logging.info("Testcases: %s", self._testcases)
- logging.info("%s: %s", keys.ConfigKeys.IKEY_DATA_FILE_PATH,
+ logging.debug("Testcases: %s", self._testcases)
+ logging.debug("%s: %s", keys.ConfigKeys.IKEY_DATA_FILE_PATH,
self.data_file_path)
- logging.info("%s: %s", config.ConfigKeys.FUZZER_CONFIGS,
+ logging.debug("%s: %s", config.ConfigKeys.FUZZER_CONFIGS,
self.fuzzer_configs)
- self._dut = self.registerController(android_device, False)[0]
+ self._dut = self.android_devices[0]
self._dut.adb.shell("mkdir %s -p" % config.FUZZER_TEST_DIR)
def tearDownClass(self):
@@ -70,7 +73,7 @@
push_src = os.path.join(self.data_file_path, config.FUZZER_SRC_DIR,
testcase)
self._dut.adb.push("%s %s" % (push_src, config.FUZZER_TEST_DIR))
- logging.info("Adb pushed: %s", testcase)
+ logging.debug("Adb pushed: %s", testcase)
def CreateFuzzerFlags(self, fuzzer_config):
"""Creates flags for the fuzzer executable.
@@ -177,7 +180,7 @@
fuzz_cmd = "%s && %s %s %s %s > /dev/null" % (cd_cmd, ld_path,
test_cmd, corpus_dir,
test_flags)
- logging.info("Executing: %s", fuzz_cmd)
+ logging.debug("Executing: %s", fuzz_cmd)
# TODO(trong): vts shell doesn't handle timeouts properly, change this after it does.
try:
stdout = self._dut.adb.shell("'%s'" % fuzz_cmd)
@@ -217,7 +220,7 @@
for offset in xrange(0, len(output), 2):
crash_report += "\\x%s" % output[offset:offset + 2]
- logging.info('FUZZER_TEST_CRASH_REPORT for %s: "%s"', fuzzer,
+ logging.debug('FUZZER_TEST_CRASH_REPORT for %s: "%s"', fuzzer,
crash_report)
# TODO(trong): differentiate between crashes and sanitizer rule violations.
@@ -232,7 +235,7 @@
fuzzer: string, name of fuzzer executable.
result: dict(str, str, int), command results from shell.
"""
- logging.info("Test result: %s" % result)
+ logging.debug("Test result: %s" % result)
if not self._dut.hasBooted():
self._dut.waitForBootCompletion()
asserts.fail("%s left the device in unresponsive state." % fuzzer)
diff --git a/utils/python/retry/__init__.py b/testcases/template/mobly/__init__.py
similarity index 100%
copy from utils/python/retry/__init__.py
copy to testcases/template/mobly/__init__.py
diff --git a/testcases/template/mobly/mobly_test.py b/testcases/template/mobly/mobly_test.py
new file mode 100644
index 0000000..aabcbab
--- /dev/null
+++ b/testcases/template/mobly/mobly_test.py
@@ -0,0 +1,285 @@
+#
+# Copyright (C) 2017 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.
+#
+
+import importlib
+import json
+import logging
+import os
+import sys
+import time
+import yaml
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test
+from vts.runners.host import config_parser
+from vts.runners.host import keys
+from vts.runners.host import records
+from vts.runners.host import test_runner
+from vts.utils.python.io import capture_printout
+from vts.utils.python.io import file_util
+
+from mobly import test_runner as mobly_test_runner
+
+
+LIST_TEST_OUTPUT_START = '==========> '
+LIST_TEST_OUTPUT_END = ' <=========='
+# Temp directory inside python log path. The name is required to be
+# the set value for tradefed to skip reading contents as logs.
+TEMP_DIR_NAME = 'temp'
+CONFIG_FILE_NAME = 'test_config.yaml'
+MOBLY_RESULT_JSON_FILE_NAME = 'test_run_summary.json'
+MOBLY_RESULT_YAML_FILE_NAME = 'test_summary.yaml'
+
+
+MOBLY_CONFIG_TEXT = '''TestBeds:
+ - Name: {module_name}
+ Controllers:
+ AndroidDevice:
+ - serial: {serial1}
+ - serial: {serial2}
+
+MoblyParams:
+ LogPath: {log_path}
+'''
+
+#TODO(yuexima):
+# 1. make DEVICES_REQUIRED configurable
+# 2. add include filter function
+DEVICES_REQUIRED = 2
+
+RESULT_KEY_TYPE = 'Type'
+RESULT_TYPE_SUMMARY = 'Summary'
+RESULT_TYPE_RECORD = 'Record'
+RESULT_TYPE_TEST_NAME_LIST = 'TestNameList'
+RESULT_TYPE_CONTROLLER_INFO = 'ControllerInfo'
+
+
+class MoblyTest(base_test.BaseTestClass):
+ '''Template class for running mobly test cases.
+
+ Attributes:
+ mobly_dir: string, mobly test temp directory for mobly runner
+ mobly_config_file_path: string, mobly test config file path
+ result_handlers: dict, map of result type and handler functions
+ '''
+ def setUpClass(self):
+ asserts.assertEqual(
+ len(self.android_devices), DEVICES_REQUIRED,
+ 'Exactly %s devices are required for this test.' % DEVICES_REQUIRED
+ )
+
+ for ad in self.android_devices:
+ logging.debug('Android device serial: %s' % ad.serial)
+
+ logging.debug('Test cases: %s' % self.ListTestCases())
+
+ self.mobly_dir = os.path.join(logging.log_path, TEMP_DIR_NAME,
+ 'mobly', str(time.time()))
+
+ file_util.Makedirs(self.mobly_dir)
+
+ logging.debug('mobly log path: %s' % self.mobly_dir)
+
+ self.result_handlers = {
+ RESULT_TYPE_SUMMARY: self.HandleSimplePrint,
+ RESULT_TYPE_RECORD: self.HandleRecord,
+ RESULT_TYPE_TEST_NAME_LIST: self.HandleSimplePrint,
+ RESULT_TYPE_CONTROLLER_INFO: self.HandleSimplePrint,
+ }
+
+ def tearDownClass(self):
+ ''' Clear the mobly directory.'''
+ file_util.Rmdirs(self.mobly_dir, ignore_errors=True)
+
+ def PrepareConfigFile(self):
+ '''Prepare mobly config file for running test.'''
+ self.mobly_config_file_path = os.path.join(self.mobly_dir,
+ CONFIG_FILE_NAME)
+ config_text = MOBLY_CONFIG_TEXT.format(
+ module_name=self.test_module_name,
+ serial1=self.android_devices[0].serial,
+ serial2=self.android_devices[1].serial,
+ log_path=self.mobly_dir
+ )
+ with open(self.mobly_config_file_path, 'w') as f:
+ f.write(config_text)
+
+ def ListTestCases(self):
+ '''List test cases.
+
+ Returns:
+ List of string, test names.
+ '''
+ classes = mobly_test_runner._find_test_class()
+
+ with capture_printout.CaptureStdout() as output:
+ mobly_test_runner._print_test_names(classes)
+
+ test_names = []
+
+ for line in output:
+ if (not line.startswith(LIST_TEST_OUTPUT_START)
+ and line.endswith(LIST_TEST_OUTPUT_END)):
+ test_names.append(line)
+ tr_record = records.TestResultRecord(line, self.test_module_name)
+ self.results.requested.append(tr_record)
+
+ return test_names
+
+ def RunMoblyModule(self):
+ '''Execute mobly test module.'''
+ # Because mobly and vts uses a similar runner, both will modify
+ # log_path from python logging. The following step is to preserve
+ # log path after mobly test finishes.
+
+ # An alternative way is to start a new python process through shell
+ # command. In that case, test print out needs to be piped.
+ # This will also help avoid log overlapping
+
+ logger = logging.getLogger()
+ logger_path = logger.log_path
+ logging_path = logging.log_path
+
+ try:
+ mobly_test_runner.main(argv=['-c', self.mobly_config_file_path])
+ finally:
+ logger.log_path = logger_path
+ logging.log_path = logging_path
+
+ def GetMoblyResults(self):
+ '''Get mobly module run results and put in vts results.'''
+ file_handlers = (
+ (MOBLY_RESULT_YAML_FILE_NAME, self.ParseYamlResults),
+ (MOBLY_RESULT_JSON_FILE_NAME, self.ParseJsonResults),
+ )
+
+ for pair in file_handlers:
+ file_path = file_util.FindFile(self.mobly_dir, pair[0])
+
+ if file_path:
+ logging.debug('Mobly test yaml result path: %s', file_path)
+ pair[1](file_path)
+ return
+
+ asserts.fail('Mobly test result file not found.')
+
+ def generateAllTests(self):
+ '''Run the mobly test module and parse results.'''
+ #TODO(yuexima): report test names
+
+ self.PrepareConfigFile()
+ self.RunMoblyModule()
+ #TODO(yuexima): check whether DEBUG logs from mobly run are included
+ self.GetMoblyResults()
+
+ def ParseJsonResults(self, result_path):
+ '''Parse mobly test json result.
+
+ Args:
+ result_path: string, result json file path.
+ '''
+ with open(path, 'r') as f:
+ mobly_summary = json.load(f)
+
+ mobly_results = mobly_summary['Results']
+ for result in mobly_results:
+ logging.debug('Adding result for %s' % result[records.TestResultEnums.RECORD_NAME])
+ record = records.TestResultRecord(result[records.TestResultEnums.RECORD_NAME])
+ record.test_class = result[records.TestResultEnums.RECORD_CLASS]
+ record.begin_time = result[records.TestResultEnums.RECORD_BEGIN_TIME]
+ record.end_time = result[records.TestResultEnums.RECORD_END_TIME]
+ record.result = result[records.TestResultEnums.RECORD_RESULT]
+ record.uid = result[records.TestResultEnums.RECORD_UID]
+ record.extras = result[records.TestResultEnums.RECORD_EXTRAS]
+ record.details = result[records.TestResultEnums.RECORD_DETAILS]
+ record.extra_errors = result[records.TestResultEnums.RECORD_EXTRA_ERRORS]
+
+ self.results.addRecord(record)
+
+ def ParseYamlResults(self, result_path):
+ '''Parse mobly test yaml result.
+
+ Args:
+ result_path: string, result yaml file path.
+ '''
+ with open(result_path, 'r') as stream:
+ try:
+ docs = yaml.load_all(stream)
+ for doc in docs:
+ type = doc.get(RESULT_KEY_TYPE)
+ if type is None:
+ logging.warn(
+ 'Mobly result document type unrecognized: %s', doc)
+ continue
+
+ logging.debug('Parsing result type: %s', type)
+
+ handler = self.result_handlers.get(type)
+ if handler is None:
+ logging.debug('Unknown result type: %s', type)
+ handler = self.HandleSimplePrint
+
+ handler(doc)
+ except yaml.YAMLError as exc:
+ print(exc)
+
+ def HandleRecord(self, doc):
+ '''Handle record result document type.
+
+ Args:
+ doc: dict, result document item
+ '''
+ logging.debug('Adding result for %s' % doc.get(records.TestResultEnums.RECORD_NAME))
+ record = records.TestResultRecord(doc.get(records.TestResultEnums.RECORD_NAME))
+ record.test_class = doc.get(records.TestResultEnums.RECORD_CLASS)
+ record.begin_time = doc.get(records.TestResultEnums.RECORD_BEGIN_TIME)
+ record.end_time = doc.get(records.TestResultEnums.RECORD_END_TIME)
+ record.result = doc.get(records.TestResultEnums.RECORD_RESULT)
+ record.uid = doc.get(records.TestResultEnums.RECORD_UID)
+ record.extras = doc.get(records.TestResultEnums.RECORD_EXTRAS)
+ record.details = doc.get(records.TestResultEnums.RECORD_DETAILS)
+ record.extra_errors = doc.get(records.TestResultEnums.RECORD_EXTRA_ERRORS)
+
+ # 'Stacktrace' in yaml result is ignored. 'Stacktrace' is a more
+ # detailed version of record.details when exception is emitted.
+
+ self.results.addRecord(record)
+
+ def HandleSimplePrint(self, doc):
+ '''Simply print result document to log.
+
+ Args:
+ doc: dict, result document item
+ '''
+ for k, v in doc.items():
+ logging.debug(str(k) + ": " + str(v))
+
+def GetTestModuleNames():
+ '''Returns a list of mobly test module specified in test configuration.'''
+ configs = config_parser.load_test_config_file(sys.argv[1])
+ reduce_func = lambda x, y: x + y.get(keys.ConfigKeys.MOBLY_TEST_MODULE, [])
+ return reduce(reduce_func, configs, [])
+
+def ImportTestModules():
+ '''Dynamically import mobly test modules.'''
+ for module_name in GetTestModuleNames():
+ module, cls = module_name.rsplit('.', 1)
+ sys.modules['__main__'].__dict__[cls] = getattr(
+ importlib.import_module(module), cls)
+
+if __name__ == "__main__":
+ ImportTestModules()
+ test_runner.main()
diff --git a/harnesses/host_controller/__init__.py b/testcases/template/param_test/__init__.py
similarity index 100%
copy from harnesses/host_controller/__init__.py
copy to testcases/template/param_test/__init__.py
diff --git a/testcases/template/param_test/param_test.py b/testcases/template/param_test/param_test.py
new file mode 100644
index 0000000..aafa715
--- /dev/null
+++ b/testcases/template/param_test/param_test.py
@@ -0,0 +1,107 @@
+#
+# Copyright (C) 2018 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.
+#
+
+import logging
+
+from vts.runners.host import base_test
+from vts.runners.host import records
+from vts.runners.host import test_runner
+
+
+class ParamTestClass(base_test.BaseTestClass):
+ """Base class to run a parameterized test.
+
+ A parameterized test is a test with a set of parameters and the test will be
+ run against each parameter. This allows to test logic with different
+ parameters without without writing multiple copies of the same test.
+
+ An example use case of parameterized test is service name aware HAL testing
+ which we expect to run the same test logic against all service instances
+ through their corresponding service names. e.g to test graphics.composer HAL
+ against two different instance: default and vr.
+
+ Attributes:
+ params: list, a list of parameters for test run.
+ cur_param: the parameter used for the current run.
+ """
+
+ def __init__(self, configs):
+ super(ParamTestClass, self).__init__(configs)
+ self.initParams()
+
+ def initParams(self):
+ """Initialize test parameters. Expected to be overridden by a subclass."""
+ self._params = []
+
+ def getParamTag(self, param):
+ """Get the test tag used to attach with test name from the parameter.
+
+ expected to be overridden by a subclass.
+
+ Args:
+ param: the current test parameter.
+ """
+ return str(param)
+
+ @property
+ def params(self):
+ """Get params"""
+ return self._params
+
+ @params.setter
+ def params(self, params):
+ """Set params"""
+ self._params = params
+
+ @property
+ def cur_param(self):
+ """Get cur_param"""
+ return self._cur_param
+
+ @cur_param.setter
+ def cur_param(self, cur_param):
+ """Set cur_param"""
+ self._cur_param = cur_param
+
+ def run(self, test_names=None):
+ """Run a parameterized test.
+
+ For each parameter initialized for the test, runs test cases within
+ this test class against that parameter.
+
+ Args:
+ test_names: A list of string that are test case names requested in
+ cmd line.
+
+ Returns:
+ The test results object of this class.
+ """
+ logging.info("==========> %s <==========", self.test_module_name)
+ # Get the original tests.
+ tests = self.getTests(test_names)
+ # Run the set of original tests against each parameter.
+ for param in self.params:
+ self.cur_param = param
+ for idx, (test_name, test_func) in enumerate(tests):
+ param_test_name = str(test_name + self.getParamTag(param))
+ tests[idx] = (param_test_name, test_func)
+ if not self.run_as_vts_self_test:
+ self.results.requested = [
+ records.TestResultRecord(test_name, self.test_module_name)
+ for test_name, _ in tests
+ ]
+ self.runTests(tests)
+ return self.results
diff --git a/testcases/vts_selftest/manual_tests/README.txt b/testcases/vts_selftest/manual_tests/README.txt
new file mode 100644
index 0000000..5aff089
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/README.txt
@@ -0,0 +1,10 @@
+This directory contains test cases that require to be manually run.
+
+Test cases in this directory could be designed to:
+ crash device
+ crash test framework
+ have inconsistent test result
+ etc.
+
+It is up to the user's understanding and precaution before running tests
+from this directory.
\ No newline at end of file
diff --git a/harnesses/host_controller/__init__.py b/testcases/vts_selftest/manual_tests/__init__.py
similarity index 100%
copy from harnesses/host_controller/__init__.py
copy to testcases/vts_selftest/manual_tests/__init__.py
diff --git a/tools/vts-hc/Android.mk b/testcases/vts_selftest/manual_tests/flaky_hidl_test/Android.mk
similarity index 79%
copy from tools/vts-hc/Android.mk
copy to testcases/vts_selftest/manual_tests/flaky_hidl_test/Android.mk
index 7733142..ca1258f 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/vts_selftest/manual_tests/flaky_hidl_test/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsSelfTestFlakyHidlTest
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/vts_selftest/manual_tests/flaky_hidl_test/AndroidTest.xml b/testcases/vts_selftest/manual_tests/flaky_hidl_test/AndroidTest.xml
new file mode 100644
index 0000000..ff65df5
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/flaky_hidl_test/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VTS Self Test Flaky HIDL Test Case(s)">
+ <option name="config-descriptor:metadata" key="plan" value="vts-staging-selftest" />
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HalHidlTargetTest.push"/>
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsSelfTestFlakyHidlTest" />
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_selftest_flaky_test/vts_selftest_flaky_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_selftest_flaky_test/vts_selftest_flaky_test" />
+ <option name="binary-test-type" value="hal_hidl_gtest"/>
+ <option name="binary-test-disable-framework" value="true"/>
+ <option name="binary-test-stop-native-servers" value="true"/>
+ <option name="precondition-lshal" value="android.hardware.nfc@1.0"/>
+ <option name="test-timeout" value="30s"/>
+ </test>
+</configuration>
diff --git a/testcases/vts_selftest/manual_tests/flaky_test/Android.bp b/testcases/vts_selftest/manual_tests/flaky_test/Android.bp
new file mode 100644
index 0000000..9858d68
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/flaky_test/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_test {
+ name: "vts_selftest_flaky_test",
+ srcs: ["vts_selftest_flaky_test.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/tools/vts-hc/Android.mk b/testcases/vts_selftest/manual_tests/flaky_test/Android.mk
similarity index 79%
copy from tools/vts-hc/Android.mk
copy to testcases/vts_selftest/manual_tests/flaky_test/Android.mk
index 7733142..d743e41 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/vts_selftest/manual_tests/flaky_test/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsSelfTestFlakyTest
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/vts_selftest/manual_tests/flaky_test/AndroidTest.xml b/testcases/vts_selftest/manual_tests/flaky_test/AndroidTest.xml
new file mode 100644
index 0000000..53200a2
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/flaky_test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VTS Self Test Flaky Test Case(s)">
+ <option name="config-descriptor:metadata" key="plan" value="vts-staging-selftest" />
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsSelfTestFlakyTest" />
+ <option name="binary-test-working-directory" value="_32bit::/data/nativetest/" />
+ <option name="binary-test-working-directory" value="_64bit::/data/nativetest64/" />
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_selftest_flaky_test/vts_selftest_flaky_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_selftest_flaky_test/vts_selftest_flaky_test" />
+ <option name="binary-test-type" value="gtest" />
+ <option name="test-timeout" value="30s"/>
+ </test>
+</configuration>
diff --git a/testcases/vts_selftest/manual_tests/flaky_test/vts_selftest_flaky_test.cpp b/testcases/vts_selftest/manual_tests/flaky_test/vts_selftest_flaky_test.cpp
new file mode 100644
index 0000000..b63adfe
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/flaky_test/vts_selftest_flaky_test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+#define LOG_TAG "VtsSelfTestFlakyTest"
+#include <log/log.h>
+
+class VtsSelfTestFlakyTest : public ::testing::Test {
+ public:
+ virtual void SetUp() override {
+ struct timeval time;
+ gettimeofday(&time, NULL);
+
+ srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
+ }
+
+ virtual void TearDown() override {}
+};
+
+/**
+ * Always passing.
+ */
+TEST_F(VtsSelfTestFlakyTest, TestAlwaysPassing1) {
+ printf("PASS (with 100%% chance)\n");
+}
+
+TEST_F(VtsSelfTestFlakyTest, TestAlwaysPassing2) {
+ printf("PASS (with 100%% chance)\n");
+}
+
+/**
+ * Fails with 50% of chance.
+ */
+TEST_F(VtsSelfTestFlakyTest, TestFlaky1) {
+ int number = abs(rand());
+ printf("number: %d\n", number);
+ ASSERT_TRUE((number % 2) == 0);
+}
+
+TEST_F(VtsSelfTestFlakyTest, TestFlaky2) {
+ int number = abs(rand());
+ printf("number: %d\n", number);
+ ASSERT_TRUE((number % 2) == 0);
+}
+
+TEST_F(VtsSelfTestFlakyTest, TestFlaky3) {
+ int number = abs(rand());
+ printf("number: %d\n", number);
+ ASSERT_TRUE((number % 2) == 0);
+}
+
+TEST_F(VtsSelfTestFlakyTest, TestFlaky4) {
+ int number = abs(rand());
+ printf("number: %d\n", number);
+ ASSERT_TRUE((number % 2) == 0);
+}
+
+TEST_F(VtsSelfTestFlakyTest, TestFlaky5) {
+ int number = abs(rand());
+ printf("number: %d\n", number);
+ ASSERT_TRUE((number % 2) == 0);
+}
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tools/vts-hc/Android.mk b/testcases/vts_selftest/manual_tests/shell_performance/Android.mk
similarity index 79%
copy from tools/vts-hc/Android.mk
copy to testcases/vts_selftest/manual_tests/shell_performance/Android.mk
index 7733142..8474ea1 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/vts_selftest/manual_tests/shell_performance/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsSelfTestShellPerformance
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/vts_selftest/manual_tests/shell_performance/AndroidTest.xml b/testcases/vts_selftest/manual_tests/shell_performance/AndroidTest.xml
new file mode 100644
index 0000000..d21d5cc
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/shell_performance/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VTS Self Test Shell Performance Banchmark">
+ <option name="config-descriptor:metadata" key="plan" value="vts-staging-selftest" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ <option name="push" value="DATA/nativetest64/vts_selftest_zero_testcase_binary_test/vts_selftest_zero_testcase_binary_test->/data/local/tmp/zero_testcase"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsSelfTestShellPerformance" />
+ <option name="test-case-path" value="vts/testcases/vts_selftest/manual_tests/shell_performance/VtsSelfTestShellPerformance" />
+ </test>
+</configuration>
diff --git a/testcases/vts_selftest/manual_tests/shell_performance/VtsSelfTestShellPerformance.py b/testcases/vts_selftest/manual_tests/shell_performance/VtsSelfTestShellPerformance.py
new file mode 100644
index 0000000..e95d348
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/shell_performance/VtsSelfTestShellPerformance.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 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.
+#
+
+import logging
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test
+from vts.runners.host import const
+from vts.runners.host import test_runner
+import time
+
+
+class VtsSelfTestShellPerformance(base_test.BaseTestClass):
+ '''A simple performance test to compare adb shell and VTS shell.'''
+
+ def setUpClass(self):
+ # Since we are running the actual test cases, run_as_vts_self_test
+ # must be set to False.
+ self.run_as_vts_self_test = False
+
+ self.dut = self.android_devices[0]
+ self.shell = self.dut.shell
+
+ def VtsShell(self, cmd, n):
+ '''Execute a command for n times via VTS shell.
+
+ Args:
+ cmd: string, command to execute
+ n: int, number of repeated calls
+ '''
+ for i in range(n):
+ self.shell.Execute(cmd)
+
+ def AdbShell(self, cmd, n):
+ '''Execute a command for n times via ADB shell.
+
+ Args:
+ cmd: string, command to execute
+ n: int, number of repeated calls
+ '''
+ for i in range(n):
+ self.dut.adb.shell(cmd)
+
+ def VtsShellList(self, cmd, n):
+ '''Execute a command for n times via VTS shell as a list.
+
+ Args:
+ cmd: string, command to execute
+ n: int, number of repeated calls
+ '''
+ self.shell.Execute([cmd] * n)
+
+ def Measure(self, func, *args):
+ '''Measure time lapsed when executing a function.
+
+ Args:
+ func: function, function to execute
+ *args: list of arguments for the functions
+ '''
+ start = time.time()
+ func(*args)
+ return time.time() - start
+
+ def testPerformance(self):
+ '''Run a empty test case on device for 100 times and log the times.'''
+
+ cmd = "/data/local/tmp/zero_testcase"
+
+ # First call to eliminate caching effects
+ self.AdbShell(cmd, 1)
+ self.VtsShell(cmd, 1)
+
+ repeats = 100
+
+ adb_time = self.Measure(self.AdbShell, cmd, repeats)
+ vts_time = self.Measure(self.VtsShell, cmd, repeats)
+ vts_list_time = self.Measure(self.VtsShellList, cmd, repeats)
+
+ logging.info("adb shell for 100 times = %s", adb_time)
+ logging.info("vts shell for 100 times = %s", vts_time)
+ logging.info("vts shell with for 100 times = %s", vts_list_time)
+
+
+if __name__ == "__main__":
+ test_runner.main()
diff --git a/harnesses/host_controller/__init__.py b/testcases/vts_selftest/manual_tests/shell_performance/__init__.py
similarity index 100%
copy from harnesses/host_controller/__init__.py
copy to testcases/vts_selftest/manual_tests/shell_performance/__init__.py
diff --git a/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/Android.bp b/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/Android.bp
new file mode 100644
index 0000000..8c21fb5
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_test {
+ name: "vts_selftest_zero_testcase_binary_test",
+ srcs: ["vts_selftest_zero_testcase_binary_test.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/tools/vts-hc/Android.mk b/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/Android.mk
similarity index 78%
copy from tools/vts-hc/Android.mk
copy to testcases/vts_selftest/manual_tests/zero_testcase_binary_test/Android.mk
index 7733142..8cbd7ce 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsSelfTestZeroTestCaseBinaryTest
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/AndroidTest.xml b/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/AndroidTest.xml
new file mode 100644
index 0000000..dab87b0
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VTS Self Test Zero Test Case Binary Test Case(s)">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsSelfTestZeroTestCaseBinaryTest" />
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_selftest_zero_testcase_binary_test/vts_selftest_zero_testcase_binary_test" />
+ <option name="binary-test-type" value="gtest" />
+ <option name="skip-on-32bit-abi" value="true" />
+ <option name="test-timeout" value="10s"/>
+ </test>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsSelfTestZeroTestCaseBinaryTest" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_selftest_zero_testcase_binary_test/vts_selftest_zero_testcase_binary_test" />
+ <option name="binary-test-type" value="gtest" />
+ <option name="skip-on-64bit-abi" value="true" />
+ <option name="test-timeout" value="10s"/>
+ </test>
+</configuration>
diff --git a/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/vts_selftest_zero_testcase_binary_test.cpp b/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/vts_selftest_zero_testcase_binary_test.cpp
new file mode 100644
index 0000000..510204a
--- /dev/null
+++ b/testcases/vts_selftest/manual_tests/zero_testcase_binary_test/vts_selftest_zero_testcase_binary_test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 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 <gtest/gtest.h>
+#define LOG_TAG "VtsSelfTestZeroTestCaseBinaryTest"
+#include <log/log.h>
+
+class VtsSelfTestFlakyTest : public ::testing::Test {
+ public:
+ virtual void SetUp() override {}
+
+ virtual void TearDown() override {}
+};
+
+/**
+ * Always passing.
+ */
+TEST_F(VtsSelfTestFlakyTest, EmptyTest) {}
diff --git a/testcases/vts_selftest/test_framework/base_test/Android.mk b/testcases/vts_selftest/test_framework/base_test/Android.mk
index 7bfa47a..a95e592 100644
--- a/testcases/vts_selftest/test_framework/base_test/Android.mk
+++ b/testcases/vts_selftest/test_framework/base_test/Android.mk
@@ -17,5 +17,4 @@
include $(CLEAR_VARS)
LOCAL_MODULE := VtsSelfTestBaseTest
-VTS_CONFIG_SRC_DIR := testcases/vts_selftest/test_framework/base_test
include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/vts_selftest/test_framework/base_test/AndroidTest.xml b/testcases/vts_selftest/test_framework/base_test/AndroidTest.xml
index 5a8192b..60353f1 100644
--- a/testcases/vts_selftest/test_framework/base_test/AndroidTest.xml
+++ b/testcases/vts_selftest/test_framework/base_test/AndroidTest.xml
@@ -14,14 +14,19 @@
limitations under the License.
-->
<configuration description="Config for VTS Framework Integration Test Case">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
<option name="push-group" value="HostDrivenTest.push" />
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
- </target_preparer>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="VtsSelfTestBaseTest"/>
<option name="test-case-path" value="vts/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTest" />
+ <option name="config-str" key="a" value="a"/>
+ <option name="config-str" key="b" value="b"/>
+ <option name="config-int" key="a" value="1"/>
+ <option name="config-int" key="b" value="2"/>
+ <option name="config-bool" key="a" value="true"/>
+ <option name="config-bool" key="b" value="false"/>
</test>
<test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
<option name="test-module-name" value="VtsSelfTestBaseTestFilterInclude"/>
diff --git a/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTest.py b/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTest.py
index b2c3d71..1070602 100644
--- a/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTest.py
+++ b/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTest.py
@@ -86,6 +86,61 @@
asserts.assertTrue(self.dut.total_memory > 0,
'Failed to get device memory info.')
+ def test_getUserConfigStr1(self):
+ '''Test getUserConfigStr.'''
+ asserts.assertEqual(self.getUserConfigStr('a'), 'a')
+
+ def test_getUserConfigStr2(self):
+ '''Test getUserConfigStr.'''
+ asserts.assertEqual(self.getUserConfigStr('b'), 'b')
+
+ def test_getUserConfigStr3(self):
+ '''Test getUserConfigStr.'''
+ asserts.assertEqual(self.getUserConfigStr('c'), None)
+
+ def test_getUserConfigStr4(self):
+ '''Test getUserConfigStr.'''
+ asserts.assertEqual(self.getUserConfigStr('c', to_str=True), None)
+
+ def test_getUserConfigInt1(self):
+ '''Test getUserConfigInt.'''
+ asserts.assertEqual(self.getUserConfigInt('a'), 1)
+
+ def test_getUserConfigInt2(self):
+ '''Test getUserConfigInt.'''
+ asserts.assertEqual(self.getUserConfigInt('b'), 2)
+
+ def test_getUserConfigInt3(self):
+ '''Test getUserConfigInt.'''
+ asserts.assertEqual(self.getUserConfigInt('b', to_str=True), '2')
+
+ def test_getUserConfigInt4(self):
+ '''Test getUserConfigInt.'''
+ asserts.assertEqual(self.getUserConfigInt('c'), None)
+
+ def test_getUserConfigInt5(self):
+ '''Test getUserConfigInt.'''
+ asserts.assertEqual(self.getUserConfigInt('c', to_str=True), None)
+
+ def test_getUserConfigBool1(self):
+ '''Test getUserConfigBool.'''
+ asserts.assertEqual(self.getUserConfigBool('a'), True)
+
+ def test_getUserConfigBool2(self):
+ '''Test getUserConfigBool.'''
+ asserts.assertEqual(self.getUserConfigBool('b'), False)
+
+ def test_getUserConfigBool3(self):
+ '''Test getUserConfigBool.'''
+ asserts.assertEqual(self.getUserConfigBool('b', to_str=True), 'False')
+
+ def test_getUserConfigBool4(self):
+ '''Test getUserConfigBool.'''
+ asserts.assertEqual(self.getUserConfigBool('c'), None)
+
+ def test_getUserConfigBool5(self):
+ '''Test getUserConfigBool.'''
+ asserts.assertEqual(self.getUserConfigBool('c', to_str=True), None)
if __name__ == "__main__":
test_runner.main()
diff --git a/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilter.py b/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilter.py
index 5d53ee9..6cf15da 100644
--- a/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilter.py
+++ b/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilter.py
@@ -37,6 +37,10 @@
# Override
def setUpClass(self):
+ # Since we are running the actual test cases, run_as_vts_self_test
+ # must be set to False.
+ self.run_as_vts_self_test = False
+
self.dut = self.android_devices[0]
self.shell = self.dut.shell
diff --git a/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilterExclude.py b/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilterExclude.py
index a346eee..c57fbe0 100644
--- a/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilterExclude.py
+++ b/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilterExclude.py
@@ -39,6 +39,9 @@
'suite2.test1_32bit',
'suite2.test1_64bit',
'suite3.test2_64bit',
+ # Since include_filter is empty, any pattern not matching the ones in
+ # exclude filter should pass
+ 'other.test_names',
]
SHOULD_NOT_PASS_FILTER = [
@@ -50,8 +53,19 @@
'suite3.test1_32bit',
'suite3.test1_64bit',
'suite3.test2_32bit',
+ # The following test is added to exclude filter through
+ # filter's add_to_exclude_filter method when expand_bitness is True
+ 'added.test1_32bit',
+ # The following test is added to include filter with negative pattern by
+ # filter's add_to_exclude_filter method when expand_bitness is True
+ 'added.test2_64bit',
]
+ # Override
+ def setUpClass(self):
+ super(VtsSelfTestBaseTestFilterExclude, self).setUpClass()
+ self.test_filter.add_to_exclude_filter('added.test1')
+ self.test_filter.add_to_include_filter('-added.test2')
if __name__ == "__main__":
test_runner.main()
diff --git a/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilterInclude.py b/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilterInclude.py
index 3198fba..4817c0f 100644
--- a/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilterInclude.py
+++ b/testcases/vts_selftest/test_framework/base_test/VtsSelfTestBaseTestFilterInclude.py
@@ -39,6 +39,7 @@
'suite1.test2_32bit',
'suite2.any_matching_regex',
'suite3.test1',
+ 'added.test1_64bit',
]
SHOULD_NOT_PASS_FILTER = [
@@ -48,6 +49,11 @@
'suite3.test2',
]
+ # Override
+ def setUpClass(self):
+ super(VtsSelfTestBaseTestFilterInclude, self).setUpClass()
+ self.test_filter.add_to_include_filter('added.test1')
+
if __name__ == "__main__":
test_runner.main()
diff --git a/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/README.md b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/README.md
new file mode 100644
index 0000000..5288514
--- /dev/null
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/README.md
@@ -0,0 +1,12 @@
+# PythonVirtualenvPreparerTest
+
+This directory tests the functionality of VtsPythonVirtualenvPreparer.
+
+
+Two modules are included in this project:
+
+* VtsSelfTestPythonVirtualenvPreparerTestPart0: to verify the python module (numpy) that's going to be tested has not been installed by default.
+* VtsSelfTestPythonVirtualenvPreparerTestPart1: test duplicated module preparer to install a new module and empty module preparer.
+* VtsSelfTestPythonVirtualenvPreparerTestPart2: test whether a python module installed in previous tests is still available through plan level virtual environment
+
+The naming of `Part0`, `Part1` and `Part2` is to ensure the order of execution.
diff --git a/harnesses/host_controller/__init__.py b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/__init__.py
similarity index 100%
copy from harnesses/host_controller/__init__.py
copy to testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/__init__.py
diff --git a/tools/vts-hc/Android.mk b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/Android.mk
similarity index 77%
copy from tools/vts-hc/Android.mk
copy to testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/Android.mk
index 7733142..0e09299 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsSelfTestPythonVirtualenvPreparerTestPart0
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/AndroidTest.xml b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/AndroidTest.xml
new file mode 100644
index 0000000..1ad1e46
--- /dev/null
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VtsSelfTestPythonVirtualenvPreparerTestPart0 Test Case">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsSelfTestPythonVirtualenvPreparerTestPart0"/>
+ <option name="test-case-path" value="vts/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/VtsSelfTestPythonVirtualenvPreparerTestPart0" />
+ </test>
+</configuration>
diff --git a/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/VtsSelfTestPythonVirtualenvPreparerTestPart0.py b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/VtsSelfTestPythonVirtualenvPreparerTestPart0.py
new file mode 100644
index 0000000..d534362
--- /dev/null
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/VtsSelfTestPythonVirtualenvPreparerTestPart0.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 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.
+#
+
+import logging
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test
+from vts.runners.host import const
+from vts.runners.host import test_runner
+
+
+class VtsSelfTestPythonVirtualenvPreparerTestPart0(base_test.BaseTestClass):
+ '''Tests plan and module level VirtualenvPreparer.'''
+
+ def setUpClass(self):
+ # Since we are running the actual test cases, run_as_vts_self_test
+ # must be set to False.
+ self.run_as_vts_self_test = False
+
+ def testNonExistingModule(self):
+ '''Test whether numpy is not installed from default packages.
+
+ This test assumes numpy is not in default package install list.
+ If this turned otherwise, test logic here should be updated.
+ '''
+ try:
+ import numpy
+ asserts.fail('numpy should not have been not installed yet.')
+ except ImportError:
+ pass
+
+
+if __name__ == "__main__":
+ test_runner.main()
diff --git a/harnesses/host_controller/__init__.py b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/__init__.py
similarity index 100%
copy from harnesses/host_controller/__init__.py
copy to testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part0/__init__.py
diff --git a/tools/vts-hc/Android.mk b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/Android.mk
similarity index 77%
copy from tools/vts-hc/Android.mk
copy to testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/Android.mk
index 7733142..17bc31a 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsSelfTestPythonVirtualenvPreparerTestPart1
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/AndroidTest.xml b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/AndroidTest.xml
new file mode 100644
index 0000000..119b565
--- /dev/null
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for VtsSelfTestPythonVirtualenvPreparerTestPart1 Test Case">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ </target_preparer>
+ <multi_target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
+ <option name="dep-module" value="numpy" />
+ </multi_target_preparer>
+ <multi_target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
+ <option name="dep-module" value="numpy" />
+ </multi_target_preparer>
+ <multi_target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
+ </multi_target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsSelfTestPythonVirtualenvPreparerTestPart1"/>
+ <option name="test-case-path" value="vts/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/VtsSelfTestPythonVirtualenvPreparerTestPart1" />
+ </test>
+</configuration>
diff --git a/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/VtsSelfTestPythonVirtualenvPreparerTestPart1.py b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/VtsSelfTestPythonVirtualenvPreparerTestPart1.py
new file mode 100644
index 0000000..6c3fdbc
--- /dev/null
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/VtsSelfTestPythonVirtualenvPreparerTestPart1.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 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.
+#
+
+import logging
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test
+from vts.runners.host import const
+from vts.runners.host import test_runner
+
+
+class VtsSelfTestPythonVirtualenvPreparerTestPart1(base_test.BaseTestClass):
+ '''Tests plan and module level VirtualenvPreparer.'''
+
+ def setUpClass(self):
+ # Since we are running the actual test cases, run_as_vts_self_test
+ # must be set to False.
+ self.run_as_vts_self_test = False
+
+ def testInstalledModule(self):
+ '''Test a module installed in this test.'''
+ try:
+ import numpy
+ except ImportError:
+ asserts.fail('numpy should have been installed.')
+
+
+if __name__ == "__main__":
+ test_runner.main()
diff --git a/harnesses/host_controller/__init__.py b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/__init__.py
similarity index 100%
copy from harnesses/host_controller/__init__.py
copy to testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part1/__init__.py
diff --git a/tools/vts-hc/Android.mk b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/Android.mk
similarity index 77%
copy from tools/vts-hc/Android.mk
copy to testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/Android.mk
index 7733142..687e5ce 100644
--- a/tools/vts-hc/Android.mk
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -11,12 +12,9 @@
# 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.
-
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+LOCAL_MODULE := VtsSelfTestPythonVirtualenvPreparerTestPart2
+include test/vts/tools/build/Android.host_config.mk
diff --git a/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/AndroidTest.xml b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/AndroidTest.xml
new file mode 100644
index 0000000..678e891
--- /dev/null
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Config for VtsSelfTestPythonVirtualenvPreparerTestPart2 Test Case">
+ <option name="config-descriptor:metadata" key="plan" value="vts-misc" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsSelfTestPythonVirtualenvPreparerTestPart2"/>
+ <option name="test-case-path" value="vts/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/VtsSelfTestPythonVirtualenvPreparerTestPart2" />
+ </test>
+</configuration>
diff --git a/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/VtsSelfTestPythonVirtualenvPreparerTestPart2.py b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/VtsSelfTestPythonVirtualenvPreparerTestPart2.py
new file mode 100644
index 0000000..0e43289
--- /dev/null
+++ b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/VtsSelfTestPythonVirtualenvPreparerTestPart2.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 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.
+#
+
+import logging
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test
+from vts.runners.host import const
+from vts.runners.host import test_runner
+
+
+class VtsSelfTestPythonVirtualenvPreparerTestPart2(base_test.BaseTestClass):
+ '''Tests plan and module level VirtualenvPreparer.'''
+
+ def setUpClass(self):
+ # Since we are running the actual test cases, run_as_vts_self_test
+ # must be set to False.
+ self.run_as_vts_self_test = False
+
+ def testExistingModule(self):
+ '''Test previously installed module's availability.'''
+ try:
+ import numpy
+ except ImportError:
+ asserts.fail('numpy should have been installed in Part1.')
+
+
+if __name__ == "__main__":
+ test_runner.main()
diff --git a/harnesses/host_controller/__init__.py b/testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/__init__.py
similarity index 100%
copy from harnesses/host_controller/__init__.py
copy to testcases/vts_selftest/test_framework/python_virtualenv_preparer_test/part2/__init__.py
diff --git a/tools/build/tasks/list/vts_apk_package_list.mk b/tools/build/tasks/list/vts_apk_package_list.mk
index cccae0d..ec79590 100644
--- a/tools/build/tasks/list/vts_apk_package_list.mk
+++ b/tools/build/tasks/list/vts_apk_package_list.mk
@@ -13,11 +13,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# APKs used by VTS framework.
vts_apk_packages := \
VtsAgentApp \
CtsVerifier \
sl4a \
+# Other tests APKs included as part of VTS.
+vts_apk_packages += \
+ DeviceHealthTests
vts_prebuilt_apk_packages := \
diff --git a/tools/build/tasks/list/vts_bin_package_list.mk b/tools/build/tasks/list/vts_bin_package_list.mk
index 76e3be1..86e6808 100644
--- a/tools/build/tasks/list/vts_bin_package_list.mk
+++ b/tools/build/tasks/list/vts_bin_package_list.mk
@@ -21,3 +21,7 @@
vts_profiling_configure \
vts_coverage_configure \
vts_testability_checker \
+
+# Extra apk utils for VTS framework.
+vts_bin_packages += \
+ WifiUtil \
diff --git a/tools/build/tasks/list/vts_test_bin_package_list.mk b/tools/build/tasks/list/vts_test_bin_package_list.mk
index 07ecec4..d23f809 100644
--- a/tools/build/tasks/list/vts_test_bin_package_list.mk
+++ b/tools/build/tasks/list/vts_test_bin_package_list.mk
@@ -27,7 +27,10 @@
libhwbinder_latency \
libbinder_benchmark \
vts_codelab_target_binary \
+ vts_selftest_flaky_test \
+ vts_selftest_zero_testcase_binary_test \
vts_test_binary_crash_app \
+ vts_test_binary_seg_fault \
vts_test_binary_syscall_exists \
simpleperf_cpu_hotplug_test \
binderThroughputTest \
@@ -38,6 +41,7 @@
stressapptest \
libcutils_test \
vts_test_binary_qtaguid_module \
+ vts_test_binary_bpf_module \
# Proto fuzzer executable
vts_test_bin_packages += \
@@ -45,14 +49,17 @@
# VTS Treble VINTF Test
vts_test_bin_packages += \
+ vts_ibase_test \
vts_treble_vintf_test \
# Netd tests
vts_test_bin_packages += \
netd_integration_test \
-# Tun device tests.
+# Kernel tests.
vts_test_bin_packages += \
+ dt_early_mount_test \
+ kernel_net_tests \
vts_kernel_tun_test \
# Binder tests.
@@ -64,6 +71,7 @@
binderLibTest_IPC_32 \
binderTextOutputTest \
binderSafeInterfaceTest \
+ memunreachable_binder_test \
# VTS security PoC tests
vts_test_bin_packages += \
@@ -71,4 +79,8 @@
28838221 \
32219453 \
31707909 \
- 32402310
+ 32402310 \
+
+# VTS DTBO verification tests
+vts_test_bin_packages += \
+ ufdt_verify_overlay
diff --git a/tools/build/tasks/list/vts_test_host_bin_package_list.mk b/tools/build/tasks/list/vts_test_host_bin_package_list.mk
index 932a0c0..bb190e9 100644
--- a/tools/build/tasks/list/vts_test_host_bin_package_list.mk
+++ b/tools/build/tasks/list/vts_test_host_bin_package_list.mk
@@ -2,3 +2,10 @@
host_cross_vndk-vtable-dumper \
trace_processor \
vndk-vtable-dumper \
+ img2simg \
+ simg2img \
+ mkuserimg_mke2fs.sh \
+
+# Need to package mkdtboimg.py since the tool is not just used by the VTS test.
+vts_test_host_bin_packages += \
+ mkdtboimg.py \
diff --git a/tools/build/tasks/list/vts_test_host_lib_package_list.mk b/tools/build/tasks/list/vts_test_host_lib_package_list.mk
index eef8357..c15180f 100644
--- a/tools/build/tasks/list/vts_test_host_lib_package_list.mk
+++ b/tools/build/tasks/list/vts_test_host_lib_package_list.mk
@@ -1,9 +1,9 @@
vts_test_host_lib_packages := \
- host_cross_libLLVM \
+ host_cross_libLLVM_android \
libbase \
libc++ \
libcutils \
- libLLVM \
+ libLLVM_android \
liblog \
libprotobuf-cpp-full \
libvts_multidevice_proto \
diff --git a/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk b/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
index bdc0f3e..34e99ab 100644
--- a/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
+++ b/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
@@ -49,6 +49,7 @@
android.hardware.memtrack@1.0-vts.driver \
android.hardware.neuralnetworks@1.0-vts.driver \
android.hardware.nfc@1.0-vts.driver \
+ android.hardware.nfc@1.1-vts.driver \
android.hardware.oemlock@1.0-vts.driver \
android.hardware.power@1.0-vts.driver \
android.hardware.power@1.1-vts.driver \
@@ -56,6 +57,7 @@
android.hardware.radio@1.1-vts.driver \
android.hardware.radio.deprecated@1.0-vts.driver \
android.hardware.renderscript@1.0-vts.driver \
+ android.hardware.secure_element@1.0-vts.driver \
android.hardware.sensors@1.0-vts.driver \
android.hardware.soundtrigger@2.0-vts.driver \
android.hardware.tetheroffload.config@1.0-vts.driver \
@@ -111,6 +113,7 @@
android.hardware.memtrack@1.0-vts.profiler \
android.hardware.neuralnetworks@1.0-vts.profiler \
android.hardware.nfc@1.0-vts.profiler \
+ android.hardware.nfc@1.1-vts.profiler \
android.hardware.oemlock@1.0-vts.profiler \
android.hardware.power@1.0-vts.profiler \
android.hardware.power@1.1-vts.profiler \
@@ -118,6 +121,7 @@
android.hardware.radio@1.1-vts.profiler \
android.hardware.radio.deprecated@1.0-vts.profiler \
android.hardware.renderscript@1.0-vts.profiler \
+ android.hardware.secure_element@1.0-vts.profiler \
android.hardware.sensors@1.0-vts.profiler \
android.hardware.soundtrigger@2.0-vts.profiler \
android.hardware.tetheroffload.config@1.0-vts.profiler \
@@ -150,6 +154,7 @@
VtsHalContexthubV1_0TargetTest \
VtsHalDrmV1_0TargetTest \
VtsHalDumpstateV1_0TargetTest \
+ VtsHalEvsV1_0TargetTest \
VtsHalGatekeeperV1_0TargetTest \
VtsHalGnssV1_0TargetTest \
VtsHalGraphicsComposerV2_1TargetTest \
@@ -166,13 +171,16 @@
VtsHalMemtrackV1_0TargetTest \
VtsHalNeuralnetworksV1_0TargetTest \
VtsHalNfcV1_0TargetTest \
+ VtsHalNfcV1_1TargetTest \
VtsHalOemLockV1_0TargetTest \
VtsHalPowerV1_0TargetTest \
VtsHalPowerV1_1TargetTest \
VtsHalRadioV1_0TargetTest \
VtsHalRadioV1_1TargetTest \
+ VtsHalRadioV1_2TargetTest \
VtsHalRenderscriptV1_0TargetTest \
VtsHalSapV1_0TargetTest \
+ VtsHalSecureElementV1_0TargetTest \
VtsHalSensorsV1_0TargetTest \
VtsHalSoundtriggerV2_0TargetTest \
VtsHalTetheroffloadConfigV1_0TargetTest \
diff --git a/tools/build/tasks/list/vts_test_lib_package_list.mk b/tools/build/tasks/list/vts_test_lib_package_list.mk
index 7f33503..84c6b23 100644
--- a/tools/build/tasks/list/vts_test_lib_package_list.mk
+++ b/tools/build/tasks/list/vts_test_lib_package_list.mk
@@ -41,6 +41,10 @@
libfortify2-tests-clang \
libgnu-hash-table-library \
libnstest_dlopened \
+ libnstest_ns_a_public1 \
+ libnstest_ns_a_public1_internal \
+ libnstest_ns_b_public2 \
+ libnstest_ns_b_public3 \
libnstest_private \
libnstest_private_external \
libnstest_public \
diff --git a/tools/build/tasks/vts_package.mk b/tools/build/tasks/vts_package.mk
index 72b2efe..b63d0ee 100644
--- a/tools/build/tasks/vts_package.mk
+++ b/tools/build/tasks/vts_package.mk
@@ -36,7 +36,7 @@
-include external/ltp/android/ltp_package_list.mk
VTS_OUT_ROOT := $(HOST_OUT)/vts
-VTS_TESTCASES_OUT := $(HOST_OUT)/vts/android-vts/testcases
+VTS_TESTCASES_OUT := $(VTS_OUT_ROOT)/android-vts/testcases
VTS_TOOLS_OUT := $(VTS_OUT_ROOT)/android-vts/tools
# Packaging rule for android-vts.zip
@@ -47,7 +47,7 @@
include $(BUILD_SYSTEM)/tasks/tools/compatibility.mk
.PHONY: vts
-vts: $(compatibility_zip) run
+vts: $(compatibility_zip) vtslab adb
$(call dist-for-goals, vts, $(compatibility_zip))
# Packaging rule for android-vts.zip's testcases dir (DATA subdir).
@@ -111,15 +111,14 @@
$(call host-native-copy-pairs,$(target_hostdriven_modules),$(VTS_TESTCASES_OUT))
host_additional_deps_copy_pairs := \
- test/vts/tools/vts-hc/run:$(VTS_TOOLS_OUT)/run \
test/vts/tools/vts-tradefed/etc/vts-tradefed_win.bat:$(VTS_TOOLS_OUT)/vts-tradefed_win.bat \
- test/vts/tools/vts-tradefed/CtsDynamicConfig.xml:$(VTS_TESTCASES_OUT)/cts.dynamic
+ test/vts/tools/vts-tradefed/DynamicConfig.xml:$(VTS_TESTCASES_OUT)/cts.dynamic
# Packaging rule for host-side Python logic, configs, and data files
host_framework_files := \
$(call find-files-in-subdirs,test/vts,"*.py" -and -type f,.) \
- $(call find-files-in-subdirs,test/vts,"*.config" -and -type f,.) \
+ $(call find-files-in-subdirs,test/vts,"*.runner_conf" -and -type f,.) \
$(call find-files-in-subdirs,test/vts,"*.push" -and -type f,.)
host_framework_copy_pairs := \
@@ -128,7 +127,7 @@
host_testcase_files := \
$(call find-files-in-subdirs,test/vts-testcase,"*.py" -and -type f,.) \
- $(call find-files-in-subdirs,test/vts-testcase,"*.config" -and -type f,.) \
+ $(call find-files-in-subdirs,test/vts-testcase,"*.runner_conf" -and -type f,.) \
$(call find-files-in-subdirs,test/vts-testcase,"*.push" -and -type f,.) \
$(call find-files-in-subdirs,test/vts-testcase,"*.dump" -and -type f,.)
@@ -143,6 +142,8 @@
$(foreach f,$(host_kernel_config_files),\
kernel/configs/$(f):$(VTS_TESTCASES_OUT)/vts/testcases/kernel/config/data/$(f))
+ifneq ($(TARGET_BUILD_PDK),true)
+
host_camera_its_files := \
$(call find-files-in-subdirs,cts/apps/CameraITS,"*.py" -and -type f,.) \
$(call find-files-in-subdirs,cts/apps/CameraITS,"*.pdf" -and -type f,.) \
@@ -152,6 +153,12 @@
$(foreach f,$(host_camera_its_files),\
cts/apps/CameraITS/$(f):$(VTS_TESTCASES_OUT)/CameraITS/$(f))
+else
+
+host_camera_its_copy_pairs :=
+
+endif # ifneq ($(TARGET_BUILD_PDK),true)
+
host_systrace_files := \
$(filter-out .git/%, \
$(call find-files-in-subdirs,external/chromium-trace,"*" -and -type f,.))
@@ -167,6 +174,13 @@
$(foreach f,$(media_test_res_files),\
hardware/interfaces/media/res/$(f):$(VTS_TESTCASES_OUT)/DATA/media/res/$(f))
+nbu_p2p_apk_files := \
+ $(call find-files-in-subdirs,test/vts-testcase/nbu/src,"*.apk" -and -type f,.)
+
+nbu_p2p_apk_copy_pairs := \
+ $(foreach f,$(nbu_p2p_apk_files),\
+ test/vts-testcase/nbu/src/$(f):$(VTS_TESTCASES_OUT)/DATA/app/nbu/$(f))
+
performance_test_res_files := \
$(call find-files-in-subdirs,test/vts-testcase/performance/res/,"*.*" -and -type f,.) \
@@ -202,23 +216,48 @@
$(foreach f,$(acts_testcases_files),\
tools/test/connectivity/acts/tests/google/$(f):$(VTS_TESTCASES_OUT)/vts/testcases/acts/$(f))
-$(compatibility_zip): \
- $(call copy-many-files,$(target_native_copy_pairs)) \
- $(call copy-many-files,$(target_spec_copy_pairs)) \
- $(call copy-many-files,$(target_trace_copy_pairs)) \
- $(call copy-many-files,$(target_hostdriven_copy_pairs)) \
- $(call copy-many-files,$(target_hal_hash_copy_pairs)) \
- $(call copy-many-files,$(host_additional_deps_copy_pairs)) \
+target_script_files := \
+ $(call find-files-in-subdirs,test/vts/script/target,"*.sh" -and -type f,.)
+
+target_script_copy_pairs := \
+ $(foreach f,$(target_script_files),\
+ test/vts/script/target/$(f):$(VTS_TESTCASES_OUT)/script/target/$(f))
+
+system_property_compatibility_test_res_copy_pairs := \
+ system/sepolicy/public/property_contexts:$(VTS_TESTCASES_OUT)/vts/testcases/security/system_property/data/property_contexts
+
+$(VTS_TESTCASES_OUT)/vts/testcases/vndk/golden/platform_vndk_version.txt:
+ @echo -n $(PLATFORM_VNDK_VERSION) > $@
+
+vts_test_core_copy_pairs := \
$(call copy-many-files,$(host_framework_copy_pairs)) \
$(call copy-many-files,$(host_testcase_copy_pairs)) \
+ $(call copy-many-files,$(host_additional_deps_copy_pairs)) \
+ $(call copy-many-files,$(target_spec_copy_pairs)) \
+ $(call copy-many-files,$(target_hal_hash_copy_pairs)) \
+ $(call copy-many-files,$(acts_framework_copy_pairs)) \
+
+vts_copy_pairs := \
+ $(vts_test_core_copy_pairs) \
+ $(call copy-many-files,$(target_native_copy_pairs)) \
+ $(call copy-many-files,$(target_trace_copy_pairs)) \
+ $(call copy-many-files,$(target_hostdriven_copy_pairs)) \
$(call copy-many-files,$(host_kernel_config_copy_pairs)) \
$(call copy-many-files,$(host_camera_its_copy_pairs)) \
$(call copy-many-files,$(host_systrace_copy_pairs)) \
$(call copy-many-files,$(media_test_res_copy_pairs)) \
+ $(call copy-many-files,$(nbu_p2p_apk_copy_pairs)) \
$(call copy-many-files,$(performance_test_res_copy_pairs)) \
$(call copy-many-files,$(audio_test_res_copy_pairs)) \
$(call copy-many-files,$(kernel_rootdir_test_rc_copy_pairs)) \
- $(call copy-many-files,$(acts_framework_copy_pairs)) \
$(call copy-many-files,$(acts_testcases_copy_pairs)) \
+ $(call copy-many-files,$(target_script_copy_pairs)) \
+ $(call copy-many-files,$(system_property_compatibility_test_res_copy_pairs)) \
+ $(VTS_TESTCASES_OUT)/vts/testcases/vndk/golden/platform_vndk_version.txt \
+
+.PHONY: vts-test-core
+vts-test-core: $(vts_test_core_copy_pairs)
+
+$(compatibility_zip): $(vts_copy_pairs)
-include vendor/google_vts/tools/build/vts_package_vendor.mk
diff --git a/tools/vts-hc/run b/tools/vts-hc/run
deleted file mode 100755
index 121a7b8..0000000
--- a/tools/vts-hc/run
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/bash
-# Copyright (C) 2017 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.
-
-# launcher script for vts-hc (host controller)
-# can be used from an Android build environment, or a standalone vts zip
-
-# get OS
-HOST=`uname`
-if [ "$HOST" == "Linux" ]; then
- OS="linux-x86"
-elif [ "$HOST" == "Darwin" ]; then
- OS="darwin-x86"
-else
- echo "Unrecognized OS"
- exit
-fi
-
-# check if in Android build env
-if [ ! -z "${ANDROID_BUILD_TOP}" ]; then
- if [ ! -z "${ANDROID_HOST_OUT}" ]; then
- VTS_ROOT=${ANDROID_HOST_OUT}/vts
- else
- VTS_ROOT=${ANDROID_BUILD_TOP}/${OUT_DIR:-out}/host/${OS}/vts
- fi
- if [ ! -d ${VTS_ROOT} ]; then
- echo "Could not find $VTS_ROOT in Android build environment. Try 'make vts'"
- exit
- fi;
-fi;
-
-if [ -z ${VTS_ROOT} ]; then
- # assume we're in an extracted vts install
- VTS_ROOT="$(dirname $(readlink -e $0))/../.."
-fi;
-
-cd ${VTS_ROOT}/android-vts/testcases/; python -m vts.harnesses.host_controller.main "$@"
diff --git a/tools/vts-tradefed/CtsDynamicConfig.xml b/tools/vts-tradefed/DynamicConfig.xml
similarity index 100%
rename from tools/vts-tradefed/CtsDynamicConfig.xml
rename to tools/vts-tradefed/DynamicConfig.xml
diff --git a/tools/vts-tradefed/etc/Android.mk b/tools/vts-tradefed/etc/Android.mk
index aa3cc16..7eaef2a 100644
--- a/tools/vts-tradefed/etc/Android.mk
+++ b/tools/vts-tradefed/etc/Android.mk
@@ -31,3 +31,5 @@
LOCAL_MODULE_HOST_OS := windows
include $(BUILD_PREBUILT)
+.PHONY: vts-tradefed-standalone
+vts-tradefed-standalone: vts-tradefed vts-tradefed-tests hosttestlib compatibility-host-util tradefed
diff --git a/tools/vts-tradefed/etc/vts-tradefed b/tools/vts-tradefed/etc/vts-tradefed
index 346f813..abb5a6c 100755
--- a/tools/vts-tradefed/etc/vts-tradefed
+++ b/tools/vts-tradefed/etc/vts-tradefed
@@ -16,6 +16,16 @@
# launcher script for vts-tradefed harness
# can be used from an Android build environment, or a standalone vts zip
+#
+# Usage:
+# # to test a device with system.img = v9.0 and vendor.img = v9.0
+# $ vts-tradefed
+#
+# # to test a device with system.img = v9.0 and vendor.img = v8.1
+# $ vts-tradefed -v=8.1
+#
+# # all other cases are unsupported
+#
checkFile() {
if [ ! -f "$1" ]; then
@@ -78,16 +88,31 @@
VTS_ROOT="$(dirname $(readlink -e $0))/../.."
fi;
-JAR_DIR=${VTS_ROOT}/android-vts/tools
+VTS_JAR_DIR=${VTS_ROOT}/android-vts/tools
+STANDALONE_JAR_DIR=${ANDROID_HOST_OUT}/framework
+JAR_DIRS="$VTS_JAR_DIR
+ $STANDALONE_JAR_DIR"
+JAR_DIR=""
+# Wherever we find the tradefed jar is where we expect the other jars to be.
TRADEFED_JAR="tradefed"
-if [ ! -f ${JAR_DIR}/${TRADEFED_JAR}.jar ]; then
+for CHECK_JAR_DIR in $JAR_DIRS; do
+ if [ -f ${CHECK_JAR_DIR}/${TRADEFED_JAR}.jar ]; then
+ JAR_DIR=$CHECK_JAR_DIR
+ break
+ fi;
+done
+
+# If we didn't find the TF jar, resort to tf prebuilt in VTS_JAR_DIR.
+if [ -z $JAR_DIR ]; then
+ JAR_DIR=$VTS_JAR_DIR
TRADEFED_JAR="tradefed-prebuilt"
-fi;
+fi
JARS="${TRADEFED_JAR}
hosttestlib
vts-tradefed
+ vts-tradefed-tests
compatibility-host-util"
for JAR in $JARS; do
@@ -100,13 +125,17 @@
android-vts/tools/google-tradefed-vts-prebuilt
google-tradefed-prebuilt
google-tradefed-tests
- google-tf-prod-tests"
+ google-tf-prod-tests
+ google-tradefed"
for JAR in $OPTIONAL_JARS; do
- if [ -f "${VTS_ROOT}/${JAR}.jar" ]; then
- echo "Including optional JAR: $VTS_ROOT/$JAR.jar"
- JAR_PATH=${JAR_PATH}:${VTS_ROOT}/${JAR}.jar
- fi;
+ for OPT_JAR_DIR in $VTS_ROOT $JAR_DIR; do
+ if [ -f "${OPT_JAR_DIR}/${JAR}.jar" ]; then
+ echo "Including optional JAR: ${OPT_JAR_DIR}/${JAR}.jar"
+ JAR_PATH=${JAR_PATH}:${OPT_JAR_DIR}/${JAR}.jar
+ break
+ fi;
+ done
done
# load any shared libraries for host-side executables
@@ -124,4 +153,30 @@
JAR_PATH=${JAR_PATH}:$j
done
-cd ${VTS_ROOT}/android-vts/testcases/; java $RDBG_FLAG -cp ${JAR_PATH} -DVTS_ROOT=${VTS_ROOT} com.android.compatibility.common.tradefed.command.CompatibilityConsole "$@"
+ARGS=()
+for var in "$@"
+do
+case $var in
+ -v=*|--vendor-image=*)
+ VENDOR="${var#*=}"
+ if [ "${VENDOR}" == "9.0" ]; then
+ VENDOR=""
+ elif [ "${VENDOR}" != "8.1" ]; then
+ echo "Supports only --vendor-image=8.1."
+ echo "By default, 9.0 is the supported vendor.img version."
+ exit 1
+ fi
+ ;;
+ *)
+ ARGS+=("$var")
+ ;;
+esac
+done
+
+if [ -z "${VENDOR}" ]; then
+ VTS_TESTCASES=${VTS_ROOT}/android-vts/testcases/
+else
+ VTS_TESTCASES=${VTS_ROOT}/android-vts/${VENDOR}/testcases/
+fi
+
+cd ${VTS_TESTCASES}; VTS_TESTCASES=${VTS_TESTCASES} java $RDBG_FLAG -cp ${JAR_PATH} -DVTS_ROOT=${VTS_ROOT} com.android.compatibility.common.tradefed.command.CompatibilityConsole "${ARGS[@]}"
diff --git a/tools/vts-tradefed/etc/vts-tradefed_win.bat b/tools/vts-tradefed/etc/vts-tradefed_win.bat
index 10dca2e..e9055f4 100644
--- a/tools/vts-tradefed/etc/vts-tradefed_win.bat
+++ b/tools/vts-tradefed/etc/vts-tradefed_win.bat
@@ -70,6 +70,7 @@
set JARS=^
hosttestlib^
vts-tradefed^
+ vts-tradefed-tests^
compatibility-host-util
for %%J in (%JARS%) do (
set JAR=%JAR_DIR%\%%J.jar
diff --git a/tools/vts-tradefed/res/config/common-preparers.xml b/tools/vts-tradefed/res/config/common-preparers.xml
new file mode 100644
index 0000000..8030039
--- /dev/null
+++ b/tools/vts-tradefed/res/config/common-preparers.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Common preparer for both vts and cts-on-gsi">
+ <multi_target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer">
+ <option name="dep-module" value="enum" />
+ <option name="dep-module" value="future" />
+ <option name="dep-module" value="futures" />
+ <option name="dep-module" value="google-api-python-client" />
+ <option name="dep-module" value="httplib2" />
+ <option name="dep-module" value="oauth2client" />
+ <option name="dep-module" value="protobuf" />
+ <option name="dep-module" value="requests" />
+ </multi_target_preparer>
+</configuration>
diff --git a/tools/vts-tradefed/res/config/cts-base.xml b/tools/vts-tradefed/res/config/cts-base.xml
new file mode 100644
index 0000000..7ff79c5
--- /dev/null
+++ b/tools/vts-tradefed/res/config/cts-base.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Base test plan for running CTS test modules with VTS">
+
+ <option name="dynamic-sharding" value="false" />
+ <device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
+ <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider">
+ <option name="url-suite-name-override" value="CTS" />
+ </build_provider>
+ <test class="com.android.compatibility.common.tradefed.testtype.CompatibilityTestMultiDevice" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:rerun-from-file:true" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:fallback-to-serial-rerun:false" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.testtype.LibcoreTest:rerun-from-file:true" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.testtype.LibcoreTest:fallback-to-serial-rerun:false" />
+
+ <logger class="com.android.tradefed.log.FileLogger">
+ <option name="log-level-display" value="WARN" />
+ </logger>
+ <result_reporter class="com.android.compatibility.common.tradefed.result.ConsoleReporter" />
+ <result_reporter class="com.android.compatibility.common.tradefed.result.VtsResultReporter" />
+
+ <include name="cts-preconditions" />
+ <option name="dynamic-config-pusher:dynamic-resource-name" value="vts-tradefed" />
+ <include name="cts-system-checkers" />
+ <include name="cts-known-failures" />
+
+ <option name="test-tag" value="cts" />
+
+ <option name="enable-root" value="false" />
+ <!-- retain 200MB of host log -->
+ <option name="max-log-size" value="200" />
+ <!-- retain 200MB of logcat -->
+ <option name="max-tmp-logcat-file" value="209715200" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put global package_verifier_enable 0" />
+ <option name="teardown-command" value="settings put global package_verifier_enable 1"/>
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
+ <option name="property-name" value="ro.build.type" />
+ <option name="expected-value" value="user"/> <!-- Device should have user build -->
+ <option name="throw-error" value="false"/> <!-- Only print warning if not user build -->
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
+ <option name="property-name" value="ro.product.locale" />
+ <option name="expected-value" value="en-US"/> <!-- Device locale should be US English -->
+ <option name="throw-error" value="false"/> <!-- Only print warning if not en-US -->
+ </target_preparer>
+ <template-include name="reporters" default="basic-reporters" />
+
+ <!-- Include additional test metadata output. -->
+ <template-include name="metadata-reporters" default="empty" />
+ <target_preparer class="com.android.tradefed.targetprep.VtsDeviceInfoCollector">
+ <option name="disable-framework" value="false"/>
+ </target_preparer>
+
+ <option name="compatibility:primary-abi-only" value="true" />
+
+ <!-- Explicitly include CTS components listed in CtsConfigLoadingTest.java -->
+ <option name="compatibility:module-metadata-include-filter" key="component" value="abuse" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="art" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="auth" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="auto" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="backup" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="bionic" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="bluetooth" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="camera" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="deqp" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="devtools" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="framework" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="graphics" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="inputmethod" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="libcore" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="location" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="media" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="metrics" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="misc" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="networking" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="neuralnetworks" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="renderscript" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="security" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="statsd" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="systems" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="sysui" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="telecom" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="tv" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="uitoolkit" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="vr" />
+ <option name="compatibility:module-metadata-include-filter" key="component" value="webview" />
+
+ <!-- Exclude vts-hal-adapter tests -->
+ <option name="compatibility:module-metadata-exclude-filter" key="plan" value="vts-hal-adapter" />
+</configuration>
diff --git a/tools/vts-tradefed/res/config/cts-on-gsi.xml b/tools/vts-tradefed/res/config/cts-on-gsi.xml
index 30010c2..3c8309a 100644
--- a/tools/vts-tradefed/res/config/cts-on-gsi.xml
+++ b/tools/vts-tradefed/res/config/cts-on-gsi.xml
@@ -14,12 +14,8 @@
limitations under the License.
-->
<configuration description="Runs a subset of CTS tests using a general system image (GSI)">
-
- <include name="cts-common" />
-
- <option name="plan" value="cts-on-gsi" />
-
- <option name="compatibility:primary-abi-only" value="true" />
+ <include name="common-preparers" />
+ <include name="cts-base" />
<!-- Tell all AndroidJUnitTests to exclude certain annotations -->
<option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
@@ -43,9 +39,9 @@
<option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.NoReceiveSmsPermissionTest#testAppSpecificSmsToken" />
<option name="compatibility:exclude-filter" value="CtsPermission2TestCases android.permission2.cts.NoReceiveSmsPermissionTest#testReceiveTextMessage" />
<option name="compatibility:exclude-filter" value="CtsPermissionTestCases android.permission.cts.NoSystemFunctionPermissionTest#testSendSms" />
- <option name="compatibility:exclude-filter" value="CtsSecurityHostTest android.security.cts.SELinuxHostTest#testNoExemptionsForBinderInVendorBan" />
- <option name="compatibility:exclude-filter" value="CtsSecurityHostTest android.security.cts.SELinuxHostTest#testNoExemptionsForSocketsBetweenCoreAndVendorBan" />
- <option name="compatibility:exclude-filter" value="CtsSecurityHostTest android.security.cts.SELinuxHostTest#testNoExemptionsForVendorExecutingCore" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForBinderInVendorBan" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForSocketsBetweenCoreAndVendorBan" />
+ <option name="compatibility:exclude-filter" value="CtsSecurityHostTestCases android.security.cts.SELinuxHostTest#testNoExemptionsForVendorExecutingCore" />
<option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testAppDetails" />
<option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testAppSummary" />
<option name="compatibility:exclude-filter" value="CtsUsageStatsTestCases android.app.usage.cts.NetworkUsageStatsTest#testCallback" />
@@ -97,235 +93,6 @@
<option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.KeyAttestationTest#testEcAttestation" />
<option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.KeyAttestationTest#testRsaAttestation" />
- <!-- Explicitly include CTS test modules -->
- <option name="compatibility:include-filter" value="CtsAadbHostTestCases" />
- <option name="compatibility:include-filter" value="CtsAbiOverrideHostTestCases" />
- <option name="compatibility:include-filter" value="CtsAccelerationTestCases" />
- <option name="compatibility:include-filter" value="CtsAccessibilityServiceTestCases" />
- <option name="compatibility:include-filter" value="CtsAccessibilityTestCases" />
- <option name="compatibility:include-filter" value="CtsAccountManagerTestCases" />
- <option name="compatibility:include-filter" value="CtsAdminPackageInstallerTestCases" />
- <option name="compatibility:include-filter" value="CtsAdminTestCases" />
- <option name="compatibility:include-filter" value="CtsAlarmClockTestCases" />
- <option name="compatibility:include-filter" value="CtsAndroidAppTestCases" />
- <option name="compatibility:include-filter" value="CtsAnimationTestCases" />
- <option name="compatibility:include-filter" value="CtsAppSecurityHostTestCases" />
- <option name="compatibility:include-filter" value="CtsAppTestCases" />
- <option name="compatibility:include-filter" value="CtsAppUsageHostTestCases" />
- <option name="compatibility:include-filter" value="CtsAppWidgetTestCases" />
- <option name="compatibility:include-filter" value="CtsAslrMallocTestCases" />
- <option name="compatibility:include-filter" value="CtsAssistTestCases" />
- <option name="compatibility:include-filter" value="CtsAtraceHostTestCases" />
- <option name="compatibility:include-filter" value="CtsAutoFillServiceTestCases" />
- <option name="compatibility:include-filter" value="CtsBackgroundRestrictionsTestCases" />
- <option name="compatibility:include-filter" value="CtsBackupHostTestCases" />
- <option name="compatibility:include-filter" value="CtsBackupTestCases" />
- <option name="compatibility:include-filter" value="CtsBionicTestCases" />
- <option name="compatibility:include-filter" value="CtsBluetoothTestCases" />
- <option name="compatibility:include-filter" value="CtsBootStatsTestCases" />
- <option name="compatibility:include-filter" value="CtsCalendarcommon2TestCases" />
- <option name="compatibility:include-filter" value="CtsCameraApi25TestCases" />
- <option name="compatibility:include-filter" value="CtsCameraTestCases" />
- <option name="compatibility:include-filter" value="CtsCarTestCases" />
- <option name="compatibility:include-filter" value="CtsCarrierApiTestCases" />
- <option name="compatibility:include-filter" value="CtsColorModeTestCases" />
- <option name="compatibility:include-filter" value="CtsCompilationTestCases" />
- <option name="compatibility:include-filter" value="CtsContactsProviderWipe" />
- <option name="compatibility:include-filter" value="CtsContentTestCases" />
- <option name="compatibility:include-filter" value="CtsCppToolsTestCases" />
- <option name="compatibility:include-filter" value="CtsDatabaseTestCases" />
- <option name="compatibility:include-filter" value="CtsDebugTestCases" />
- <option name="compatibility:include-filter" value="CtsDeqpTestCases" />
- <option name="compatibility:include-filter" value="CtsDevicePolicyManagerTestCases" />
- <option name="compatibility:include-filter" value="CtsDisplayTestCases" />
- <option name="compatibility:include-filter" value="CtsDpiTestCases" />
- <option name="compatibility:include-filter" value="CtsDpiTestCases2" />
- <option name="compatibility:include-filter" value="CtsDramTestCases" />
- <option name="compatibility:include-filter" value="CtsDreamsTestCases" />
- <option name="compatibility:include-filter" value="CtsDrmTestCases" />
- <option name="compatibility:include-filter" value="CtsDumpsysHostTestCases" />
- <option name="compatibility:include-filter" value="CtsEdiHostTestCases" />
- <option name="compatibility:include-filter" value="CtsEffectTestCases" />
- <option name="compatibility:include-filter" value="CtsExternalServiceTestCases" />
- <option name="compatibility:include-filter" value="CtsExternalSourcesTestCases" />
- <option name="compatibility:include-filter" value="CtsFileSystemTestCases" />
- <option name="compatibility:include-filter" value="CtsFragmentTestCases" />
- <option name="compatibility:include-filter" value="CtsGestureTestCases" />
- <option name="compatibility:include-filter" value="CtsGraphicsTestCases" />
- <option name="compatibility:include-filter" value="CtsHardwareTestCases" />
- <option name="compatibility:include-filter" value="CtsHostTzDataTests" />
- <option name="compatibility:include-filter" value="CtsHostsideNetworkTests" />
- <option name="compatibility:include-filter" value="CtsHostsideNumberBlockingTestCases" />
- <option name="compatibility:include-filter" value="CtsHostsideTvTests" />
- <option name="compatibility:include-filter" value="CtsHostsideWebViewTests" />
- <option name="compatibility:include-filter" value="CtsIcuTestCases" />
- <option name="compatibility:include-filter" value="CtsIncidentHostTestCases" />
- <option name="compatibility:include-filter" value="CtsIncidentTestCases" />
- <option name="compatibility:include-filter" value="CtsInputMethodServiceHostTestCases" />
- <option name="compatibility:include-filter" value="CtsInputMethodTestCases" />
- <option name="compatibility:include-filter" value="CtsIntentSignatureTestCases" />
- <option name="compatibility:include-filter" value="CtsJankDeviceTestCases" />
- <option name="compatibility:include-filter" value="CtsJdwpSecurityHostTestCases" />
- <option name="compatibility:include-filter" value="CtsJdwpTestCases" />
- <option name="compatibility:include-filter" value="CtsJniTestCases" />
- <option name="compatibility:include-filter" value="CtsJobSchedulerTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiAttachingHostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRedefineClassesHostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest902HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest903HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest904HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest905HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest906HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest907HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest908HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest910HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest911HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest912HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest913HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest914HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest915HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest917HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest918HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest919HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest920HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest922HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest923HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest924HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest926HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest927HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest928HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest930HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest931HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest932HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest940HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest942HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest944HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest945HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest947HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest951HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest982HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest984HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest985HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiRunTest986HostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiTaggingHostTestCases" />
- <option name="compatibility:include-filter" value="CtsJvmtiTrackingHostTestCases" />
- <option name="compatibility:include-filter" value="CtsKernelConfigTestCases" />
- <option name="compatibility:include-filter" value="CtsKeystoreTestCases" />
- <option name="compatibility:include-filter" value="CtsLeanbackJankTestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreFileIOTestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreJavaUtilCollectionsTestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreJsr166TestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreLegacy22TestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreOjTestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreOkHttpTestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreTestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreWycheproofBCTestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreWycheproofConscryptTestCases" />
- <option name="compatibility:include-filter" value="CtsLiblogTestCases" />
- <option name="compatibility:include-filter" value="CtsLocation2TestCases" />
- <option name="compatibility:include-filter" value="CtsLocationTestCases" />
- <option name="compatibility:include-filter" value="CtsLogdTestCases" />
- <option name="compatibility:include-filter" value="CtsMediaBitstreamsTestCases" />
- <option name="compatibility:include-filter" value="CtsMediaHostTestCases" />
- <option name="compatibility:include-filter" value="CtsMediaStressTestCases" />
- <option name="compatibility:include-filter" value="CtsMediaTestCases" />
- <option name="compatibility:include-filter" value="CtsMidiTestCases" />
- <option name="compatibility:include-filter" value="CtsMonkeyTestCases" />
- <option name="compatibility:include-filter" value="CtsMultiUserHostTestCases" />
- <option name="compatibility:include-filter" value="CtsMultiUserTestCases" />
- <option name="compatibility:include-filter" value="CtsNativeHardwareTestCases" />
- <option name="compatibility:include-filter" value="CtsNativeMediaAAudioTestCases" />
- <option name="compatibility:include-filter" value="CtsNativeMediaSlTestCases" />
- <option name="compatibility:include-filter" value="CtsNativeMediaXaTestCases" />
- <option name="compatibility:include-filter" value="CtsNativeNetTestCases" />
- <option name="compatibility:include-filter" value="CtsNdefTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecConfigAttributeTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecConfigBasicDebugDisabledTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecConfigBasicDebugEnabledTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecConfigBasicDomainConfigTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecConfigCleartextTrafficTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecConfigDownloadManagerTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecConfigInvalidPinTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecConfigNestedDomainConfigTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecConfigResourcesSrcTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecPolicyUsesCleartextTrafficFalseTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecPolicyUsesCleartextTrafficTrueTestCases" />
- <option name="compatibility:include-filter" value="CtsNetSecPolicyUsesCleartextTrafficUnspecifiedTestCases" />
- <option name="compatibility:include-filter" value="CtsNetTestCases" />
- <option name="compatibility:include-filter" value="CtsNetTestCasesLegacyApi22" />
- <option name="compatibility:include-filter" value="CtsNetTestCasesLegacyPermission22" />
- <option name="compatibility:include-filter" value="CtsOpenGLTestCases" />
- <option name="compatibility:include-filter" value="CtsOpenGlPerf2TestCases" />
- <option name="compatibility:include-filter" value="CtsOpenGlPerfTestCases" />
- <option name="compatibility:include-filter" value="CtsOsHostTestCases" />
- <option name="compatibility:include-filter" value="CtsOsTestCases" />
- <option name="compatibility:include-filter" value="CtsPdfTestCases" />
- <option name="compatibility:include-filter" value="CtsPermission2TestCases" />
- <option name="compatibility:include-filter" value="CtsPermissionTestCases" />
- <option name="compatibility:include-filter" value="CtsPreference2TestCases" />
- <option name="compatibility:include-filter" value="CtsPreferenceTestCases" />
- <option name="compatibility:include-filter" value="CtsPrintTestCases" />
- <option name="compatibility:include-filter" value="CtsProtoTestCases" />
- <option name="compatibility:include-filter" value="CtsProviderTestCases" />
- <option name="compatibility:include-filter" value="CtsRenderscriptLegacyTestCases" />
- <option name="compatibility:include-filter" value="CtsRenderscriptTestCases" />
- <option name="compatibility:include-filter" value="CtsRsBlasTestCases" />
- <option name="compatibility:include-filter" value="CtsRsCppTestCases" />
- <option name="compatibility:include-filter" value="CtsSampleDeviceTestCases" />
- <option name="compatibility:include-filter" value="CtsSampleHostTestCases" />
- <option name="compatibility:include-filter" value="CtsSaxTestCases" />
- <option name="compatibility:include-filter" value="CtsSecurityHostTestCases" />
- <option name="compatibility:include-filter" value="CtsSecurityTestCases" />
- <option name="compatibility:include-filter" value="CtsSelinuxTargetSdk2TestCases" />
- <option name="compatibility:include-filter" value="CtsSelinuxTargetSdkTestCases" />
- <option name="compatibility:include-filter" value="CtsSensorTestCases" />
- <option name="compatibility:include-filter" value="CtsServicesHostTestCases" />
- <option name="compatibility:include-filter" value="CtsShortcutHostTestCases" />
- <option name="compatibility:include-filter" value="CtsShortcutManagerTestCases" />
- <option name="compatibility:include-filter" value="CtsSimpleCpuTestCases" />
- <option name="compatibility:include-filter" value="CtsSimpleperfTestCases" />
- <option name="compatibility:include-filter" value="CtsSpeechTestCases" />
- <option name="compatibility:include-filter" value="CtsSustainedPerformanceHostTestCases" />
- <option name="compatibility:include-filter" value="CtsSyncContentHostTestCases" />
- <option name="compatibility:include-filter" value="CtsSystemIntentTestCases" />
- <option name="compatibility:include-filter" value="CtsSystemUiHostTestCases" />
- <option name="compatibility:include-filter" value="CtsSystemUiTestCases" />
- <option name="compatibility:include-filter" value="CtsTelecomTestCases" />
- <option name="compatibility:include-filter" value="CtsTelecomTestCases2" />
- <option name="compatibility:include-filter" value="CtsTelecomTestCases3" />
- <option name="compatibility:include-filter" value="CtsTelephony2TestCases" />
- <option name="compatibility:include-filter" value="CtsTelephonyTestCases" />
- <option name="compatibility:include-filter" value="CtsTextTestCases" />
- <option name="compatibility:include-filter" value="CtsThemeDeviceTestCases" />
- <option name="compatibility:include-filter" value="CtsThemeHostTestCases" />
- <option name="compatibility:include-filter" value="CtsToastLegacyTestCases" />
- <option name="compatibility:include-filter" value="CtsToastTestCases" />
- <option name="compatibility:include-filter" value="CtsTransitionTestCases" />
- <option name="compatibility:include-filter" value="CtsTrustedVoiceHostTestCases" />
- <option name="compatibility:include-filter" value="CtsTvProviderTestCases" />
- <option name="compatibility:include-filter" value="CtsTvTestCases" />
- <option name="compatibility:include-filter" value="CtsUiAutomationTestCases" />
- <option name="compatibility:include-filter" value="CtsUiDeviceTestCases" />
- <option name="compatibility:include-filter" value="CtsUiHostTestCases" />
- <option name="compatibility:include-filter" value="CtsUiRenderingTestCases" />
- <option name="compatibility:include-filter" value="CtsUidIsolationTestCases" />
- <option name="compatibility:include-filter" value="CtsUsageStatsTestCases" />
- <option name="compatibility:include-filter" value="CtsUsbTests" />
- <option name="compatibility:include-filter" value="CtsUtilTestCases" />
- <option name="compatibility:include-filter" value="CtsVideoTestCases" />
- <option name="compatibility:include-filter" value="CtsViewTestCases" />
- <option name="compatibility:include-filter" value="CtsVmTestCases" />
- <option name="compatibility:include-filter" value="CtsVoiceInteractionTestCases" />
- <option name="compatibility:include-filter" value="CtsVoiceSettingsTestCases" />
- <option name="compatibility:include-filter" value="CtsVrTestCases" />
- <option name="compatibility:include-filter" value="CtsWebkitTestCases" />
- <option name="compatibility:include-filter" value="CtsWidgetTestCases" />
- <option name="compatibility:include-filter" value="CtsWindowManagerHostTestCases" />
- <option name="compatibility:include-filter" value="CtsWrapNoWrapTestCases" />
- <option name="compatibility:include-filter" value="CtsWrapWrapDebugMallocDebugTestCases" />
- <option name="compatibility:include-filter" value="CtsWrapWrapDebugTestCases" />
- <option name="compatibility:include-filter" value="CtsWrapWrapNoDebugTestCases" />
-
<!-- Exclude test cases for b/64488375
-->
@@ -359,4 +126,7 @@
<option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testRequestFocusNodeHref" />
<option name="compatibility:exclude-filter" value="CtsWebkitTestCases android.webkit.cts.WebViewTest#testRequestImageRef" />
+ <!-- b/65561379: Exclude android.media.cts.MediaPlayerFlakyNetworkTest -->
+ <option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.MediaPlayerFlakyNetworkTest" />
+
</configuration>
diff --git a/tools/vts-tradefed/res/config/cts-vendor-interface.xml b/tools/vts-tradefed/res/config/cts-vendor-interface.xml
index 73ec49b..049d6a1 100644
--- a/tools/vts-tradefed/res/config/cts-vendor-interface.xml
+++ b/tools/vts-tradefed/res/config/cts-vendor-interface.xml
@@ -16,6 +16,8 @@
<configuration description="Runs a subset of CTS tests that can heavily exercise HALs">
<include name="cts" />
+ <option name="compatibility-build-provider:url-suite-name-override" value="CTS" />
+ <option name="dynamic-config-pusher:dynamic-resource-name" value="vts-tradefed" />
<option name="plan" value="cts-vendor-interface" />
@@ -35,7 +37,6 @@
<option name="compatibility:include-filter" value="CtsHostsideNetworkTests" />
<option name="compatibility:include-filter" value="CtsIcuTestCases" />
<option name="compatibility:include-filter" value="CtsKeystoreTestCases" />
- <option name="compatibility:include-filter" value="CtsLibcoreJavaUtilCollectionsTestCases" />
<option name="compatibility:include-filter" value="CtsLibcoreOjTestCases" />
<option name="compatibility:include-filter" value="CtsLibcoreTestCases" />
<option name="compatibility:include-filter" value="CtsLocationTestCases" />
diff --git a/tools/vts-tradefed/res/config/plans.md b/tools/vts-tradefed/res/config/plans.md
index 85e16d2..197310e 100644
--- a/tools/vts-tradefed/res/config/plans.md
+++ b/tools/vts-tradefed/res/config/plans.md
@@ -11,6 +11,7 @@
and partners.
* __vts__: For all default VTS tests.
+ * __vts-firmware__: For all default VTS System Firmware tests.
* __vts-fuzz__: For all default VTS fuzz tests.
* __vts-hal__: For all default VTS HAL (hardware abstraction layer) module tests.
* __vts-hal-profiling__: For all default VTS HAL performance profiling tests.
diff --git a/tools/vts-tradefed/res/config/vts-automated.xml b/tools/vts-tradefed/res/config/vts-automated.xml
index bc62afd..6018959 100644
--- a/tools/vts-tradefed/res/config/vts-automated.xml
+++ b/tools/vts-tradefed/res/config/vts-automated.xml
@@ -43,6 +43,7 @@
<option name="compatibility:include-filter" value="VtsKernelNetdTest" />
<option name="compatibility:include-filter" value="VtsKernelSelinuxFileApi" />
<option name="compatibility:include-filter" value="VtsKernelTunTest" />
+ <option name="compatibility:include-filter" value="VtsKernelVersion" />
<option name="compatibility:include-filter" value="VtsQtaguidTest" />
<!-- From vts-vndk.xml -->
diff --git a/tools/vts-tradefed/res/config/vts-base-common.xml b/tools/vts-tradefed/res/config/vts-base-common.xml
new file mode 100644
index 0000000..5a9e22d
--- /dev/null
+++ b/tools/vts-tradefed/res/config/vts-base-common.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="VTS Main Test Plan">
+ <include name="common-preparers" />
+ <device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
+
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:rerun-from-file:true" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:fallback-to-serial-rerun:false" />
+ <logger class="com.android.tradefed.log.FileLogger">
+ <option name="log-level-display" value="INFO" />
+ </logger>
+ <option name="compatibility:skip-all-system-status-check" value="true" />
+ <option name="max-log-size" value="200" />
+ <object type="vts-vendor-config" class="com.android.tradefed.util.VtsVendorConfigFileUtil" />
+ <result_reporter class="com.android.compatibility.common.tradefed.result.ConsoleReporter" />
+ <result_reporter class="com.android.compatibility.common.tradefed.result.ResultReporter" />
+ <template-include name="reporters" default="basic-reporters" />
+ <multi_target_preparer class="com.android.tradefed.targetprep.VtsTestPlanResultReporter" />
+ <test class="com.android.compatibility.common.tradefed.testtype.CompatibilityTestMultiDevice" />
+</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-base.xml b/tools/vts-tradefed/res/config/vts-base.xml
index 506062f..27d66b0 100644
--- a/tools/vts-tradefed/res/config/vts-base.xml
+++ b/tools/vts-tradefed/res/config/vts-base.xml
@@ -14,22 +14,7 @@
limitations under the License.
-->
<configuration description="VTS Main Test Plan">
- <device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
-
- <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:rerun-from-file:true" />
- <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:fallback-to-serial-rerun:false" />
- <logger class="com.android.tradefed.log.FileLogger">
- <option name="log-level-display" value="WARN" />
- </logger>
- <option name="compatibility:skip-all-system-status-check" value="true" />
- <option name="max-log-size" value="200" />
- <object type="vts-vendor-config" class="com.android.tradefed.util.VtsVendorConfigFileUtil" />
- <result_reporter class="com.android.compatibility.common.tradefed.result.ConsoleReporter" />
- <result_reporter class="com.android.compatibility.common.tradefed.result.VtsResultReporter" />
-
- <template-include name="reporters" default="basic-reporters" />
- <target_preparer class="com.android.tradefed.targetprep.VtsTestPlanResultReporter" />
- <test class="com.android.compatibility.common.tradefed.testtype.CompatibilityTest" />
+ <include name="vts-base-common" />
<build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
<target_preparer class="com.android.tradefed.targetprep.VtsDeviceInfoCollector" />
diff --git a/tools/vts-tradefed/res/config/vts-codelab-multi-device.xml b/tools/vts-tradefed/res/config/vts-codelab-multi-device.xml
new file mode 100644
index 0000000..c43c939
--- /dev/null
+++ b/tools/vts-tradefed/res/config/vts-codelab-multi-device.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<configuration description="VTS Codelab Plan">
+ <include name="vts-base-common" />
+ <option name="plan" value="vts" />
+ <option name="test-tag" value="vts" />
+ <option name="vts-plan-result:plan-name" value="vts" />
+
+ <device name="device1">
+ <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
+ <target_preparer class="com.android.tradefed.targetprep.VtsDeviceInfoCollector" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ </target_preparer>
+ </device>
+
+ <device name="device2" >
+ <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
+ <target_preparer class="com.android.tradefed.targetprep.VtsDeviceInfoCollector" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ </target_preparer>
+ </device>
+
+ <option name="compatibility:include-filter" value="VtsCodelabHelloWorldMultiDeviceTest" />
+
+</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-codelab.xml b/tools/vts-tradefed/res/config/vts-codelab.xml
index a838a98..c683c5e 100644
--- a/tools/vts-tradefed/res/config/vts-codelab.xml
+++ b/tools/vts-tradefed/res/config/vts-codelab.xml
@@ -19,8 +19,6 @@
<option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-codelab" />
- <option name="compatibility:include-filter" value="VtsCodelabHelloWorldTest" />
- <option name="compatibility:include-filter" value="VtsCodelabHelloWorldStagingTest" />
- <option name="compatibility:include-filter" value="VtsCodelabTargetBinary" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-codelab" />
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-device-health.xml b/tools/vts-tradefed/res/config/vts-device-health.xml
new file mode 100644
index 0000000..cdabad9
--- /dev/null
+++ b/tools/vts-tradefed/res/config/vts-device-health.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="VTS Device Health Test Plan">
+ <include name="vts-base" />
+ <option name="plan" value="vts" />
+ <option name="test-tag" value="vts-star" />
+ <option name="vts-plan-result:plan-name" value="vts-device-health" />
+ <option name="compatibility:primary-abi-only" value="true" />
+
+ <option name="compatibility:include-filter" value="VtsDeviceHealth" />
+
+</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-firmware.xml b/tools/vts-tradefed/res/config/vts-firmware.xml
new file mode 100644
index 0000000..5afb79d
--- /dev/null
+++ b/tools/vts-tradefed/res/config/vts-firmware.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="VTS System Firmware Test Plan">
+ <include name="vts-base" />
+ <option name="plan" value="vts" />
+ <option name="test-tag" value="vts-star" />
+ <option name="vts-plan-result:plan-name" value="vts-firmware" />
+
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-firmware" />
+
+</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-fuzz.xml b/tools/vts-tradefed/res/config/vts-fuzz.xml
index ed62b85..4e3cfdf 100644
--- a/tools/vts-tradefed/res/config/vts-fuzz.xml
+++ b/tools/vts-tradefed/res/config/vts-fuzz.xml
@@ -20,22 +20,7 @@
<option name="vts-plan-result:plan-name" value="vts-fuzz" />
<option name="compatibility:primary-abi-only" value="true" />
- <option name="compatibility:include-filter" value="VtsHalAudioV2_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalAudioEffectV2_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalConfigstoreV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalDumpstateV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalGatekeeperV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalGraphicsAllocatorV2_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalLightV2_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalMemtrackV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalPowerV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalPowerV1_1IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalRadioDeprecatedV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalThermalV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalThermalV1_1IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_1IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalVrV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalWifiV1_0IfaceFuzzer" />
- <option name="compatibility:include-filter" value="VtsHalWifiV1_1IfaceFuzzer" />
+
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-fuzz" />
+
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-hal-auto.xml b/tools/vts-tradefed/res/config/vts-hal-auto.xml
index fb45101..7bc6dcc 100644
--- a/tools/vts-tradefed/res/config/vts-hal-auto.xml
+++ b/tools/vts-tradefed/res/config/vts-hal-auto.xml
@@ -14,14 +14,11 @@
limitations under the License.
-->
<configuration description="VTS Serving Plan for HALs - Auto">
- <include name="vts-base" />
- <option name="plan" value="vts" />
- <option name="test-tag" value="vts" />
- <option name="vts-plan-result:plan-name" value="vts-hal-auto" />
+ <include name="vts-base" />
+ <option name="plan" value="vts" />
+ <option name="test-tag" value="vts-star" />
+ <option name="vts-plan-result:plan-name" value="vts-hal-auto" />
- <option name="compatibility:include-filter" value="VtsHalBroadcastradioV1_1TargetTest" />
- <option name="compatibility:include-filter" value="VtsHalEvsV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalAutomotiveVehicleV2_0Host" />
- <option name="compatibility:include-filter" value="VtsHalAutomotiveVehicleV2_1Host" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-hal-auto" />
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-hal-profiling.xml b/tools/vts-tradefed/res/config/vts-hal-profiling.xml
index 3fdd261..6eed201 100644
--- a/tools/vts-tradefed/res/config/vts-hal-profiling.xml
+++ b/tools/vts-tradefed/res/config/vts-hal-profiling.xml
@@ -14,50 +14,10 @@
limitations under the License.
-->
<configuration description="VTS HAL Profiling Plan">
- <include name="vts-base" />
+ <include name="vts-hal" />
<option name="plan" value="vts" />
<option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-hal-profiling" />
-
- <option name="compatibility:include-filter" value="VtsHalAudioV2_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalAudioEffectV2_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalBiometricsFingerprintV2_1TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalBootV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalBroadcastradioV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalBluetoothV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalCameraProviderV2_4TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalConfigstoreV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalConfigstoreV1_1TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalContexthubV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalDrmV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalGatekeeperV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalGnssV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalGraphicsComposerV2_1TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalGraphicsMapperV2_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalHealthV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalIrV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalKeymasterV3_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalLightV2_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalMemtrackV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalNfcV1_0HostProfiling" />
- <option name="compatibility:include-filter" value="VtsHalNfcV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalOemLockV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalPowerV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalPowerV1_1TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalRadioV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalRenderscriptV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalSensorsV1_0HostProfiling" />
- <option name="compatibility:include-filter" value="VtsHalSensorsV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalSoundtriggerV2_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalThermalV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalUsbV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_0HostProfiling" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalVrV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalWeaverV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalWifiV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalWifiV1_1TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalWifiNanV1_0TargetProfiling" />
- <option name="compatibility:include-filter" value="VtsHalWifiSupplicantV1_0TargetProfiling" />
-
+ <target_preparer class="com.android.tradefed.targetprep.VtsTraceCollectPreparer" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.VtsMultiDeviceTest:enable-profiling:true" />
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-hal-replay.xml b/tools/vts-tradefed/res/config/vts-hal-replay.xml
index 8ebc252..d7045f6 100644
--- a/tools/vts-tradefed/res/config/vts-hal-replay.xml
+++ b/tools/vts-tradefed/res/config/vts-hal-replay.xml
@@ -17,7 +17,7 @@
<include name="vts-base" />
<target_preparer class="com.android.tradefed.targetprep.VtsSancovPreparer" />
<option name="plan" value="vts" />
- <option name="test-tag" value="vts" />
+ <option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-hal-replay" />
<!-- For Hidl Hal replay tests -->
diff --git a/tools/vts-tradefed/res/config/vts-hal-tv.xml b/tools/vts-tradefed/res/config/vts-hal-tv.xml
index 88c0e25..6ebd9d5 100644
--- a/tools/vts-tradefed/res/config/vts-hal-tv.xml
+++ b/tools/vts-tradefed/res/config/vts-hal-tv.xml
@@ -16,12 +16,11 @@
<configuration description="VTS Serving Plan for HALs - TV/x86">
<include name="vts-base" />
<option name="plan" value="vts" />
- <option name="test-tag" value="vts" />
+ <option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-hal-tv" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-hal-tv" />
+
<option name="compatibility:test-arg" value="com.android.tradefed.testtype.VtsMultiDeviceTest:gtest-batch-mode:true" />
- <option name="compatibility:include-filter" value="VtsHalTvCecV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalTvInputV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalTvInputV1_0Target" />
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-hal.xml b/tools/vts-tradefed/res/config/vts-hal.xml
index ddc0baf..5ee4d3b 100644
--- a/tools/vts-tradefed/res/config/vts-hal.xml
+++ b/tools/vts-tradefed/res/config/vts-hal.xml
@@ -17,64 +17,9 @@
<include name="vts-base" />
<target_preparer class="com.android.tradefed.targetprep.VtsCoveragePreparer" />
<option name="plan" value="vts" />
- <option name="test-tag" value="vts" />
+ <option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-hal" />
- <option name="compatibility:include-filter" value="VtsHalBluetoothV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalBootV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalDumpstateV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalIrV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalNfcV1_0HostBinderize" />
- <option name="compatibility:include-filter" value="VtsHalNfcV1_0HostPassthrough" />
- <option name="compatibility:include-filter" value="VtsHalNfcV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalRadioV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalRadioV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalRadioV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalRenderscriptV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalWifiV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalWifiV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalWifiNanV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalWifiOffloadV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalWifiSupplicantV1_0Target" />
-
- <!-- Internal Only -->
- <option name="compatibility:include-filter" value="VtsHalAudioV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalAudioEffectV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalBiometricsFingerprintV2_1Target" />
- <option name="compatibility:include-filter" value="VtsHalBroadcastradioV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalCameraProviderV2_4Target" />
- <option name="compatibility:include-filter" value="VtsHalCasV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalConfigstoreV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalContexthubV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalDrmV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalGatekeeperV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalGnssV1_0HostBinderize" />
- <option name="compatibility:include-filter" value="VtsHalGnssV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalGraphicsComposerV2_1Target" />
- <option name="compatibility:include-filter" value="VtsHalGraphicsMapperV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalHealthV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalKeymasterV3_0Target" />
- <option name="compatibility:include-filter" value="VtsHalLightV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalMemtrackV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalMediaOmxStoreV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalMediaOmxV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalOemLockV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalPowerV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalPowerV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalSensorsV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalSensorsV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalSoundtriggerV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalTetherOffloadConfigV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalTetherOffloadControlV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalThermalV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalThermalV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalUsbV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalUsbV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalVrV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalVrV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalWeaverV1_0Target" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-hal" />
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-host.xml b/tools/vts-tradefed/res/config/vts-host.xml
index 266b1ad..599d274 100644
--- a/tools/vts-tradefed/res/config/vts-host.xml
+++ b/tools/vts-tradefed/res/config/vts-host.xml
@@ -19,20 +19,7 @@
<option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-host" />
- <!-- For HIDL HALs -->
- <option name="compatibility:include-filter" value="VtsHalContexthubV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalGnssV1_0HostBinderize" />
- <option name="compatibility:include-filter" value="VtsHalMediaOmxV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalNfcV1_0HostBinderize" />
- <option name="compatibility:include-filter" value="VtsHalNfcV1_0HostPassthrough" />
- <option name="compatibility:include-filter" value="VtsHalRadioV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalSensorsV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalVrV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalWifiV1_0Host" />
-
- <!-- For shell-based tests -->
- <option name="compatibility:include-filter" value="SampleShellTest" />
- <option name="compatibility:include-filter" value="ShellBinaryCrashTest" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-hal-host" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-host" />
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-kernel.xml b/tools/vts-tradefed/res/config/vts-kernel.xml
index a6272a5..be5188e 100644
--- a/tools/vts-tradefed/res/config/vts-kernel.xml
+++ b/tools/vts-tradefed/res/config/vts-kernel.xml
@@ -16,22 +16,9 @@
<configuration description="VTS Kernel Test Plan">
<include name="vts-base" />
<option name="plan" value="vts" />
- <option name="test-tag" value="vts" />
+ <option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-kernel" />
- <option name="compatibility:include-filter" value="VtsKernelLtp" />
- <option name="compatibility:include-filter" value="KernelProcFileApiTest" />
- <option name="compatibility:include-filter" value="VtsKernelLinuxKselftest" />
- <option name="compatibility:include-filter" value="VtsKernelLinuxKselftestPresubmit" />
- <option name="compatibility:include-filter" value="SyscallExistenceTest" />
- <option name="compatibility:include-filter" value="VtsKernelApiSysfsTest" />
- <option name="compatibility:include-filter" value="VtsKernelBinderTest" />
- <option name="compatibility:include-filter" value="VtsKernelConfig" />
- <option name="compatibility:include-filter" value="VtsKernelHwBinder" />
- <option name="compatibility:include-filter" value="VtsKernelLibcutilsTest" />
- <option name="compatibility:include-filter" value="VtsKernelNetdTest" />
- <option name="compatibility:include-filter" value="VtsKernelSelinuxFileApi" />
- <option name="compatibility:include-filter" value="VtsKernelTunTest" />
- <option name="compatibility:include-filter" value="VtsQtaguidTest" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-kernel" />
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-p2p.xml b/tools/vts-tradefed/res/config/vts-p2p.xml
new file mode 100644
index 0000000..3ac978a
--- /dev/null
+++ b/tools/vts-tradefed/res/config/vts-p2p.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<configuration description="VTS Pair to Pair Test Plan">
+ <include name="vts-base-common" />
+ <option name="plan" value="vts" />
+ <option name="test-tag" value="vts-star" />
+ <option name="vts-plan-result:plan-name" value="vts-p2p" />
+ <option name="compatibility:primary-abi-only" value="true" />
+
+ <device name="device1">
+ <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
+ <target_preparer class="com.android.tradefed.targetprep.VtsDeviceInfoCollector" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ </target_preparer>
+ <!-- TODO(yuexima): The following preparer should be moved to module level when supported. -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="test-file-name" value="DATA/app/nbu/android_snippet.apk" />
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-r" />
+ <option name="install-arg" value="-g" />
+ </target_preparer>
+ </device>
+
+ <device name="device2" >
+ <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
+ <target_preparer class="com.android.tradefed.targetprep.VtsDeviceInfoCollector" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HostDrivenTest.push" />
+ </target_preparer>
+ <!-- TODO(yuexima): The following preparer should be moved to module level when supported. -->
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="test-file-name" value="DATA/app/nbu/android_snippet.apk" />
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-r" />
+ <option name="install-arg" value="-g" />
+ </target_preparer>
+ </device>
+
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-p2p" />
+
+</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-security.xml b/tools/vts-tradefed/res/config/vts-security.xml
index 2fa4bff..674248a 100644
--- a/tools/vts-tradefed/res/config/vts-security.xml
+++ b/tools/vts-tradefed/res/config/vts-security.xml
@@ -21,5 +21,7 @@
<!-- For Proof-of-Concept (PoC) Tests -->
<option name="compatibility:include-filter" value="SecurityPoCKernelTest" />
+ <!-- For system property Tests -->
+ <option name="compatibility:include-filter" value="VtsTrebleSysProp" />
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-selftest.xml b/tools/vts-tradefed/res/config/vts-selftest.xml
index de08e84..d6e3118 100644
--- a/tools/vts-tradefed/res/config/vts-selftest.xml
+++ b/tools/vts-tradefed/res/config/vts-selftest.xml
@@ -16,12 +16,15 @@
<configuration description="VTS Self Test Plan">
<include name="vts-base" />
<option name="plan" value="vts" />
- <option name="test-tag" value="vts" />
+ <option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-selftest" />
<option name="compatibility:primary-abi-only" value="true" />
<!-- VTS self test modules -->
<option name="compatibility:include-filter" value="VtsSelfTestBaseTest" />
+ <option name="compatibility:include-filter" value="VtsSelfTestPythonVirtualenvPreparerTestPart0" />
+ <option name="compatibility:include-filter" value="VtsSelfTestPythonVirtualenvPreparerTestPart1" />
+ <option name="compatibility:include-filter" value="VtsSelfTestPythonVirtualenvPreparerTestPart2" />
<option name="compatibility:test-arg" value="com.android.tradefed.testtype.VtsMultiDeviceTest:run-as-vts-self-test:true" />
@@ -51,7 +54,7 @@
<option name="compatibility:include-filter" value="VtsKernelNetdTest" />
<option name="compatibility:include-filter" value="VtsKernelSelinuxFileApi" />
<option name="compatibility:include-filter" value="VtsKernelTunTest" />
- <option name="compatibility:include-filter" value="VtsQtaguidTest" />
+ <option name="compatibility:include-filter" value="VtsKernelQtaguidTest" />
<!-- From vts-vndk.xml -->
<option name="compatibility:include-filter" value="VtsVndkDependency" />
diff --git a/tools/vts-tradefed/res/config/vts-staging-default.xml b/tools/vts-tradefed/res/config/vts-staging-default.xml
index 4ac5ad5..38cebb0 100644
--- a/tools/vts-tradefed/res/config/vts-staging-default.xml
+++ b/tools/vts-tradefed/res/config/vts-staging-default.xml
@@ -27,5 +27,4 @@
<!-- for VNDK -->
<option name="compatibility:include-filter" value="VtsVndkAbi" />
<option name="compatibility:include-filter" value="VtsVndkOpenLibraries" />
-
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-staging-kernel.xml b/tools/vts-tradefed/res/config/vts-staging-kernel.xml
index bd91235..f28d005 100644
--- a/tools/vts-tradefed/res/config/vts-staging-kernel.xml
+++ b/tools/vts-tradefed/res/config/vts-staging-kernel.xml
@@ -16,7 +16,7 @@
<configuration description="VTS Serving Plan for Kernel Staging Tests">
<include name="vts-base" />
<option name="plan" value="vts" />
- <option name="test-tag" value="vts" />
+ <option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-staging-kernel" />
<option name="compatibility:include-filter" value="SecurityPoCKernelTestStaging" />
diff --git a/tools/vts-tradefed/res/config/vts-staging-presubmit.xml b/tools/vts-tradefed/res/config/vts-staging-presubmit.xml
index 2bf7d41..0f048f9 100644
--- a/tools/vts-tradefed/res/config/vts-staging-presubmit.xml
+++ b/tools/vts-tradefed/res/config/vts-staging-presubmit.xml
@@ -19,6 +19,7 @@
<option name="plan" value="vts" />
<option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-staging-presubmit" />
+ <option name="vts-plan-result:default-type" value="staging" />
<!-- For vts-hal-hidl -->
<option name="compatibility:test-arg" value="com.android.tradefed.testtype.VtsMultiDeviceTest:gtest-batch-mode:true" />
diff --git a/tools/vts-tradefed/res/config/vts-staging-sancov.xml b/tools/vts-tradefed/res/config/vts-staging-sancov.xml
index d5f37e3..615e3e5 100644
--- a/tools/vts-tradefed/res/config/vts-staging-sancov.xml
+++ b/tools/vts-tradefed/res/config/vts-staging-sancov.xml
@@ -32,6 +32,7 @@
<option name="compatibility:include-filter" value="VtsHalRadioV1_0Target" />
<option name="compatibility:include-filter" value="VtsHalRadioV1_1Target" />
<option name="compatibility:include-filter" value="VtsHalRenderscriptV1_0Target" />
+ <option name="compatibility:include-filter" value="VtsHalSapV1_0Target" />
<option name="compatibility:include-filter" value="VtsHalWifiV1_0Host" />
<option name="compatibility:include-filter" value="VtsHalWifiV1_1Target" />
<option name="compatibility:include-filter" value="VtsHalWifiNanV1_0Target" />
diff --git a/tools/vts-tradefed/res/config/vts-staging-selftest.xml b/tools/vts-tradefed/res/config/vts-staging-selftest.xml
new file mode 100644
index 0000000..272ce93
--- /dev/null
+++ b/tools/vts-tradefed/res/config/vts-staging-selftest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 Google Inc.
+
+ 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.
+-->
+<configuration description="VTS Serving Plan for SelfTest (Staging)">
+ <include name="vts-base" />
+ <option name="compatibility:primary-abi-only" value="true" />
+ <option name="plan" value="vts" />
+ <option name="test-tag" value="vts-star" />
+
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-staging-selftest" />
+
+</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-staging-web.xml b/tools/vts-tradefed/res/config/vts-staging-web.xml
index 891f3d2..655cc3a 100644
--- a/tools/vts-tradefed/res/config/vts-staging-web.xml
+++ b/tools/vts-tradefed/res/config/vts-staging-web.xml
@@ -16,7 +16,7 @@
<configuration description="VTS Staging Plan for VTS Dashboard">
<include name="vts-base" />
<option name="plan" value="vts" />
- <option name="test-tag" value="vts" />
+ <option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-staging-web" />
<option name="vts-plan-result:default-type" value="staging" />
diff --git a/tools/vts-tradefed/res/config/vts-star.xml b/tools/vts-tradefed/res/config/vts-star.xml
new file mode 100644
index 0000000..a41b029
--- /dev/null
+++ b/tools/vts-tradefed/res/config/vts-star.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="VTS-* Main Test Plan Excluding VTS">
+ <include name="vts-base" />
+ <option name="plan" value="vts" />
+ <option name="test-tag" value="vts-star" />
+ <option name="vts-plan-result:plan-name" value="vts-star" />
+
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-app" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-codelab" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-device-health" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-fuzz" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-hal-adapter" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-hal-profiling" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-host" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-library" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-performance" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-selftest" />
+
+</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-unit-tests.xml b/tools/vts-tradefed/res/config/vts-unit-tests.xml
new file mode 100644
index 0000000..22c09d8
--- /dev/null
+++ b/tools/vts-tradefed/res/config/vts-unit-tests.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Executes the VTS unit tests">
+ <option name="null-device" value="true" />
+ <build_provider class="com.android.tradefed.build.StubBuildProvider" />
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="class" value="com.android.tradefed.VtsUnitTests" />
+ <option name="class" value="com.android.compatibility.common.tradefed.VtsUnitTests" />
+ </test>
+ <logger class="com.android.tradefed.log.FileLogger" />
+
+ <result_reporter class="com.android.tradefed.result.ConsoleResultReporter">
+ <option name="suppress-passed-tests" value="true" />
+ </result_reporter>
+ <template-include name="reporters" default="empty" />
+</configuration>
diff --git a/tools/vts-tradefed/res/config/vts-vndk.xml b/tools/vts-tradefed/res/config/vts-vndk.xml
index 57f2453..dc31f12 100644
--- a/tools/vts-tradefed/res/config/vts-vndk.xml
+++ b/tools/vts-tradefed/res/config/vts-vndk.xml
@@ -16,9 +16,9 @@
<configuration description="VTS VNDK (Vendor NDK) Test Plan">
<include name="vts-base" />
<option name="plan" value="vts" />
- <option name="test-tag" value="vts" />
+ <option name="test-tag" value="vts-star" />
<option name="vts-plan-result:plan-name" value="vts-vndk" />
- <option name="compatibility:include-filter" value="VtsVndkDependency" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-vndk" />
</configuration>
diff --git a/tools/vts-tradefed/res/config/vts.xml b/tools/vts-tradefed/res/config/vts.xml
index c98f434..0da9002 100644
--- a/tools/vts-tradefed/res/config/vts.xml
+++ b/tools/vts-tradefed/res/config/vts.xml
@@ -19,92 +19,16 @@
<option name="test-tag" value="vts" />
<option name="vts-plan-result:plan-name" value="vts" />
- <!-- For Treble-specific validations -->
- <option name="compatibility:include-filter" value="VtsTreblePlatformVersionTest" />
- <option name="compatibility:include-filter" value="VtsTrebleVintfTest" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-firmware" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-hal" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-hal-replay" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-kernel" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-security" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-treble" />
+ <option name="compatibility:module-metadata-include-filter" key="plan" value="vts-vndk" />
- <!-- From vts-hal-hidl.xml -->
- <option name="compatibility:include-filter" value="VtsHalBluetoothV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalBootV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalDumpstateV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalIrV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalNfcV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalRadioV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalRadioV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalRenderscriptV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalWifiV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalWifiV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalWifiNanV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalWifiOffloadV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalWifiSupplicantV1_0Target" />
-
- <!-- From vts-hal-hidl.xml: Internal Only -->
- <option name="compatibility:include-filter" value="VtsHalAudioV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalAudioEffectV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalBiometricsFingerprintV2_1Target" />
- <option name="compatibility:include-filter" value="VtsHalBroadcastradioV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalCameraProviderV2_4Target" />
- <option name="compatibility:include-filter" value="VtsHalCasV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalConfigstoreV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalContexthubV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalDrmV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalGatekeeperV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalGnssV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalGraphicsComposerV2_1Target" />
- <option name="compatibility:include-filter" value="VtsHalGraphicsMapperV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalHealthV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalKeymasterV3_0Target" />
- <option name="compatibility:include-filter" value="VtsHalLightV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalMemtrackV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalMediaOmxStoreV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalMediaOmxV1_0Host" />
- <option name="compatibility:include-filter" value="VtsHalOemLockV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalPowerV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalPowerV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalSensorsV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalSoundtriggerV2_0Target" />
- <option name="compatibility:include-filter" value="VtsHalTetherOffloadConfigV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalTetherOffloadControlV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalThermalV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalThermalV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalUsbV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalUsbV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_1Target" />
- <option name="compatibility:include-filter" value="VtsHalVrV1_0Target" />
- <option name="compatibility:include-filter" value="VtsHalWeaverV1_0Target" />
-
- <!-- From vts-kernel.xml -->
- <option name="compatibility:include-filter" value="VtsKernelLtp" />
- <option name="compatibility:include-filter" value="KernelProcFileApiTest" />
- <option name="compatibility:include-filter" value="VtsKernelLinuxKselftest" />
- <option name="compatibility:include-filter" value="VtsKernelLinuxKselftestPresubmit" />
- <option name="compatibility:include-filter" value="SyscallExistenceTest" />
- <option name="compatibility:include-filter" value="VtsKernelApiSysfsTest" />
- <option name="compatibility:include-filter" value="VtsKernelBinderTest" />
- <option name="compatibility:include-filter" value="VtsKernelConfig" />
- <option name="compatibility:include-filter" value="VtsKernelHwBinder" />
- <option name="compatibility:include-filter" value="VtsKernelLibcutilsTest" />
- <option name="compatibility:include-filter" value="VtsKernelNetdTest" />
- <option name="compatibility:include-filter" value="VtsKernelSelinuxFileApi" />
- <option name="compatibility:include-filter" value="VtsKernelTunTest" />
- <option name="compatibility:include-filter" value="VtsQtaguidTest" />
-
- <!-- From vts-vndk.xml -->
- <option name="compatibility:include-filter" value="VtsVndkDependency" />
-
- <!-- For Hidl Hal replay tests -->
- <option name="compatibility:include-filter" value="VtsHalNfcV1_0TargetReplay" />
-
- <!-- For Hidl Hal replay tests: Internal Only -->
- <option name="compatibility:include-filter" value="VtsHalBiometricsFingerprintV2_1TargetReplay" />
- <option name="compatibility:include-filter" value="VtsHalContexthubV1_0TargetReplay" />
- <option name="compatibility:include-filter" value="VtsHalKeymasterV3_0TargetReplay" />
- <option name="compatibility:include-filter" value="VtsHalLightV2_0TargetReplay" />
- <option name="compatibility:include-filter" value="VtsHalMemtrackV1_0TargetReplay" />
- <option name="compatibility:include-filter" value="VtsHalPowerV1_0TargetReplay" />
- <option name="compatibility:include-filter" value="VtsHalUsbV1_0TargetReplay" />
- <option name="compatibility:include-filter" value="VtsHalVibratorV1_0TargetReplay" />
- <option name="compatibility:include-filter" value="VtsHalVrV1_0TargetReplay" />
+ <!-- Unapproved vts-security Tests -->
+ <option name="compatibility:exclude-filter" value="SecurityPoCKernelTest" />
+ <option name="compatibility:exclude-filter" value="VtsSecuritySelinuxPolicyHost" />
</configuration>
diff --git a/tools/vts-tradefed/res/default/DefaultTestCase.config b/tools/vts-tradefed/res/default/DefaultTestCase.runner_conf
similarity index 100%
rename from tools/vts-tradefed/res/default/DefaultTestCase.config
rename to tools/vts-tradefed/res/default/DefaultTestCase.runner_conf
diff --git a/utils/Android.bp b/utils/Android.bp
index 3971d00..71743eb 100644
--- a/utils/Android.bp
+++ b/utils/Android.bp
@@ -14,4 +14,5 @@
subdirs = [
"native",
-]
\ No newline at end of file
+ "python",
+]
diff --git a/utils/native/libprofiling/Android.bp b/utils/native/libprofiling/Android.bp
index 070c645..3928457 100644
--- a/utils/native/libprofiling/Android.bp
+++ b/utils/native/libprofiling/Android.bp
@@ -53,6 +53,15 @@
"-Wall",
],
+ multilib: {
+ lib32: {
+ ldflags: ["-Wl,--rpath,/data/local/tmp/32"],
+ },
+ lib64: {
+ ldflags: ["-Wl,--rpath,/data/local/tmp/64"],
+ },
+ },
+
export_include_dirs: ["."],
}
diff --git a/utils/native/libprofiling/VtsProfilingConfigureMain.cpp b/utils/native/libprofiling/VtsProfilingConfigureMain.cpp
index 8694b11..67cd7cc 100644
--- a/utils/native/libprofiling/VtsProfilingConfigureMain.cpp
+++ b/utils/native/libprofiling/VtsProfilingConfigureMain.cpp
@@ -85,36 +85,34 @@
return true;
}
-// Usage examples:
-// To enable, <binary> enable <lib path>
-// To disable, <binary> disable clear
-int main(int argc, char *argv[]) {
- bool enable_profiling = false;
- if (argc >= 2) {
- if (!strcmp(argv[1], "enable")) {
- enable_profiling = true;
- }
- if (argc == 3 && strlen(argv[2]) > 0) {
- if (!strcmp(argv[2], "clear")) {
- property_set("hal.instrumentation.lib.path", "");
- printf("* setprop hal.instrumentation.lib.path \"\"\n");
- } else {
- property_set("hal.instrumentation.lib.path", argv[2]);
- printf("* setprop hal.instrumentation.lib.path %s\n", argv[2]);
- }
- }
- }
+void PrintUsage() {
+ printf(
+ "Usage: \n"
+ "To enable profiling: <binary> enable <lib path 32> <lib path 64>"
+ "To disable profiling <binary> disable");
+}
- if (enable_profiling) {
+int main(int argc, char *argv[]) {
+ if (argc == 2 && !strcmp(argv[1], "disable")) {
+ printf("* disable profiling.\n");
+ property_set("hal.instrumentation.lib.path.32", "");
+ property_set("hal.instrumentation.lib.path.64", "");
+ if (!DisableHALProfiling()) {
+ printf("failed to disable profiling.\n");
+ return -1;
+ }
+ } else if (argc >= 2 && !strcmp(argv[1], "enable")) {
printf("* enable profiling.\n");
+ if (argc == 4) {
+ property_set("hal.instrumentation.lib.path.32", argv[2]);
+ property_set("hal.instrumentation.lib.path.64", argv[3]);
+ }
if (!EnableHALProfiling()) {
- fprintf(stderr, "failed to enable profiling.\n");
+ printf("failed to enable profiling.\n");
+ return -1;
}
} else {
- printf("* disable profiling.\n");
- if (!DisableHALProfiling()) {
- fprintf(stderr, "failed to disable profiling.\n");
- }
+ PrintUsage();
}
return 0;
}
diff --git a/utils/native/testability_checker/Android.bp b/utils/native/testability_checker/Android.bp
index ed24285..e37e9e8 100644
--- a/utils/native/testability_checker/Android.bp
+++ b/utils/native/testability_checker/Android.bp
@@ -19,13 +19,17 @@
shared_libs: [
"libbase",
"libcutils",
+ "libhidlbase",
+ "libhidltransport",
"liblog",
"libselinux",
"libtinyxml2",
+ "libutils",
"libz",
],
static_libs: [
"libvintf",
+ "libhidl-gen-utils",
],
cflags: [
"-Wall",
@@ -37,14 +41,12 @@
name: "libvts_testability_checker",
defaults : ["VtsTestabilityCheckerDefaults"],
srcs: ["VtsTestabilityChecker.cpp"],
- host_supported: true,
}
cc_test {
name: "libvts_testability_checker_test",
defaults : ["VtsTestabilityCheckerDefaults"],
srcs: ["VtsTestabilityCheckerTest.cpp"],
- host_supported: true,
static_libs: [
"libgmock",
diff --git a/utils/native/testability_checker/VtsTestabilityChecker.cpp b/utils/native/testability_checker/VtsTestabilityChecker.cpp
index 19da321..206ed3d 100644
--- a/utils/native/testability_checker/VtsTestabilityChecker.cpp
+++ b/utils/native/testability_checker/VtsTestabilityChecker.cpp
@@ -21,16 +21,25 @@
#include <iostream>
#include <set>
+#include <android-base/strings.h>
+#include <vintf/parse_string.h>
+
+using android::base::Join;
using android::vintf::Arch;
using android::vintf::CompatibilityMatrix;
using android::vintf::gArchStrings;
using android::vintf::HalManifest;
using android::vintf::ManifestHal;
+using android::vintf::ManifestInstance;
using android::vintf::MatrixHal;
+using android::vintf::MatrixInstance;
+using android::vintf::toFQNameString;
using android::vintf::Transport;
using android::vintf::Version;
+using android::vintf::operator<<;
using std::set;
using std::string;
+using std::vector;
namespace android {
namespace vts {
@@ -45,13 +54,13 @@
bool check_framework_hal = CheckFrameworkManifestHal(
hal_package_name, hal_version, hal_interface_name, arch,
&famework_hal_instances);
- bool check_vendor_hal_compliance = CheckFrameworkCompatibleHal(
- hal_package_name, hal_version, hal_interface_name, arch,
- &vendor_hal_instances);
+ bool check_vendor_hal =
+ CheckVendorManifestHal(hal_package_name, hal_version, hal_interface_name,
+ arch, &vendor_hal_instances);
set_union(famework_hal_instances.begin(), famework_hal_instances.end(),
vendor_hal_instances.begin(), vendor_hal_instances.end(),
std::inserter(*instances, instances->begin()));
- return check_framework_hal || check_vendor_hal_compliance;
+ return check_framework_hal || check_vendor_hal;
}
bool VtsTestabilityChecker::CheckHalForNonComplianceTest(
@@ -59,8 +68,43 @@
const string& hal_interface_name, const Arch& arch,
set<string>* instances) {
CHECK(instances) << "instances set should not be NULL.";
- return CheckVendorManifestHal(hal_package_name, hal_version,
- hal_interface_name, arch, instances);
+ set<string> vendor_hal_instances;
+ set<string> test_hal_instances;
+ bool check_vendor_hal =
+ CheckVendorManifestHal(hal_package_name, hal_version, hal_interface_name,
+ arch, &vendor_hal_instances);
+
+ bool check_test_hal = CheckTestHalWithHwManager(
+ hal_package_name, hal_version, hal_interface_name, &test_hal_instances);
+
+ set_union(vendor_hal_instances.begin(), vendor_hal_instances.end(),
+ test_hal_instances.begin(), test_hal_instances.end(),
+ std::inserter(*instances, instances->begin()));
+ return check_vendor_hal || check_test_hal;
+}
+
+vector<const ManifestInstance*> VtsTestabilityChecker::FindInstance(
+ const vector<ManifestInstance>& manifest_instances,
+ const MatrixInstance& matrix_instance) {
+ vector<const ManifestInstance*> ret;
+ for (const auto& e : manifest_instances) {
+ if (matrix_instance.matchInstance(e.instance())) {
+ ret.push_back(&e);
+ }
+ }
+ return ret;
+}
+
+vector<const ManifestInstance*> VtsTestabilityChecker::FindInterface(
+ const vector<ManifestInstance>& manifest_instances,
+ const MatrixInstance& matrix_instance) {
+ vector<const ManifestInstance*> ret;
+ for (const auto& e : manifest_instances) {
+ if (e.interface() == matrix_instance.interface()) {
+ ret.push_back(&e);
+ }
+ }
+ return ret;
}
bool VtsTestabilityChecker::CheckFrameworkCompatibleHal(
@@ -68,107 +112,99 @@
const string& hal_interface_name, const Arch& arch,
set<string>* instances) {
CHECK(instances) << "instances set should not be NULL.";
- const MatrixHal* matrix_hal =
- framework_comp_matrix_->getHal(hal_package_name, hal_version);
- if (!matrix_hal) {
- LOG(DEBUG) << "Does not find hal " << hal_package_name
- << " in compatibility matrix";
- return false;
- }
+ auto matrix_instances = framework_comp_matrix_->getFqInstances(
+ hal_package_name, hal_version, hal_interface_name);
+ auto manifest_instances = device_hal_manifest_->getFqInstances(
+ hal_package_name, hal_version, hal_interface_name);
- if (!hal_interface_name.empty() &&
- !matrix_hal->hasInterface(hal_interface_name)) {
- LOG(DEBUG) << "MaxtrixHal " << hal_package_name
- << " does not support interface " << hal_interface_name;
- return false;
- }
+ bool testable = false;
- const ManifestHal* manifest_hal =
- device_hal_manifest_->getHal(hal_package_name, hal_version);
-
- if (!manifest_hal || (!hal_interface_name.empty() &&
- !manifest_hal->hasInterface(hal_interface_name))) {
- if (!matrix_hal->optional) {
+ for (const auto& matrix_instance : matrix_instances) {
+ const auto& matched_instances =
+ FindInstance(manifest_instances, matrix_instance);
+ if (!matrix_instance.optional() && matched_instances.empty()) {
+ // In matrix but not in manifest.
+ // The test should still run, but expect the test
+ // to fail (due to incompatible vendor and framework HAL).
LOG(ERROR) << "Compatibility error. Hal " << hal_package_name
<< " is required by framework but not supported by vendor";
- // Return true here to indicate the test should run, but expect the test
- // to fail (due to incompatible vendor and framework HAL).
- GetTestInstances(matrix_hal, nullptr /*ManifestHal*/, hal_interface_name,
- instances);
- return true;
+ if (!hal_interface_name.empty()) {
+ if (!matrix_instance.isRegex()) {
+ instances->insert(matrix_instance.exactInstance());
+ } else {
+ LOG(ERROR) << "Ignore regex-instance '"
+ << matrix_instance.regexPattern();
+ }
+ }
+ testable |= true;
+ continue;
}
- return false;
- }
- if (manifest_hal->transport() == Transport::PASSTHROUGH &&
- !CheckPassthroughManifestHal(manifest_hal, arch)) {
- LOG(DEBUG) << "ManfestHal " << hal_package_name
- << " is passthrough and does not support arch "
- << gArchStrings.at(static_cast<int>(arch));
- return false;
- }
+ if (hal_interface_name.empty()) {
+ testable |= !matched_instances.empty();
+ continue;
+ }
- GetTestInstances(matrix_hal, manifest_hal, hal_interface_name, instances);
- return true;
+ auto get_testable_instances =
+ [&](const vector<const vintf::ManifestInstance*>& manifest_instances) {
+ vector<string> ret;
+ for (const auto& manifest_instance : manifest_instances) {
+ if ((manifest_instance->transport() == Transport::PASSTHROUGH &&
+ CheckPassthroughManifestArch(manifest_instance->arch(),
+ arch)) ||
+ manifest_instance->transport() == Transport::HWBINDER) {
+ ret.push_back(manifest_instance->instance());
+ }
+ }
+ return ret;
+ };
+
+ auto testable_instances = get_testable_instances(matched_instances);
+ if (!testable_instances.empty()) {
+ instances->insert(testable_instances.begin(), testable_instances.end());
+ testable |= true;
+ continue;
+ }
+
+ // Special case: if a.h.foo@1.0::IFoo/default is in matrix but /custom
+ // is in manifest, the interface is still testable, but /default should
+ // not be added to instances.
+ const auto& matched_interface_instances =
+ FindInterface(manifest_instances, matrix_instance);
+ auto testable_interfaces =
+ get_testable_instances(matched_interface_instances);
+ if (!testable_interfaces.empty()) {
+ testable |= true;
+ continue;
+ }
+ }
+ if (instances->empty()) {
+ LOG(ERROR) << "Hal "
+ << toFQNameString(hal_package_name, hal_version,
+ hal_interface_name)
+ << " has no testable instance";
+ }
+ return testable;
}
-void VtsTestabilityChecker::GetTestInstances(const MatrixHal* matrix_hal,
- const ManifestHal* manifest_hal,
- const string& interface_name,
- set<string>* instances) {
- CHECK(matrix_hal || manifest_hal)
- << "MatrixHal and ManifestHal should not both be NULL.";
- CHECK(instances) << "instances set should not be NULL.";
- if (interface_name.empty()) {
- LOG(INFO) << "No interface name provided, return empty instances set.";
- return;
- }
-
- set<string> manifest_hal_instances;
- if (!manifest_hal || (matrix_hal && !matrix_hal->optional)) {
- // Only matrix_hal is provided or matrix_hal is required, get instances
- // from matrix_hal.
- set<string> matrix_hal_instances = matrix_hal->getInstances(interface_name);
- instances->insert(matrix_hal_instances.begin(), matrix_hal_instances.end());
- } else if (!matrix_hal) {
- // Only manifest_hal is provided, get instances from manifest_hal.
- set<string> manifest_hal_instances =
- manifest_hal->getInstances(interface_name);
- instances->insert(manifest_hal_instances.begin(),
- manifest_hal_instances.end());
- } else {
- // Both matrix_hal and manifest_hal not null && matrix_hal is optional,
- // get intersection of instances from both matrix_hal and manifest_hal.
- set<string> matrix_hal_instances = matrix_hal->getInstances(interface_name);
- set<string> manifest_hal_instances =
- manifest_hal->getInstances(interface_name);
- set_intersection(matrix_hal_instances.begin(), matrix_hal_instances.end(),
- manifest_hal_instances.begin(),
- manifest_hal_instances.end(),
- std::inserter(*instances, instances->begin()));
- }
-}
-
-bool VtsTestabilityChecker::CheckPassthroughManifestHal(
- const ManifestHal* manifest_hal, const Arch& arch) {
- CHECK(manifest_hal) << "ManifestHal should not be NULL.";
+bool VtsTestabilityChecker::CheckPassthroughManifestArch(
+ const Arch& manifest_arch, const Arch& arch) {
switch (arch) {
case Arch::ARCH_32: {
- if (android::vintf::has32(manifest_hal->transportArch.arch)) {
+ if (android::vintf::has32(manifest_arch)) {
return true;
}
break;
}
case Arch::ARCH_64: {
- if (android::vintf::has64(manifest_hal->transportArch.arch)) {
+ if (android::vintf::has64(manifest_arch)) {
return true;
}
break;
}
default: {
- LOG(ERROR) << "Unexpected arch to check: "
- << gArchStrings.at(static_cast<int>(arch));
+ LOG(ERROR) << "Unexpected arch to check: " << arch;
break;
}
}
@@ -179,49 +215,85 @@
const string& hal_package_name, const Version& hal_version,
const string& hal_interface_name, const Arch& arch,
set<string>* instances) {
- CHECK(instances) << "instances set should not be NULL.";
- return CheckManifestHal(
- framework_hal_manifest_->getHal(hal_package_name, hal_version),
- hal_interface_name, arch, instances);
+ return CheckManifestHal(framework_hal_manifest_, hal_package_name,
+ hal_version, hal_interface_name, arch, instances);
}
bool VtsTestabilityChecker::CheckVendorManifestHal(
const string& hal_package_name, const Version& hal_version,
const string& hal_interface_name, const Arch& arch,
set<string>* instances) {
- CHECK(instances) << "instances set should not be NULL.";
- return CheckManifestHal(
- device_hal_manifest_->getHal(hal_package_name, hal_version),
- hal_interface_name, arch, instances);
+ return CheckManifestHal(device_hal_manifest_, hal_package_name, hal_version,
+ hal_interface_name, arch, instances);
}
-bool VtsTestabilityChecker::CheckManifestHal(const ManifestHal* manifest_hal,
+bool VtsTestabilityChecker::CheckManifestHal(const HalManifest* hal_manifest,
+ const string& hal_package_name,
+ const Version& hal_version,
const string& hal_interface_name,
const Arch& arch,
set<string>* instances) {
CHECK(instances) << "instances set should not be NULL.";
- if (!manifest_hal) {
- LOG(DEBUG) << "Does not find hal " << manifest_hal->name
+
+ const auto& manifest_instances = hal_manifest->getFqInstances(
+ hal_package_name, hal_version, hal_interface_name);
+
+ const auto& fq_instance_name =
+ toFQNameString(hal_package_name, hal_version, hal_interface_name);
+
+ if (manifest_instances.empty()) {
+ LOG(DEBUG) << "Does not find instances for " << fq_instance_name
<< " in manifest file";
return false;
}
- if (!hal_interface_name.empty() &&
- !manifest_hal->hasInterface(hal_interface_name)) {
- LOG(DEBUG) << "ManifestHal " << manifest_hal->name
- << " does not support interface " << hal_interface_name;
- return false;
- }
- if (manifest_hal->transport() == Transport::PASSTHROUGH &&
- !CheckPassthroughManifestHal(manifest_hal, arch)) {
- LOG(DEBUG) << "ManfestHal " << manifest_hal->name
- << " is passthrough and does not support arch "
- << gArchStrings.at(static_cast<int>(arch));
+ bool testable = false;
+ for (const auto& manifest_instance : manifest_instances) {
+ if (manifest_instance.transport() == Transport::PASSTHROUGH &&
+ !CheckPassthroughManifestArch(manifest_instance.arch(), arch)) {
+ LOG(DEBUG) << "Manifest HAL " << fq_instance_name
+ << " is passthrough and does not support arch " << arch;
+ continue; // skip this instance
+ }
+ if (!hal_interface_name.empty()) {
+ instances->insert(manifest_instance.instance());
+ }
+ testable = true;
+ }
+ return testable;
+}
+
+bool VtsTestabilityChecker::CheckTestHalWithHwManager(
+ const string& hal_package_name, const Version& hal_version,
+ const string& hal_interface_name, set<string>* instances) {
+ CHECK(instances) << "instances set should not be NULL.";
+
+ string fqName =
+ toFQNameString(hal_package_name, hal_version, hal_interface_name);
+ bool registered = false;
+ hardware::Return<void> res;
+ if (!hal_interface_name.empty()) {
+ res = sm_->listByInterface(fqName, [&](const auto& registered_instances) {
+ for (const string& instance : registered_instances) {
+ registered = true;
+ instances->insert(instance);
+ }
+ });
+ } else { // handle legacy data without interface info.
+ res = sm_->list([&](const auto& services) {
+ for (const string& service : services) {
+ if (service.find(fqName) == 0) {
+ registered = true;
+ break;
+ }
+ }
+ });
+ }
+ if (!res.isOk()) {
+ LOG(ERROR) << "failed to check services: " << res.description();
return false;
}
- GetTestInstances(nullptr /*matrix_hal*/, manifest_hal, hal_interface_name,
- instances);
- return true;
+ return registered;
}
} // namespace vts
diff --git a/utils/native/testability_checker/VtsTestabilityChecker.h b/utils/native/testability_checker/VtsTestabilityChecker.h
index a3ff174..a7ebb83 100644
--- a/utils/native/testability_checker/VtsTestabilityChecker.h
+++ b/utils/native/testability_checker/VtsTestabilityChecker.h
@@ -20,9 +20,11 @@
#include <set>
#include <android-base/logging.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
#include <vintf/CompatibilityMatrix.h>
#include <vintf/HalManifest.h>
+using android::hidl::manager::V1_0::IServiceManager;
using android::vintf::Arch;
using android::vintf::CompatibilityMatrix;
using android::vintf::HalManifest;
@@ -31,6 +33,7 @@
using android::vintf::Version;
using std::set;
using std::string;
+using std::vector;
namespace android {
namespace vts {
@@ -42,10 +45,12 @@
public:
VtsTestabilityChecker(const CompatibilityMatrix* framework_comp_matrix,
const HalManifest* framework_hal_manifest,
- const HalManifest* device_hal_manifest)
+ const HalManifest* device_hal_manifest,
+ sp<IServiceManager> sm)
: framework_comp_matrix_(framework_comp_matrix),
framework_hal_manifest_(framework_hal_manifest),
- device_hal_manifest_(device_hal_manifest) {
+ device_hal_manifest_(device_hal_manifest),
+ sm_(sm) {
CHECK(framework_comp_matrix_) << "framework_comp_matrix null.";
CHECK(framework_hal_manifest_) << "framework_hal_manifest null.";
CHECK(device_hal_manifest_) << "device_hal_manifest null.";
@@ -72,7 +77,6 @@
const Version& hal_version,
const string& hal_interface_name,
const Arch& arch, set<string>* instances);
-
private:
// Internal method to check the given hal against the framework compatibility
// matrix and device manifest.
@@ -102,31 +106,50 @@
const string& hal_interface_name,
const Arch& arch, set<string>* instances);
- // Helper method to check whether the mantifest_hal support the interface
- // and arch (for passthrough hal). Store the corresponding
- // instance names if supported.
- bool CheckManifestHal(const ManifestHal* manifest_hal,
+ // Internal method to check whether the given hal is registered with
+ // hwservicemanager. Store the corresponding instance names if registered.
+ // This is used to check test hals that is not listed in manifest files.
+ // Note this could not check for passthrough hals.
+ bool CheckTestHalWithHwManager(const string& hal_package_name,
+ const Version& hal_version,
+ const string& hal_interface_name,
+ set<string>* instances);
+
+ // Helper method to check whether the hal_manifest support the
+ // package@version::interface and arch (for passthrough hal). Store the
+ // corresponding instance names if supported.
+ bool CheckManifestHal(const HalManifest* hal_manifest,
+ const string& hal_package_name,
+ const Version& hal_version,
const string& hal_interface_name, const Arch& arch,
set<string>* instances);
- // Helper method to get the instance name for a given hal.
- // If both matrix_hal and manifest_hal not null (i.e. the given hal exists
- // in both compatibilty matrix and manifest), find the instance names in both
- // hal and return the intersection.
- // If either matrix_hal or manifest_hal not null, return the corresponding
- // instance names
- void GetTestInstances(const MatrixHal* matrix_hal,
- const ManifestHal* manifest_hal,
- const string& interface_name, set<string>* instances);
-
// Helper method to check whether a passthrough hal support the given arch
// (32 or 64).
- bool CheckPassthroughManifestHal(const ManifestHal* manifest_hal,
- const Arch& arch);
+ bool CheckPassthroughManifestArch(const Arch& manifest_arch,
+ const Arch& arch);
+
+ // Helper method to find matching instances from a list of
+ // manifest_instances.
+ vector<const vintf::ManifestInstance*> FindInstance(
+ const vector<vintf::ManifestInstance>& manifest_instances,
+ const vintf::MatrixInstance& matrix_instance);
+
+ // Helper method to find matching interfaces from a list of
+ // manifest_instances.
+ vector<const vintf::ManifestInstance*> FindInterface(
+ const vector<vintf::ManifestInstance>& manifest_instances,
+ const vintf::MatrixInstance& matrix_instance);
const CompatibilityMatrix* framework_comp_matrix_; // Do not own.
const HalManifest* framework_hal_manifest_; // Do not own.
const HalManifest* device_hal_manifest_; // Do not own.
+ sp<IServiceManager> sm_;
+
+ friend class
+ VtsTestabilityCheckerTest_CheckFrameworkCompatibleHalOptional_Test;
+ friend class
+ VtsTestabilityCheckerTest_CheckFrameworkCompatibleHalRequired_Test;
};
} // namespace vts
diff --git a/utils/native/testability_checker/VtsTestabilityCheckerMain.cpp b/utils/native/testability_checker/VtsTestabilityCheckerMain.cpp
index b3e31d2..3bf0d15 100644
--- a/utils/native/testability_checker/VtsTestabilityCheckerMain.cpp
+++ b/utils/native/testability_checker/VtsTestabilityCheckerMain.cpp
@@ -18,10 +18,12 @@
#include <iostream>
#include <hidl-util/FQName.h>
+#include <hidl/ServiceManagement.h>
#include <vintf/VintfObject.h>
#include "VtsTestabilityChecker.h"
+using android::hidl::manager::V1_0::IServiceManager;
using android::vintf::VintfObject;
using std::cerr;
using std::cout;
@@ -82,8 +84,8 @@
return -1;
}
- android::FQName hal_fq_name = android::FQName(argv[optind]);
- if (!hal_fq_name.isValid()) {
+ android::FQName hal_fq_name;
+ if (!android::FQName::parse(argv[optind], &hal_fq_name)) {
cerr << "Invalid hal name: " << argv[optind] << endl;
return -1;
}
@@ -119,9 +121,16 @@
return -1;
}
+ android::sp<IServiceManager> sm =
+ ::android::hardware::defaultServiceManager();
+ if (sm == nullptr) {
+ cerr << "failed to get IServiceManager" << endl;
+ return -1;
+ }
+
android::vts::VtsTestabilityChecker checker(framework_comp_matrix.get(),
framework_hal_manifest.get(),
- device_hal_manifest.get());
+ device_hal_manifest.get(), sm);
set<string> instances;
bool result = false;
if (is_compliance_test) {
diff --git a/utils/native/testability_checker/VtsTestabilityCheckerTest.cpp b/utils/native/testability_checker/VtsTestabilityCheckerTest.cpp
index 2ce1a00..38822bc 100644
--- a/utils/native/testability_checker/VtsTestabilityCheckerTest.cpp
+++ b/utils/native/testability_checker/VtsTestabilityCheckerTest.cpp
@@ -22,6 +22,16 @@
#include <vintf/HalManifest.h>
#include <vintf/parse_xml.h>
+using namespace testing;
+
+using android::hidl::base::V1_0::IBase;
+using android::hidl::manager::V1_0::IServiceManager;
+using android::hidl::manager::V1_0::IServiceNotification;
+using android::hardware::hidl_array;
+using android::hardware::hidl_death_recipient;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
using android::vintf::Arch;
using android::vintf::CompatibilityMatrix;
using android::vintf::HalManifest;
@@ -34,20 +44,51 @@
using std::set;
using std::string;
-extern const XmlConverter<HalManifest> &android::vintf::gHalManifestConverter;
-extern const XmlConverter<CompatibilityMatrix>
- &android::vintf::gCompatibilityMatrixConverter;
-
namespace android {
namespace vts {
+class MockServiceManager : public IServiceManager {
+ public:
+ template <typename T>
+ using R = ::android::hardware::Return<T>;
+ using String = const hidl_string &;
+ ~MockServiceManager() = default;
+
+#define MOCK_METHOD_CB(name) \
+ MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
+
+ MOCK_METHOD2(get, R<sp<IBase>>(String, String));
+ MOCK_METHOD2(add, R<bool>(String, const sp<IBase> &));
+ MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
+ MOCK_METHOD_CB(list);
+ MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
+ MOCK_METHOD3(registerForNotifications,
+ R<bool>(String, String, const sp<IServiceNotification> &));
+ MOCK_METHOD_CB(debugDump);
+ MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
+ MOCK_METHOD_CB(interfaceChain);
+ MOCK_METHOD2(debug,
+ R<void>(const hidl_handle &, const hidl_vec<hidl_string> &));
+ MOCK_METHOD_CB(interfaceDescriptor);
+ MOCK_METHOD_CB(getHashChain);
+ MOCK_METHOD0(setHalInstrumentation, R<void>());
+ MOCK_METHOD2(linkToDeath,
+ R<bool>(const sp<hidl_death_recipient> &, uint64_t));
+ MOCK_METHOD0(ping, R<void>());
+ MOCK_METHOD_CB(getDebugInfo);
+ MOCK_METHOD0(notifySyspropsChanged, R<void>());
+ MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient> &));
+};
+
class VtsTestabilityCheckerTest : public ::testing::Test {
public:
virtual void SetUp() override {
test_cm_ = testFrameworkCompMatrix();
test_fm_ = testFrameworkManfiest();
test_vm_ = testDeviceManifest();
- checker_.reset(new VtsTestabilityChecker(&test_cm_, &test_fm_, &test_vm_));
+ sm_ = new NiceMock<MockServiceManager>();
+ checker_.reset(
+ new VtsTestabilityChecker(&test_cm_, &test_fm_, &test_vm_, sm_));
}
virtual void TearDown() override {}
@@ -223,161 +264,180 @@
CompatibilityMatrix test_cm_;
HalManifest test_fm_;
HalManifest test_vm_;
+ sp<MockServiceManager> sm_;
std::unique_ptr<VtsTestabilityChecker> checker_;
};
-TEST_F(VtsTestabilityCheckerTest, CheckComplianceTestForOptionalHal) {
+TEST_F(VtsTestabilityCheckerTest, CheckComplianceTest) {
set<string> instances;
// Check non-existent hal.
EXPECT_FALSE(checker_->CheckHalForComplianceTest(
- "non-existent", {1, 0}, "None", Arch::ARCH_EMPTY, &instances));
+ "nonexistent", {1, 0}, "None", Arch::ARCH_32, &instances));
EXPECT_TRUE(instances.empty());
-
- // Check hal not required by framework
+ // Check hal with unsupported version by vendor.
EXPECT_FALSE(checker_->CheckHalForComplianceTest(
- "android.hardware.renderscript", {1, 0}, "IRenderscript",
- Arch::ARCH_EMPTY, &instances));
+ "android.hardware.nfc", {2, 0}, "INfc", Arch::ARCH_32, &instances));
EXPECT_TRUE(instances.empty());
-
- // Check hal with unsupported version.
+ // Check hal with unsupported interface by vendor.
EXPECT_FALSE(checker_->CheckHalForComplianceTest(
- "android.hardware.camera", {1, 0}, "ICamera", Arch::ARCH_EMPTY,
- &instances));
+ "android.hardware.nfc", {1, 0}, "INfcTest", Arch::ARCH_32, &instances));
EXPECT_TRUE(instances.empty());
-
- // Check hal with non-existent interface.
+ // Check hal with unsupported arch by vendor.
EXPECT_FALSE(checker_->CheckHalForComplianceTest(
- "android.hardware.camera", {1, 2}, "None", Arch::ARCH_EMPTY, &instances));
+ "android.hardware.audio", {1, 0}, "IAudio", Arch::ARCH_64, &instances));
EXPECT_TRUE(instances.empty());
-
- // Check an optional hal not supported by vendor.
+ // Check hal claimed by framework but not supported by vendor (error case).
EXPECT_FALSE(checker_->CheckHalForComplianceTest(
- "android.hardware.radio", {1, 0}, "IRadio", Arch::ARCH_EMPTY,
- &instances));
- EXPECT_TRUE(instances.empty());
-
- // Check an optional hal with version not supported by vendor.
- EXPECT_FALSE(checker_->CheckHalForComplianceTest(
- "android.hardware.camera", {4, 5}, "ICamera", Arch::ARCH_EMPTY,
- &instances));
- EXPECT_TRUE(instances.empty());
-
- // Check an optional hal with interface not supported by vendor.
- EXPECT_FALSE(checker_->CheckHalForComplianceTest(
- "android.hardware.nfc", {4, 5}, "INfcTest", Arch::ARCH_EMPTY,
- &instances));
- EXPECT_TRUE(instances.empty());
-
- // Check an option passthrough hal with unsupported arch.
- EXPECT_FALSE(checker_->CheckHalForComplianceTest(
- "android.hardware.audio", {2, 0}, "IAudio", Arch::ARCH_64, &instances));
- EXPECT_TRUE(instances.empty());
-
- // Check an optional hal supported by vendor but with no compatible
- // instance.
- EXPECT_TRUE(checker_->CheckHalForComplianceTest(
- "android.hardware.camera", {2, 2}, "ICamera", Arch::ARCH_EMPTY,
- &instances));
- EXPECT_TRUE(instances.empty());
-
- // Check an optional hal supported by vendor.
- instances.clear();
- EXPECT_TRUE(checker_->CheckHalForComplianceTest(
- "android.hardware.camera", {2, 2}, "IBetterCamera", Arch::ARCH_EMPTY,
- &instances));
- EXPECT_THAT(instances, ::testing::ContainerEq(set<string>({"camera"})));
-
- // Check an optional hal supported by vendor and framework.
- instances.clear();
- EXPECT_TRUE(checker_->CheckHalForComplianceTest(
- "android.hardware.nfc", {1, 0}, "INfc", Arch::ARCH_EMPTY, &instances));
- EXPECT_THAT(instances,
- ::testing::ContainerEq(set<string>({"default", "fnfc"})));
-
- // Check an optional passthrough hal supported by vendor.
- instances.clear();
- EXPECT_TRUE(checker_->CheckHalForComplianceTest(
- "android.hardware.audio", {2, 0}, "IAudio", Arch::ARCH_32, &instances));
- EXPECT_THAT(instances, ::testing::ContainerEq(set<string>({"default"})));
-
- // Check an optional hal with empty interface (legacy input).
- instances.clear();
- EXPECT_TRUE(checker_->CheckHalForComplianceTest(
- "android.hardware.camera", {2, 2}, "" /*interface*/, Arch::ARCH_EMPTY,
- &instances));
- EXPECT_TRUE(instances.empty());
-}
-
-TEST_F(VtsTestabilityCheckerTest, CheckComplianceTestForRequiredHal) {
- set<string> instances;
- // Check a required hal not supported by vendor.
- EXPECT_TRUE(checker_->CheckHalForComplianceTest(
"android.hardware.light", {2, 0}, "ILight", Arch::ARCH_32, &instances));
- EXPECT_THAT(instances, ::testing::ContainerEq(set<string>({"default"})));
+ EXPECT_TRUE(instances.empty());
+ // Check hal interface claimed by framework but not supported by vendor (error
+ // case).
+ EXPECT_FALSE(checker_->CheckHalForComplianceTest(
+ "android.hardware.drm", {1, 0}, "IDrmTest", Arch::ARCH_32, &instances));
+ EXPECT_TRUE(instances.empty());
- // Check a required hal with version not supported by vendor.
+ // Check hal claimed by framework and supported by vendor.
instances.clear();
EXPECT_TRUE(checker_->CheckHalForComplianceTest("android.hardware.vibrator",
- {2, 0}, "IVibrator",
+ {1, 0}, "IVibrator",
Arch::ARCH_32, &instances));
- EXPECT_THAT(instances, ::testing::ContainerEq(set<string>({"default"})));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
- // Check a required hal with interface not supported by vendor.
+ // Check hal not claimed by framework but supported by vendor.
instances.clear();
EXPECT_TRUE(checker_->CheckHalForComplianceTest(
- "android.hardware.drm", {1, 0}, "IDrmTest", Arch::ARCH_32, &instances));
- EXPECT_THAT(instances, ::testing::ContainerEq(set<string>({"default"})));
+ "android.hardware.renderscript", {1, 0}, "IRenderscript", Arch::ARCH_32,
+ &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
- // Check a required hal supported by vendor.
+ // Check hal with version not claimed by framework by supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForComplianceTest("android.hardware.vibrator",
+ {1, 0}, "IVibrator",
+ Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
+
+ // Check hal with instance not claimed by framework but supported by vendor.
instances.clear();
EXPECT_TRUE(checker_->CheckHalForComplianceTest(
- "android.hardware.drm", {1, 0}, "IDrm", Arch::ARCH_32, &instances));
- EXPECT_THAT(instances,
- ::testing::ContainerEq(set<string>({"default", "drm"})));
+ "android.hardware.camera", {2, 2}, "ICamera", Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"legacy/0"})));
+
+ // Check hal with additional vendor instance not claimed by framework.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForComplianceTest("android.hardware.camera",
+ {1, 2}, "IBetterCamera",
+ Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default", "camera"})));
+
+ // Check hal supported by both framework and vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForComplianceTest(
+ "android.hardware.nfc", {1, 0}, "INfc", Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default", "fnfc"})));
+
+ // Check hal instance claimed by framework but not supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForComplianceTest(
+ "android.hardware.drm", {2, 0}, "IDrm", Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
// Check an optional hal with empty interface (legacy input).
instances.clear();
EXPECT_TRUE(checker_->CheckHalForComplianceTest(
- "android.hardware.vibrator", {2, 0}, "" /*interface*/, Arch::ARCH_EMPTY,
+ "android.hardware.vibrator", {1, 0}, "" /*interface*/, Arch::ARCH_EMPTY,
&instances));
EXPECT_TRUE(instances.empty());
}
TEST_F(VtsTestabilityCheckerTest, CheckNonComplianceTest) {
set<string> instances;
+ ON_CALL(*sm_, listByInterface(_, _))
+ .WillByDefault(
+ Invoke([](hidl_string str, IServiceManager::listByInterface_cb cb) {
+ if (str == "android.hardware.foo@1.0::IFoo") {
+ cb({"default", "footest"});
+ } else if (str == "android.hardware.nfc@3.0::INfc") {
+ cb({"default"});
+ } else if (str == "android.hardware.drm@2.0::IDrm") {
+ cb({"drmtest"});
+ }
+ return hardware::Void();
+ }));
+
+ ON_CALL(*sm_, list(_)).WillByDefault(Invoke([](IServiceManager::list_cb cb) {
+ cb({"android.hardware.foo@1.0::IFoo/default",
+ "android.hardware.foo@1.0::IFoo/footest",
+ "android.hardware.nfc@3.0::INfc/default",
+ "android.hardware.drm@2.0::IDrm/drmtest"});
+ return hardware::Void();
+ }));
+
// Check non-existent hal.
EXPECT_FALSE(checker_->CheckHalForNonComplianceTest(
"non-existent", {1, 0}, "None", Arch::ARCH_32, &instances));
EXPECT_TRUE(instances.empty());
- // Check hal with unsupported version by vendor
+ // Check hal with unsupported version by vendor.
EXPECT_FALSE(checker_->CheckHalForNonComplianceTest(
"android.hardware.nfc", {2, 0}, "INfc", Arch::ARCH_32, &instances));
EXPECT_TRUE(instances.empty());
- // Check hal with unsupported interface by vendor
+ // Check hal with unsupported interface by vendor.
EXPECT_FALSE(checker_->CheckHalForNonComplianceTest(
"android.hardware.nfc", {1, 0}, "INfcTest", Arch::ARCH_32, &instances));
EXPECT_TRUE(instances.empty());
+ // Check hal with unsupported arch by vendor.
+ EXPECT_FALSE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.audio", {1, 0}, "IAudio", Arch::ARCH_64, &instances));
+ EXPECT_TRUE(instances.empty());
+ // Check hal claimed by framework but not supported by vendor (error case).
+ EXPECT_FALSE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.light", {2, 0}, "ILight", Arch::ARCH_32, &instances));
+ EXPECT_TRUE(instances.empty());
+ // Check hal interface claimed by framework but not supported by vendor (error
+ // case).
+ EXPECT_FALSE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.drm", {1, 0}, "IDrmTest", Arch::ARCH_32, &instances));
+ EXPECT_TRUE(instances.empty());
- // Check hal only supported by vendor
- EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
- "android.hardware.renderscript", {1, 0}, "IRenderscript", Arch::ARCH_32,
- &instances));
- EXPECT_THAT(instances, ::testing::ContainerEq(set<string>({"default"})));
-
- // Check a required hal with version only supported by vendor.
+ // Check hal claimed by framework and supported by vendor.
instances.clear();
EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
"android.hardware.vibrator", {1, 0}, "IVibrator", Arch::ARCH_32,
&instances));
- EXPECT_THAT(instances, ::testing::ContainerEq(set<string>({"default"})));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
- // Check hal with additional vendor instance
+ // Check hal not claimed by framework but supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.renderscript", {1, 0}, "IRenderscript", Arch::ARCH_32,
+ &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
+
+ // Check hal with version not claimed by framework by supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.vibrator", {1, 0}, "IVibrator", Arch::ARCH_32,
+ &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
+
+ // Check hal with instance not claimed by framework but supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.camera", {2, 2}, "ICamera", Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"legacy/0"})));
+
+ // Check hal with additional vendor instance not claimed by framework.
instances.clear();
EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
"android.hardware.camera", {1, 2}, "IBetterCamera", Arch::ARCH_32,
&instances));
- EXPECT_THAT(instances,
- ::testing::ContainerEq(set<string>({"default", "camera"})));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default", "camera"})));
+
+ // Check hal supported by both framework and vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.nfc", {1, 0}, "INfc", Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
// Check an optional hal with empty interface (legacy input).
instances.clear();
@@ -385,6 +445,138 @@
"android.hardware.vibrator", {1, 0}, "" /*interface*/, Arch::ARCH_EMPTY,
&instances));
EXPECT_TRUE(instances.empty());
+
+ // Check hal only registered with hwmanger.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.foo", {1, 0}, "IFoo", Arch::ARCH_EMPTY, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default", "footest"})));
+
+ // Check hal with version only registered with hwmanger.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.nfc", {3, 0}, "INfc", Arch::ARCH_EMPTY, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
+
+ // Check hal with additional instance registered with hwmanger.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.drm", {2, 0}, "IDrm", Arch::ARCH_EMPTY, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default", "drmtest"})));
+
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckHalForNonComplianceTest(
+ "android.hardware.foo", {1, 0}, "", Arch::ARCH_EMPTY, &instances));
+ EXPECT_TRUE(instances.empty());
+}
+
+TEST_F(VtsTestabilityCheckerTest, CheckFrameworkCompatibleHalOptional) {
+ set<string> instances;
+ // Check non-existent hal.
+ EXPECT_FALSE(checker_->CheckFrameworkCompatibleHal(
+ "nonexistent", {1, 0}, "None", Arch::ARCH_EMPTY, &instances));
+ EXPECT_TRUE(instances.empty());
+
+ // Check hal not required by framework
+ EXPECT_FALSE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.renderscript", {1, 0}, "IRenderscript",
+ Arch::ARCH_EMPTY, &instances));
+ EXPECT_TRUE(instances.empty());
+
+ // Check hal with unsupported version.
+ EXPECT_FALSE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.camera", {1, 0}, "ICamera", Arch::ARCH_EMPTY,
+ &instances));
+ EXPECT_TRUE(instances.empty());
+
+ // Check hal with non-existent interface.
+ EXPECT_FALSE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.camera", {1, 2}, "None", Arch::ARCH_EMPTY, &instances));
+ EXPECT_TRUE(instances.empty());
+
+ // Check an optional hal not supported by vendor.
+ EXPECT_FALSE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.radio", {1, 0}, "IRadio", Arch::ARCH_EMPTY,
+ &instances));
+ EXPECT_TRUE(instances.empty());
+
+ // Check an optional hal with version not supported by vendor.
+ EXPECT_FALSE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.camera", {4, 5}, "ICamera", Arch::ARCH_EMPTY,
+ &instances));
+ EXPECT_TRUE(instances.empty());
+
+ // Check an optional hal with interface not supported by vendor.
+ EXPECT_FALSE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.nfc", {4, 5}, "INfcTest", Arch::ARCH_EMPTY,
+ &instances));
+ EXPECT_TRUE(instances.empty());
+
+ // Check an option passthrough hal with unsupported arch.
+ EXPECT_FALSE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.audio", {2, 0}, "IAudio", Arch::ARCH_64, &instances));
+ EXPECT_TRUE(instances.empty());
+
+ // Check an optional hal supported by vendor but with no compatible
+ // instance.
+ EXPECT_TRUE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.camera", {2, 2}, "ICamera", Arch::ARCH_EMPTY,
+ &instances));
+ EXPECT_TRUE(instances.empty());
+
+ // Check an optional hal supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.camera", {2, 2}, "IBetterCamera", Arch::ARCH_EMPTY,
+ &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"camera"})));
+
+ // Check an optional passthrough hal supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.audio", {2, 0}, "IAudio", Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
+
+ // Check an optional hal with empty interface (legacy input).
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.camera", {2, 2}, "" /*interface*/, Arch::ARCH_EMPTY,
+ &instances));
+ EXPECT_TRUE(instances.empty());
+}
+
+TEST_F(VtsTestabilityCheckerTest, CheckFrameworkCompatibleHalRequired) {
+ set<string> instances;
+ // Check a required hal not supported by vendor.
+ EXPECT_TRUE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.light", {2, 0}, "ILight", Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
+
+ // Check a required hal with version not supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckFrameworkCompatibleHal("android.hardware.vibrator",
+ {2, 0}, "IVibrator",
+ Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
+
+ // Check a required hal with interface not supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.drm", {1, 0}, "IDrmTest", Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default"})));
+
+ // Check a required hal supported by vendor.
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.drm", {1, 0}, "IDrm", Arch::ARCH_32, &instances));
+ EXPECT_THAT(instances, ContainerEq(set<string>({"default", "drm"})));
+
+ // Check an optional hal with empty interface (legacy input).
+ instances.clear();
+ EXPECT_TRUE(checker_->CheckFrameworkCompatibleHal(
+ "android.hardware.vibrator", {2, 0}, "" /*interface*/, Arch::ARCH_EMPTY,
+ &instances));
+ EXPECT_TRUE(instances.empty());
}
} // namespace vts
diff --git a/utils/native/trace_processor/Android.bp b/utils/native/trace_processor/Android.bp
index f051f78..fc8d8d0 100644
--- a/utils/native/trace_processor/Android.bp
+++ b/utils/native/trace_processor/Android.bp
@@ -17,7 +17,7 @@
cc_library_host_shared {
name: "libvts_traceprocessor",
- srcs: ["VtsTraceProcessor.cpp"],
+ srcs: ["VtsTraceProcessor.cpp", "VtsCoverageProcessor.cpp"],
shared_libs: [
"libbase",
@@ -26,6 +26,9 @@
"libvts_multidevice_proto",
"libvts_profiling_utils",
],
+ static_libs: [
+ "libjsoncpp",
+ ],
cflags: [
"-Wall",
"-Werror",
diff --git a/utils/native/trace_processor/TraceProcessorMain.cpp b/utils/native/trace_processor/TraceProcessorMain.cpp
index 3b45fa0..8eb821c 100644
--- a/utils/native/trace_processor/TraceProcessorMain.cpp
+++ b/utils/native/trace_processor/TraceProcessorMain.cpp
@@ -13,61 +13,192 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <getopt.h>
+
+#include "VtsCoverageProcessor.h"
#include "VtsTraceProcessor.h"
-// Usage examples:
-// To cleanup trace, <binary> --cleanup <trace file>/<trace file directory>
-// To profile trace, <binary> --profiling <trace file>
-// To dedup traces, <binary> --dedup <trace file directory>
-// To select traces based on coverage data,
-// <binary> --trace_selection <covreage file directory>
-// To parse trace, <binary> --parse <trace file>
-// Cleanup trace is used to generate trace for replay test, it will replace the
-// old trace file with a new one of the same format (VtsProfilingRecord).
-//
-// Profile trace will calculate the latency of each API recorded in the trace
-// and print them out with the format api:latency. e.g.
-// open:150231474
-// write:842604
-// coreInitialized:30466722
-//
-// Dedup trace is used to remove all duplicate traces under the given directory.
-// A trace is considered duplicated if there exists a trace that contains the
-// same API call sequence as the given trace and the input parameters for each
-// API call are all the same.
-//
-// Select trace is used to select a subset of trace files from a give trace set
-// based on their corresponding coverage data, the goal is to pick up the
-// minimal num of trace files that to maximize the total coverage.
-//
-// Parse trace is used to parse a binary trace file and print the text format of
-// the proto (used of for debug).
-int main(int argc, char* argv[]) {
- android::vts::VtsTraceProcessor trace_processor;
- if (argc == 3) {
- if (!strcmp(argv[1], "--cleanup")) {
- trace_processor.CleanupTraces(argv[2]);
- } else if (!strcmp(argv[1], "--profiling")) {
- trace_processor.ProcessTraceForLatencyProfiling(argv[2]);
- } else if (!strcmp(argv[1], "--dedup")) {
- trace_processor.DedupTraces(argv[2]);
- } else if (!strcmp(argv[1], "--parse")) {
- trace_processor.ParseTrace(argv[2]);
- } else if (!strcmp(argv[1], "--convert")) {
- trace_processor.ConvertTrace(argv[2]);
- } else {
- fprintf(stderr, "Invalid argument.\n");
- return -1;
+
+static constexpr const char* kDefaultMode = "noop";
+static constexpr const char* kDefaultOutputFile =
+ "/temp/vts_trace_processor_output";
+
+using namespace std;
+
+enum mode_code {
+ // Trace related operations.
+ CLEANUP_TRACE,
+ CONVERT_TRACE,
+ DEDUPE_TRACE,
+ GET_TEST_LIST_FROM_TRACE,
+ PARSE_TRACE,
+ PROFILING_TRACE,
+ SELECT_TRACE,
+ // Coverage related operations.
+ COMPARE_COVERAGE,
+ GET_COVERGAGE_SUMMARY,
+ GET_SUBSET_COVERAGE,
+ MERGE_COVERAGE,
+};
+
+mode_code getModeCode(const std::string& str) {
+ if (str == "cleanup_trace") return mode_code::CLEANUP_TRACE;
+ if (str == "convert_trace") return mode_code::CONVERT_TRACE;
+ if (str == "dedup_trace") return mode_code::DEDUPE_TRACE;
+ if (str == "get_test_list_from_trace")
+ return mode_code::GET_TEST_LIST_FROM_TRACE;
+ if (str == "parse_trace") return mode_code::PARSE_TRACE;
+ if (str == "profiling_trace") return mode_code::PROFILING_TRACE;
+ if (str == "select_trace") return mode_code::SELECT_TRACE;
+ if (str == "compare_coverage") return mode_code::COMPARE_COVERAGE;
+ if (str == "get_coverage_summary") return mode_code::GET_COVERGAGE_SUMMARY;
+ if (str == "get_subset_coverage") return mode_code::GET_SUBSET_COVERAGE;
+ if (str == "merge_coverage") return mode_code::MERGE_COVERAGE;
+ printf("Unknown operation mode: %s\n", str.c_str());
+ exit(-1);
+}
+
+void ShowUsage() {
+ printf(
+ "Usage: trace_processor [options] <input>\n"
+ "--mode: The operation applied to the trace file.\n"
+ "\t cleanup_trace: cleanup trace for replay (remove duplicate events "
+ "etc.).\n"
+ "\t convert_trace: convert a text format trace file into a binary format "
+ "trace.\n"
+ "\t dedup_trace: remove duplicate trace file in the given directory. A "
+ "trace is considered duplicated if there exists a trace that contains "
+ "the "
+ "same API call sequence as the given trace and the input parameters for "
+ "each API call are all the same.\n"
+ "\t get_test_list_from_trace: parse all trace files under the given "
+ "directory and create a list of test modules for each hal@version that "
+ "access all apis covered by the whole test set. (i.e. such list should "
+ "be a subset of the whole test list that access the corresponding "
+ "hal@version)\n"
+ "\t parse_trace: parse the binary format trace file and print the text "
+ "format trace. \n"
+ "\t profiling_trace: parse the trace file to get the latency of each api "
+ "call.\n"
+ "\t select_trace: select a subset of trace files from a give trace set "
+ "based on their corresponding coverage data, the goal is to pick up the "
+ "minimal num of trace files that to maximize the total coverage.\n"
+ "\t compare_coverage: compare a coverage report with a reference "
+ "coverage report and print the additional file/lines covered.\n"
+ "\t get_coverage_summary: print the summary of the coverage file (e.g. "
+ "covered lines, total lines, coverage rate.) \n"
+ "\t get_subset_coverage: extract coverage measurement from coverage "
+ "report for files covered in the reference coverage report. It is used "
+ "in cases when we have an aggregated coverage report for all files but "
+ "are only interested in the coverage measurement of a subset of files in "
+ "that report.\n"
+ "\t merge_coverage: merge all coverage reports under the given directory "
+ "and generate a merged report.\n"
+ "--output: The file path to store the output results.\n"
+ "--help: Show help\n");
+ exit(-1);
+}
+
+int main(int argc, char** argv) {
+ string mode = kDefaultMode;
+ string output = kDefaultOutputFile;
+ bool verbose_output = false;
+
+ android::vts::VtsCoverageProcessor coverage_processor;
+ android::vts::VtsTraceProcessor trace_processor(&coverage_processor);
+
+ const char* const short_opts = "hm:o:v:";
+ const option long_opts[] = {
+ {"help", no_argument, nullptr, 'h'},
+ {"mode", required_argument, nullptr, 'm'},
+ {"output", required_argument, nullptr, 'o'},
+ {"verbose", no_argument, nullptr, 'v'},
+ {nullptr, 0, nullptr, 0},
+ };
+
+ while (true) {
+ int opt = getopt_long(argc, argv, short_opts, long_opts, nullptr);
+ if (opt == -1) {
+ break;
}
- } else if (argc == 4) {
- if (!strcmp(argv[1], "--trace_selection")) {
- trace_processor.SelectTraces(argv[2], argv[3]);
- } else {
- fprintf(stderr, "Invalid argument.\n");
- return -1;
+ switch (opt) {
+ case 'h':
+ case '?':
+ ShowUsage();
+ return 0;
+ case 'm': {
+ mode = string(optarg);
+ break;
+ }
+ case 'o': {
+ output = string(optarg);
+ break;
+ }
+ case 'v': {
+ verbose_output = true;
+ break;
+ }
+ default:
+ printf("getopt_long returned unexpected value: %d\n", opt);
+ return -1;
}
- } else {
- fprintf(stderr, "Invalid argument.\n");
- return -1;
+ }
+
+ if (optind == argc - 1) {
+ string trace_path = argv[optind];
+ switch (getModeCode(mode)) {
+ case mode_code::CLEANUP_TRACE:
+ trace_processor.CleanupTraces(trace_path);
+ break;
+ case mode_code::CONVERT_TRACE:
+ trace_processor.ConvertTrace(trace_path);
+ break;
+ case mode_code::DEDUPE_TRACE:
+ trace_processor.DedupTraces(trace_path);
+ break;
+ case mode_code::GET_TEST_LIST_FROM_TRACE:
+ trace_processor.GetTestListForHal(trace_path, output, verbose_output);
+ break;
+ case mode_code::PARSE_TRACE:
+ trace_processor.ParseTrace(trace_path);
+ break;
+ case mode_code::PROFILING_TRACE:
+ trace_processor.ProcessTraceForLatencyProfiling(trace_path);
+ break;
+ case mode_code::GET_COVERGAGE_SUMMARY:
+ coverage_processor.GetCoverageSummary(trace_path);
+ break;
+ case mode_code::MERGE_COVERAGE:
+ coverage_processor.MergeCoverage(trace_path, output);
+ break;
+ default:
+ printf("Invalid argument.");
+ return -1;
+ }
+ } else if (optind == argc - 2) {
+ switch (getModeCode(mode)) {
+ case mode_code::SELECT_TRACE: {
+ string coverage_dir = argv[optind];
+ string trace_dir = argv[optind + 1];
+ trace_processor.SelectTraces(coverage_dir, trace_dir);
+ break;
+ }
+ case mode_code::COMPARE_COVERAGE: {
+ string ref_coverage_path = argv[optind];
+ string coverage_path = argv[optind + 1];
+ coverage_processor.CompareCoverage(ref_coverage_path, coverage_path);
+ break;
+ }
+ case mode_code::GET_SUBSET_COVERAGE: {
+ string ref_coverage_path = argv[optind];
+ string coverage_path = argv[optind + 1];
+ coverage_processor.GetSubsetCoverage(ref_coverage_path, coverage_path,
+ output);
+ break;
+ }
+ default:
+ printf("Invalid argument.");
+ return -1;
+ }
}
return 0;
}
diff --git a/utils/native/trace_processor/VtsCoverageProcessor.cpp b/utils/native/trace_processor/VtsCoverageProcessor.cpp
new file mode 100644
index 0000000..536ac0d
--- /dev/null
+++ b/utils/native/trace_processor/VtsCoverageProcessor.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2018 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 "VtsCoverageProcessor.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <google/protobuf/text_format.h>
+#include <test/vts/proto/VtsReportMessage.pb.h>
+
+using namespace std;
+using google::protobuf::TextFormat;
+
+namespace android {
+namespace vts {
+
+void VtsCoverageProcessor::ParseCoverageData(const string& coverage_file,
+ TestReportMessage* report_msg) {
+ ifstream in(coverage_file, std::ios::in);
+ string msg_str((istreambuf_iterator<char>(in)), istreambuf_iterator<char>());
+ if (!TextFormat::MergeFromString(msg_str, report_msg)) {
+ cerr << "Can't parse a given coverage report: " << msg_str << endl;
+ exit(-1);
+ }
+}
+
+void VtsCoverageProcessor::UpdateCoverageData(
+ const CoverageReportMessage& ref_msg,
+ CoverageReportMessage* msg_to_be_updated) {
+ if (ref_msg.file_path() == msg_to_be_updated->file_path()) {
+ for (int line = 0; line < ref_msg.line_coverage_vector_size(); line++) {
+ if (line < msg_to_be_updated->line_coverage_vector_size()) {
+ if (ref_msg.line_coverage_vector(line) > 0 &&
+ msg_to_be_updated->line_coverage_vector(line) > 0) {
+ msg_to_be_updated->set_line_coverage_vector(line, 0);
+ msg_to_be_updated->set_covered_line_count(
+ msg_to_be_updated->covered_line_count() - 1);
+ }
+ } else {
+ cout << "Reached the end of line_coverage_vector." << endl;
+ break;
+ }
+ }
+ // sanity check.
+ if (msg_to_be_updated->covered_line_count() < 0) {
+ cerr << __func__ << ": covered_line_count should not be negative."
+ << endl;
+ exit(-1);
+ }
+ }
+}
+
+void VtsCoverageProcessor::MergeCoverage(const string& coverage_file_dir,
+ const string& merged_coverage_file) {
+ DIR* coverage_dir = opendir(coverage_file_dir.c_str());
+ if (coverage_dir == 0) {
+ cerr << __func__ << ": " << coverage_file_dir << " does not exist." << endl;
+ return;
+ }
+ TestReportMessage merged_coverage_report;
+
+ struct dirent* file;
+ while ((file = readdir(coverage_dir)) != NULL) {
+ if (file->d_type == DT_REG) {
+ string coverage_file = coverage_file_dir;
+ if (coverage_file_dir.substr(coverage_file_dir.size() - 1) != "/") {
+ coverage_file += "/";
+ }
+ string coverage_file_base_name = file->d_name;
+ coverage_file += coverage_file_base_name;
+ TestReportMessage coverage_report;
+ ParseCoverageData(coverage_file, &coverage_report);
+
+ for (const auto cov : coverage_report.coverage()) {
+ bool seen_cov = false;
+ for (int i = 0; i < merged_coverage_report.coverage_size(); i++) {
+ if (merged_coverage_report.coverage(i).file_path() ==
+ cov.file_path()) {
+ MergeCoverageMsg(cov, merged_coverage_report.mutable_coverage(i));
+ seen_cov = true;
+ break;
+ }
+ }
+ if (!seen_cov) {
+ *merged_coverage_report.add_coverage() = cov;
+ }
+ }
+ }
+ }
+
+ PrintCoverageSummary(merged_coverage_report);
+ ofstream fout;
+ fout.open(merged_coverage_file);
+ fout << merged_coverage_report.DebugString();
+ fout.close();
+}
+
+void VtsCoverageProcessor::MergeCoverageMsg(
+ const CoverageReportMessage& ref_coverage_msg,
+ CoverageReportMessage* merged_coverage_msg) {
+ // sanity check.
+ if (ref_coverage_msg.file_path() != merged_coverage_msg->file_path()) {
+ cerr << "Trying to merge coverage data for different files." << endl;
+ exit(-1);
+ }
+ if (ref_coverage_msg.line_coverage_vector_size() !=
+ merged_coverage_msg->line_coverage_vector_size()) {
+ cerr << "Trying to merge coverage data with different lines."
+ << "ref_coverage_msg: " << ref_coverage_msg.DebugString()
+ << "merged_coverage_msg: " << merged_coverage_msg->DebugString()
+ << endl;
+ exit(-1);
+ }
+ for (int i = 0; i < ref_coverage_msg.line_coverage_vector_size(); i++) {
+ if (i > merged_coverage_msg->line_coverage_vector_size() - 1) {
+ cerr << "Reach the end of coverage vector" << endl;
+ break;
+ }
+ int ref_line_count = ref_coverage_msg.line_coverage_vector(i);
+ int merged_line_count = merged_coverage_msg->line_coverage_vector(i);
+ if (ref_line_count > 0) {
+ if (merged_line_count == 0) {
+ merged_coverage_msg->set_covered_line_count(
+ merged_coverage_msg->covered_line_count() + 1);
+ }
+ merged_coverage_msg->set_line_coverage_vector(
+ i, merged_line_count + ref_line_count);
+ }
+ }
+}
+
+void VtsCoverageProcessor::CompareCoverage(const string& ref_msg_file,
+ const string& new_msg_file) {
+ TestReportMessage ref_coverage_report;
+ TestReportMessage new_coverage_report;
+ ParseCoverageData(ref_msg_file, &ref_coverage_report);
+ ParseCoverageData(new_msg_file, &new_coverage_report);
+ map<string, vector<int>> new_coverage_map;
+
+ for (const auto& new_coverage : new_coverage_report.coverage()) {
+ bool seen_file = false;
+ for (const auto& ref_coverage : ref_coverage_report.coverage()) {
+ if (new_coverage.file_path() == ref_coverage.file_path()) {
+ int line = 0;
+ for (; line < new_coverage.line_coverage_vector_size(); line++) {
+ if (new_coverage.line_coverage_vector(line) > 0 &&
+ ref_coverage.line_coverage_vector(line) == 0) {
+ if (new_coverage_map.find(new_coverage.file_path()) !=
+ new_coverage_map.end()) {
+ new_coverage_map[new_coverage.file_path()].push_back(line);
+ } else {
+ new_coverage_map.insert(std::pair<string, vector<int>>(
+ new_coverage.file_path(), vector<int>{line}));
+ }
+ }
+ }
+ seen_file = true;
+ break;
+ }
+ }
+ if (!seen_file) {
+ vector<int> new_line;
+ for (int line = 0; line < new_coverage.line_coverage_vector_size();
+ line++) {
+ if (new_coverage.line_coverage_vector(line) > 0) {
+ new_line.push_back(line);
+ }
+ }
+ new_coverage_map.insert(
+ std::pair<string, vector<int>>(new_coverage.file_path(), new_line));
+ }
+ }
+ for (auto it = new_coverage_map.begin(); it != new_coverage_map.end(); it++) {
+ cout << it->first << ": " << endl;
+ for (int covered_line : it->second) {
+ cout << covered_line << endl;
+ }
+ }
+}
+
+void VtsCoverageProcessor::GetSubsetCoverage(const string& ref_msg_file,
+ const string& full_msg_file,
+ const string& result_msg_file) {
+ TestReportMessage ref_coverage_report;
+ TestReportMessage full_coverage_report;
+ TestReportMessage result_coverage_report;
+ ParseCoverageData(ref_msg_file, &ref_coverage_report);
+ ParseCoverageData(full_msg_file, &full_coverage_report);
+
+ for (const auto& ref_coverage : ref_coverage_report.coverage()) {
+ bool seen_file = false;
+ for (const auto& coverage : full_coverage_report.coverage()) {
+ if (coverage.file_path() == ref_coverage.file_path()) {
+ *result_coverage_report.add_coverage() = coverage;
+ seen_file = true;
+ break;
+ }
+ }
+ if (!seen_file) {
+ cout << ": missing coverage for file " << ref_coverage.file_path()
+ << endl;
+ CoverageReportMessage* empty_coverage =
+ result_coverage_report.add_coverage();
+ *empty_coverage = ref_coverage;
+ for (int line = 0; line < empty_coverage->line_coverage_vector_size();
+ line++) {
+ if (empty_coverage->line_coverage_vector(line) > 0) {
+ empty_coverage->set_line_coverage_vector(line, 0);
+ }
+ }
+ empty_coverage->set_covered_line_count(0);
+ }
+ }
+ PrintCoverageSummary(result_coverage_report);
+ ofstream fout;
+ fout.open(result_msg_file);
+ fout << result_coverage_report.DebugString();
+ fout.close();
+}
+
+void VtsCoverageProcessor::GetCoverageSummary(const string& coverage_msg_file) {
+ TestReportMessage coverage_report;
+ ParseCoverageData(coverage_msg_file, &coverage_report);
+ PrintCoverageSummary(coverage_report);
+}
+
+void VtsCoverageProcessor::PrintCoverageSummary(
+ const TestReportMessage& coverage_report) {
+ long total_lines_covered = GetTotalCoverageLine(coverage_report);
+ long total_code_lines = GetTotalCodeLine(coverage_report);
+ double coverage_rate = (double)total_lines_covered / total_code_lines;
+ cout << "total lines covered: " << total_lines_covered << endl;
+ cout << "total lines: " << total_code_lines << endl;
+ cout << "coverage rate: " << coverage_rate << endl;
+}
+
+long VtsCoverageProcessor::GetTotalCoverageLine(
+ const TestReportMessage& msg) const {
+ long total_coverage_line = 0;
+ for (const auto coverage : msg.coverage()) {
+ total_coverage_line += coverage.covered_line_count();
+ }
+ return total_coverage_line;
+}
+
+long VtsCoverageProcessor::GetTotalCodeLine(
+ const TestReportMessage& msg) const {
+ long total_line = 0;
+ for (const auto coverage : msg.coverage()) {
+ total_line += coverage.total_line_count();
+ }
+ return total_line;
+}
+
+} // namespace vts
+} // namespace android
diff --git a/utils/native/trace_processor/VtsCoverageProcessor.h b/utils/native/trace_processor/VtsCoverageProcessor.h
new file mode 100644
index 0000000..e1eb70a
--- /dev/null
+++ b/utils/native/trace_processor/VtsCoverageProcessor.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef TOOLS_TRACE_PROCESSOR_VTSCOVERAGEPROCESSOR_H_
+#define TOOLS_TRACE_PROCESSOR_VTSCOVERAGEPROCESSOR_H_
+
+#include <android-base/macros.h>
+#include <test/vts/proto/VtsReportMessage.pb.h>
+
+namespace android {
+namespace vts {
+// A class used for processing coverage report data, such as parse the
+// coverage report file, merge multiple coverage reports, and compare
+// two coverage reports.
+class VtsCoverageProcessor {
+ public:
+ VtsCoverageProcessor(){};
+ virtual ~VtsCoverageProcessor(){};
+
+ // Merge the coverage files under coverage_file_dir and output the merged
+ // coverage data to merged_coverage_file.
+ void MergeCoverage(const std::string& coverage_file_dir,
+ const std::string& merged_coverage_file);
+
+ // Compare coverage data contained in new_msg_file with ref_msg_file and
+ // print the additional file/lines covered by the new_msg_file.
+ void CompareCoverage(const std::string& ref_msg_file,
+ const std::string& new_msg_file);
+
+ // Parse the given coverage_file into a coverage report.
+ void ParseCoverageData(const std::string& coverage_file,
+ TestReportMessage* coverage_report);
+
+ // Updates msg_to_be_updated by removing all the covered lines in ref_msg
+ // and recalculates the count of covered lines accordingly.
+ void UpdateCoverageData(const CoverageReportMessage& ref_msg,
+ CoverageReportMessage* msg_to_be_updated);
+
+ // Extract the files covered in ref_msg_file from full_msg_file and store
+ // the result in result_msg_file.
+ void GetSubsetCoverage(const std::string& ref_msg_file,
+ const std::string& full_msg_file,
+ const std::string& result_msg_file);
+
+ // Parse the coverage report and print the coverage summary.
+ void GetCoverageSummary(const std::string& coverage_msg_file);
+
+ // Calculate total coverage line in the given report message.
+ long GetTotalCoverageLine(const TestReportMessage& msg) const;
+ // Calculate total code line in the given report message.
+ long GetTotalCodeLine(const TestReportMessage& msg) const;
+
+ private:
+ // Internal method to merge the ref_coverage_msg into merged_covergae_msg.
+ void MergeCoverageMsg(const CoverageReportMessage& ref_coverage_msg,
+ CoverageReportMessage* merged_covergae_msg);
+
+ // Help method to print the coverage summary.
+ void PrintCoverageSummary(const TestReportMessage& coverage_report);
+
+ DISALLOW_COPY_AND_ASSIGN(VtsCoverageProcessor);
+};
+
+} // namespace vts
+} // namespace android
+#endif // TOOLS_TRACE_PROCESSOR_VTSCOVERAGEPROCESSOR_H_
diff --git a/utils/native/trace_processor/VtsTraceProcessor.cpp b/utils/native/trace_processor/VtsTraceProcessor.cpp
index aae654c..06f0c5d 100644
--- a/utils/native/trace_processor/VtsTraceProcessor.cpp
+++ b/utils/native/trace_processor/VtsTraceProcessor.cpp
@@ -17,9 +17,12 @@
#include <dirent.h>
#include <fcntl.h>
+#include <json/json.h>
#include <fstream>
+#include <iomanip>
#include <iostream>
#include <map>
+#include <sstream>
#include <string>
#include <vector>
@@ -39,6 +42,7 @@
bool VtsTraceProcessor::ParseBinaryTrace(const string& trace_file,
bool ignore_timestamp, bool entry_only,
+ bool ignore_func_params,
VtsProfilingMessage* profiling_msg) {
int fd =
open(trace_file.c_str(), O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
@@ -53,6 +57,10 @@
if (ignore_timestamp) {
record.clear_timestamp();
}
+ if (ignore_func_params) {
+ record.mutable_func_msg()->clear_arg();
+ record.mutable_func_msg()->clear_return_type_hidl();
+ }
if (entry_only) {
if (isEntryEvent(record.event())) {
*profiling_msg->add_records() = record;
@@ -96,7 +104,7 @@
void VtsTraceProcessor::ParseTrace(const string& trace_file) {
VtsProfilingMessage profiling_msg;
- if (!ParseBinaryTrace(trace_file, false, false, &profiling_msg)) {
+ if (!ParseBinaryTrace(trace_file, false, false, false, &profiling_msg)) {
cerr << __func__ << ": Failed to parse trace file: " << trace_file << endl;
return;
}
@@ -140,7 +148,7 @@
void VtsTraceProcessor::CleanupTraceFile(const string& trace_file) {
VtsProfilingMessage profiling_msg;
- if (!ParseBinaryTrace(trace_file, false, false, &profiling_msg)) {
+ if (!ParseBinaryTrace(trace_file, false, false, true, &profiling_msg)) {
cerr << __func__ << ": Failed to parse trace file: " << trace_file << endl;
return;
}
@@ -240,15 +248,15 @@
void VtsTraceProcessor::ProcessTraceForLatencyProfiling(
const string& trace_file) {
VtsProfilingMessage profiling_msg;
- if (!ParseBinaryTrace(trace_file, false, false, &profiling_msg)) {
+ if (!ParseBinaryTrace(trace_file, false, false, true, &profiling_msg)) {
cerr << __func__ << ": Failed to parse trace file: " << trace_file << endl;
return;
}
if (!profiling_msg.records_size()) return;
- if (profiling_msg.records(0).event()
- == InstrumentationEventType::PASSTHROUGH_ENTRY
- || profiling_msg.records(0).event()
- == InstrumentationEventType::PASSTHROUGH_EXIT) {
+ if (profiling_msg.records(0).event() ==
+ InstrumentationEventType::PASSTHROUGH_ENTRY ||
+ profiling_msg.records(0).event() ==
+ InstrumentationEventType::PASSTHROUGH_EXIT) {
cout << "hidl_hal_mode:passthrough" << endl;
} else {
cout << "hidl_hal_mode:binder" << endl;
@@ -295,14 +303,14 @@
}
void VtsTraceProcessor::DedupTraces(const string& trace_dir) {
- DIR *dir = opendir(trace_dir.c_str());
+ DIR* dir = opendir(trace_dir.c_str());
if (dir == 0) {
cerr << trace_dir << "does not exist." << endl;
return;
}
vector<VtsProfilingMessage> seen_msgs;
vector<string> duplicate_trace_files;
- struct dirent *file;
+ struct dirent* file;
long total_trace_num = 0;
long duplicat_trace_num = 0;
while ((file = readdir(dir)) != NULL) {
@@ -314,7 +322,7 @@
}
trace_file += file->d_name;
VtsProfilingMessage profiling_msg;
- if (!ParseBinaryTrace(trace_file, true, true, &profiling_msg)) {
+ if (!ParseBinaryTrace(trace_file, true, true, false, &profiling_msg)) {
cerr << "Failed to parse trace file: " << trace_file << endl;
return;
}
@@ -323,15 +331,15 @@
duplicat_trace_num++;
continue;
}
- auto found = find_if(
- seen_msgs.begin(), seen_msgs.end(),
- [&profiling_msg] (const VtsProfilingMessage& seen_msg) {
- std::string str_profiling_msg;
- std::string str_seen_msg;
- profiling_msg.SerializeToString(&str_profiling_msg);
- seen_msg.SerializeToString(&str_seen_msg);
- return (str_profiling_msg == str_seen_msg);
- });
+ auto found =
+ find_if(seen_msgs.begin(), seen_msgs.end(),
+ [&profiling_msg](const VtsProfilingMessage& seen_msg) {
+ std::string str_profiling_msg;
+ std::string str_seen_msg;
+ profiling_msg.SerializeToString(&str_profiling_msg);
+ seen_msg.SerializeToString(&str_seen_msg);
+ return (str_profiling_msg == str_seen_msg);
+ });
if (found == seen_msgs.end()) {
seen_msgs.push_back(profiling_msg);
} else {
@@ -350,43 +358,6 @@
<< float(duplicat_trace_num) / total_trace_num << endl;
}
-bool VtsTraceProcessor::ParseCoverageData(const string& coverage_file,
- TestReportMessage* report_msg) {
- ifstream in(coverage_file, std::ios::in);
- string msg_str((istreambuf_iterator<char>(in)), istreambuf_iterator<char>());
- if (!TextFormat::MergeFromString(msg_str, report_msg)) {
- cerr << __func__ << ": Can't parse a given record: " << msg_str << endl;
- return false;
- }
- return true;
-}
-
-void VtsTraceProcessor::UpdateCoverageData(
- const CoverageReportMessage& ref_msg,
- CoverageReportMessage* msg_to_be_updated) {
- if (ref_msg.file_path() == msg_to_be_updated->file_path()) {
- for (int line = 0; line < ref_msg.line_coverage_vector_size(); line++) {
- if (line < msg_to_be_updated->line_coverage_vector_size()) {
- if (ref_msg.line_coverage_vector(line) > 0 &&
- msg_to_be_updated->line_coverage_vector(line) > 0) {
- msg_to_be_updated->set_line_coverage_vector(line, 0);
- msg_to_be_updated->set_covered_line_count(
- msg_to_be_updated->covered_line_count() - 1);
- }
- } else {
- cout << "Reached the end of line_coverage_vector." << endl;
- break;
- }
- }
- // sanity check.
- if (msg_to_be_updated->covered_line_count() < 0) {
- cerr << __func__ << ": covered_line_count should not be negative."
- << endl;
- exit(-1);
- }
- }
-}
-
void VtsTraceProcessor::SelectTraces(const string& coverage_file_dir,
const string& trace_file_dir,
TraceSelectionMetric metric) {
@@ -414,10 +385,7 @@
string coverage_file_base_name = file->d_name;
coverage_file += coverage_file_base_name;
TestReportMessage coverage_msg;
- if (!ParseCoverageData(coverage_file, &coverage_msg)) {
- cerr << "Failed to parse coverage file: " << coverage_file << endl;
- return;
- }
+ coverage_processor_->ParseCoverageData(coverage_file, &coverage_msg);
string trace_file = trace_file_dir;
if (trace_file_dir.substr(trace_file_dir.size() - 1) != "/") {
@@ -440,11 +408,10 @@
original_coverages[coverage_file] = coverage_info;
}
}
- // Greedy algorithm that selects coverage files with the maximal code coverage
- // delta at each iteration.
- // Note: Not guaranteed to generate the optimal set.
- // Example (*: covered, -: not_covered)
- // line#\coverage_file cov1 cov2 cov3
+ // Greedy algorithm that selects coverage files with the maximal code
+ // coverage delta at each iteration. Note: Not guaranteed to generate the
+ // optimal set. Example (*: covered, -: not_covered) line#\coverage_file
+ // cov1 cov2 cov3
// 1 * - -
// 2 * * -
// 3 - * *
@@ -465,11 +432,13 @@
for (int i = 0; i < cur_coverage_msg.coverage_size(); i++) {
CoverageReportMessage* coverage_to_be_updated =
cur_coverage_msg.mutable_coverage(i);
- UpdateCoverageData(ref_coverage, coverage_to_be_updated);
+ coverage_processor_->UpdateCoverageData(ref_coverage,
+ coverage_to_be_updated);
}
}
it->second.coverage_msg = cur_coverage_msg;
- long total_coverage_line = GetTotalCoverageLine(cur_coverage_msg);
+ long total_coverage_line =
+ coverage_processor_->GetTotalCoverageLine(cur_coverage_msg);
long trace_file_size = it->second.trace_file_size;
double coverage_size_ratio =
(double)total_coverage_line / trace_file_size;
@@ -503,9 +472,10 @@
++it) {
cout << "select trace file: " << it->second.trace_file_name << endl;
TestReportMessage coverage_msg = it->second.coverage_msg;
- total_lines_covered += GetTotalCoverageLine(coverage_msg);
- if (GetTotalLine(coverage_msg) > total_lines) {
- total_lines = GetTotalLine(coverage_msg);
+ total_lines_covered +=
+ coverage_processor_->GetTotalCoverageLine(coverage_msg);
+ if (coverage_processor_->GetTotalCodeLine(coverage_msg) > total_lines) {
+ total_lines = coverage_processor_->GetTotalCodeLine(coverage_msg);
}
}
double coverage_rate = (double)total_lines_covered / total_lines;
@@ -514,22 +484,6 @@
cout << "coverage rate: " << coverage_rate << endl;
}
-long VtsTraceProcessor::GetTotalCoverageLine(const TestReportMessage& msg) {
- long total_coverage_line = 0;
- for (const auto coverage : msg.coverage()) {
- total_coverage_line += coverage.covered_line_count();
- }
- return total_coverage_line;
-}
-
-long VtsTraceProcessor::GetTotalLine(const TestReportMessage& msg) {
- long total_line = 0;
- for (const auto coverage : msg.coverage()) {
- total_line += coverage.total_line_count();
- }
- return total_line;
-}
-
string VtsTraceProcessor::GetTraceFileName(const string& coverage_file_name) {
std::size_t start = coverage_file_name.find("android.hardware");
std::size_t end = coverage_file_name.find("vts.trace") + sizeof("vts.trace");
@@ -577,5 +531,158 @@
return false;
}
+void VtsTraceProcessor::GetTestListForHal(const string& test_trace_dir,
+ const string& output_file,
+ bool verbose_output) {
+ // Mapping from hal name to the list of test that access that hal.
+ map<string, vector<TraceSummary>> hal_trace_mapping;
+ GetHalTraceMapping(test_trace_dir, &hal_trace_mapping);
+
+ map<string, set<string>> test_list;
+ for (auto it = hal_trace_mapping.begin(); it != hal_trace_mapping.end();
+ it++) {
+ test_list[it->first] = set<string>();
+ vector<TraceSummary> trace_summaries = it->second;
+ vector<string> covered_apis;
+ for (auto summary : trace_summaries) {
+ for (auto const& api_stat_it : summary.api_stats) {
+ if (std::find(covered_apis.begin(), covered_apis.end(),
+ api_stat_it.first) == covered_apis.end()) {
+ covered_apis.push_back(api_stat_it.first);
+ test_list[it->first].insert(summary.test_name);
+ }
+ }
+ }
+ for (auto api : covered_apis) {
+ cout << "covered api: " << api << endl;
+ }
+ }
+
+ ofstream fout;
+ fout.open(output_file);
+ for (auto it = hal_trace_mapping.begin(); it != hal_trace_mapping.end();
+ it++) {
+ if (verbose_output) {
+ Json::Value root(Json::objectValue);
+ root["Hal_name"] = Json::Value(it->first);
+ Json::Value arr(Json::arrayValue);
+ for (const TraceSummary& summary : it->second) {
+ Json::Value obj;
+ obj["Test_name"] = summary.test_name;
+ obj["Unique_Api_Count"] = std::to_string(summary.unique_api_count);
+ obj["Total_Api_Count"] = std::to_string(summary.total_api_count);
+ arr.append(obj);
+ }
+ root["Test_list"] = arr;
+ fout << root.toStyledString();
+ } else {
+ fout << it->first << ",";
+ for (auto test : test_list[it->first]) {
+ auto found = find_if(it->second.begin(), it->second.end(),
+ [&](const TraceSummary& trace_summary) {
+ return (trace_summary.test_name == test);
+ });
+ if (found != it->second.end()) {
+ fout << found->test_name << "(" << found->unique_api_count << "/"
+ << found->total_api_count << "),";
+ }
+ }
+ fout << endl;
+ }
+ }
+ fout.close();
+}
+
+void VtsTraceProcessor::GetHalTraceMapping(
+ const string& test_trace_dir,
+ map<string, vector<TraceSummary>>* hal_trace_mapping) {
+ DIR* trace_dir = opendir(test_trace_dir.c_str());
+ if (trace_dir == 0) {
+ cerr << __func__ << ": " << trace_dir << " does not exist." << endl;
+ return;
+ }
+ vector<TraceSummary> trace_summaries;
+ struct dirent* test_dir;
+ while ((test_dir = readdir(trace_dir)) != NULL) {
+ if (test_dir->d_type == DT_DIR) {
+ string test_name = test_dir->d_name;
+ cout << "Processing test: " << test_name << endl;
+ string trace_file_dir_name = test_trace_dir;
+ if (test_trace_dir.substr(test_trace_dir.size() - 1) != "/") {
+ trace_file_dir_name += "/";
+ }
+ trace_file_dir_name += test_name;
+ DIR* trace_file_dir = opendir(trace_file_dir_name.c_str());
+ struct dirent* trace_file;
+ while ((trace_file = readdir(trace_file_dir)) != NULL) {
+ if (trace_file->d_type == DT_REG) {
+ string trace_file_name =
+ trace_file_dir_name + "/" + trace_file->d_name;
+ GetHalTraceSummary(trace_file_name, test_name, &trace_summaries);
+ }
+ }
+ }
+ }
+
+ // Generate hal_trace_mapping mappings.
+ for (const TraceSummary& trace_summary : trace_summaries) {
+ string test_name = trace_summary.test_name;
+ stringstream stream;
+ stream << fixed << setprecision(1) << trace_summary.version;
+ string hal_name = trace_summary.package + "@" + stream.str();
+ if (hal_trace_mapping->find(hal_name) != hal_trace_mapping->end()) {
+ (*hal_trace_mapping)[hal_name].push_back(trace_summary);
+ } else {
+ (*hal_trace_mapping)[hal_name] = vector<TraceSummary>{trace_summary};
+ }
+ }
+ for (auto it = hal_trace_mapping->begin(); it != hal_trace_mapping->end();
+ it++) {
+ // Sort the tests according to unique_api_count and break tie with
+ // total_api_count.
+ std::sort(it->second.begin(), it->second.end(),
+ [](const TraceSummary& lhs, const TraceSummary& rhs) {
+ return (lhs.unique_api_count > rhs.unique_api_count) ||
+ (lhs.unique_api_count == rhs.unique_api_count &&
+ lhs.total_api_count > rhs.total_api_count);
+ });
+ }
+}
+
+void VtsTraceProcessor::GetHalTraceSummary(
+ const string& trace_file, const string& test_name,
+ vector<TraceSummary>* trace_summaries) {
+ VtsProfilingMessage profiling_msg;
+ if (!ParseBinaryTrace(trace_file, true, true, true, &profiling_msg)) {
+ cerr << __func__ << ": Failed to parse trace file: " << trace_file << endl;
+ return;
+ }
+ for (const auto& record : profiling_msg.records()) {
+ string package = record.package();
+ float version = record.version();
+ string func_name = record.func_msg().name();
+ auto found = find_if(trace_summaries->begin(), trace_summaries->end(),
+ [&](const TraceSummary& trace_summary) {
+ return (test_name == trace_summary.test_name &&
+ package == trace_summary.package &&
+ version == trace_summary.version);
+ });
+ if (found != trace_summaries->end()) {
+ found->total_api_count++;
+ if (found->api_stats.find(func_name) != found->api_stats.end()) {
+ found->api_stats[func_name]++;
+ } else {
+ found->unique_api_count++;
+ found->api_stats[func_name] = 1;
+ }
+ } else {
+ map<string, long> api_stats;
+ api_stats[func_name] = 1;
+ TraceSummary trace_summary(test_name, package, version, 1, 1, api_stats);
+ trace_summaries->push_back(trace_summary);
+ }
+ }
+}
+
} // namespace vts
} // namespace android
diff --git a/utils/native/trace_processor/VtsTraceProcessor.h b/utils/native/trace_processor/VtsTraceProcessor.h
index 1e8eddf..3d205e8 100644
--- a/utils/native/trace_processor/VtsTraceProcessor.h
+++ b/utils/native/trace_processor/VtsTraceProcessor.h
@@ -20,14 +20,16 @@
#include <android-base/macros.h>
#include <test/vts/proto/VtsProfilingMessage.pb.h>
#include <test/vts/proto/VtsReportMessage.pb.h>
+#include "VtsCoverageProcessor.h"
namespace android {
namespace vts {
class VtsTraceProcessor {
public:
- VtsTraceProcessor() {};
- virtual ~VtsTraceProcessor() {};
+ VtsTraceProcessor(VtsCoverageProcessor* coverage_processor)
+ : coverage_processor_(coverage_processor){};
+ virtual ~VtsTraceProcessor(){};
enum TraceSelectionMetric {
MAX_COVERAGE,
@@ -60,12 +62,20 @@
// Reads a text trace file, parse each trace event and convert it into a
// binary trace file.
void ConvertTrace(const std::string& trace_file);
+ // Parse all trace files under test_trace_dir and create a list of test
+ // modules for each hal@version that access all apis covered by the whole test
+ // set. (i.e. such list should be a subset of the whole test list that access
+ // the corresponding hal@version)
+ void GetTestListForHal(const std::string& test_trace_dir,
+ const std::string& output_file,
+ bool verbose_output = false);
private:
// Reads a binary trace file and parse each trace event into
// VtsProfilingRecord.
bool ParseBinaryTrace(const std::string& trace_file, bool ignore_timestamp,
- bool entry_only, VtsProfilingMessage* profiling_msg);
+ bool entry_only, bool summary_only,
+ VtsProfilingMessage* profiling_msg);
// Reads a text trace file and parse each trace event into
// VtsProfilingRecord.
@@ -90,8 +100,7 @@
long GetTotalCoverageLine(const TestReportMessage& msg);
// Helper method to calculate total code line in the given report message.
long GetTotalLine(const TestReportMessage& msg);
- // Helper method to extract the trace file name from the given coverage file
- // name.
+ // Helper method to extract the trace file name from the given file name.
std::string GetTraceFileName(const std::string& coverage_file_name);
// Helper method to check whether the given event is an entry event.
bool isEntryEvent(const InstrumentationEventType& event);
@@ -108,7 +117,48 @@
long trace_file_size;
};
- DISALLOW_COPY_AND_ASSIGN (VtsTraceProcessor);
+ // Struct to store the trace summary data.
+ struct TraceSummary {
+ // Name of test module that generates the trace. e.g. CtsUsbTests.
+ std::string test_name;
+ // Hal package name. e.g. android.hardware.light
+ std::string package;
+ // Hal version e.g. 1.0
+ float version;
+ // Total number of API calls recorded in the trace.
+ long total_api_count;
+ // Total number of different APIs recorded in the trace.
+ long unique_api_count;
+ // Call statistics for each API: <API_name, number_called>
+ std::map<std::string, long> api_stats;
+
+ TraceSummary(std::string test_name, std::string package, float version,
+ long total_api_count, long unique_api_count,
+ std::map<std::string, long> api_stats)
+ : test_name(test_name),
+ package(package),
+ version(version),
+ total_api_count(total_api_count),
+ unique_api_count(unique_api_count),
+ api_stats(api_stats){};
+ };
+
+ // Internal method to parse all trace files under test_trace_dir and create
+ // the mapping from each hal@version to the list of test that access it.
+ void GetHalTraceMapping(
+ const std::string& test_trace_dir,
+ std::map<std::string, std::vector<TraceSummary>>* hal_trace_mapping);
+
+ // Internal method to parse a trace file and create the corresponding
+ // TraceSummary from it.
+ void GetHalTraceSummary(const std::string& trace_file,
+ const std::string& test_name,
+ std::vector<TraceSummary>* trace_summaries);
+
+ // A class to process coverage reports. Not owned.
+ VtsCoverageProcessor* coverage_processor_;
+
+ DISALLOW_COPY_AND_ASSIGN(VtsTraceProcessor);
};
} // namespace vts
diff --git a/utils/python/Android.bp b/utils/python/Android.bp
new file mode 100644
index 0000000..7111b03
--- /dev/null
+++ b/utils/python/Android.bp
@@ -0,0 +1,22 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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.
+
+python_library_host {
+ name: "vts_runner_utils_python",
+ srcs: [
+ "**/*.py",
+ ],
+ defaults: ["py2_only"],
+}
+
diff --git a/utils/python/retry/__init__.py b/utils/python/android/__init__.py
similarity index 100%
copy from utils/python/retry/__init__.py
copy to utils/python/android/__init__.py
diff --git a/tools/vts-hc/Android.mk b/utils/python/android/api.py
similarity index 72%
copy from tools/vts-hc/Android.mk
copy to utils/python/android/api.py
index 7733142..f97a8cd 100644
--- a/tools/vts-hc/Android.mk
+++ b/utils/python/android/api.py
@@ -1,4 +1,5 @@
-# Copyright (C) 2017 The Android Open Source Project
+#
+# Copyright (C) 2018 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.
@@ -12,11 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_PREBUILT_EXECUTABLES := run
-include $(BUILD_HOST_PREBUILT)
-
+PLATFORM_API_LEVEL_O = 26
+PLATFORM_API_LEVEL_O_MR1 = 27
+PLATFORM_API_LEVEL_P = 28
diff --git a/utils/python/build/api/artifact_fetcher.py b/utils/python/build/api/artifact_fetcher.py
index c4769da..2224038 100644
--- a/utils/python/build/api/artifact_fetcher.py
+++ b/utils/python/build/api/artifact_fetcher.py
@@ -16,17 +16,16 @@
"""Class to fetch artifacts from internal build server.
"""
-import apiclient
+import googleapiclient
import httplib2
import io
import json
import logging
import re
import time
-from apiclient.discovery import build
+from googleapiclient.discovery import build
from oauth2client import client as oauth2_client
from oauth2client.service_account import ServiceAccountCredentials
-from vts.utils.python.retry import retry
logger = logging.getLogger('artifact_fetcher')
@@ -48,15 +47,7 @@
DEFAULT_ATTEMPT_ID: string, default attempt to request for the artifact.
DEFAULT_CHUNK_SIZE: int, number of bytes to download at a time.
RETRY_COUNT: int, max number of retries.
- RETRY_BACKOFF_FACTOR: float, base of exponential determining sleep time.
- total_time = (backoff_factor^(attempt - 1))*sleep
- RETRY_SLEEP_MULTIPLIER: float, multiplier for how long to sleep between
- attempts.
- RETRY_HTTP_CODES: int array, HTTP codes for which a retry will be
- attempted.
- RETRIABLE_AUTH_ERRORS: class tuple, list of error classes for which a
- retry will be attempted.
-
+ RETRY_DELAY_IN_SECS: int, time delays between retries in seconds.
"""
API_NAME = "androidbuildinternal"
@@ -74,15 +65,7 @@
# Defaults for retry.
RETRY_COUNT = 5
- RETRY_BACKOFF_FACTOR = 1.5
- RETRY_SLEEP_MULTIPLIER = 1
- RETRY_HTTP_CODES = [
- 500, # Internal Server Error
- 502, # Bad Gateway
- 503, # Service Unavailable
- ]
-
- RETRIABLE_AUTH_ERRORS = (oauth2_client.AccessTokenRefreshError, )
+ RETRY_DELAY_IN_SECS = 3
def __init__(self, oauth2_service_json):
"""Initialize.
@@ -93,15 +76,21 @@
authToken = ServiceAccountCredentials.from_json_keyfile_name(
oauth2_service_json, [self.SCOPE])
http_auth = authToken.authorize(httplib2.Http())
- self.service = retry.RetryException(
- exc_retry=self.RETRIABLE_AUTH_ERRORS,
- max_retry=self.RETRY_COUNT,
- functor=build,
- sleep=self.RETRY_SLEEP_MULTIPLIER,
- backoff_factor=self.RETRY_BACKOFF_FACTOR,
- serviceName=self.API_NAME,
- version=self.API_VERSION,
- http=http_auth)
+ for _ in xrange(self.RETRY_COUNT):
+ try:
+ self.service = build(
+ serviceName=self.API_NAME,
+ version=self.API_VERSION,
+ http=http_auth)
+ break
+ except oauth2_client.AccessTokenRefreshError as e:
+ # The following HTTP code typically indicates transient errors:
+ # 500 (Internal Server Error)
+ # 502 (Bad Gateway)
+ # 503 (Service Unavailable)
+ logging.exception(e)
+ logging.info("Retrying to connect to %s", self.API_NAME)
+ time.sleep(self.RETRY_DELAY_IN_SECS)
def DownloadArtifactToFile(self,
branch,
@@ -163,7 +152,7 @@
else:
fh = io.BytesIO()
- downloader = apiclient.http.MediaIoBaseDownload(
+ downloader = googleapiclient.http.MediaIoBaseDownload(
fh, api, chunksize=self.DEFAULT_CHUNK_SIZE)
done = False
while not done:
diff --git a/utils/python/common/cmd_utils.py b/utils/python/common/cmd_utils.py
index 8279994..d03e8c2 100644
--- a/utils/python/common/cmd_utils.py
+++ b/utils/python/common/cmd_utils.py
@@ -15,12 +15,55 @@
import logging
import subprocess
+import threading
+
+from vts.runners.host import utils
STDOUT = 'stdouts'
STDERR = 'stderrs'
EXIT_CODE = 'return_codes'
+def _ExecuteOneShellCommandWithTimeout(cmd, timeout):
+ """Executes a command with timeout.
+
+ If the process times out, this function terminates it and continues
+ waiting.
+
+ Args:
+ proc: Popen object, the process to wait for.
+ timeout: float, timeout in seconds.
+
+ Returns:
+ tuple(string, string, int) which are stdout, stderr and return code.
+ """
+ # On Windows, subprocess.Popen(shell=True) starts two processes, cmd.exe
+ # and the command. The Popen object represents the cmd.exe process, so
+ # calling Popen.kill() does not terminate the command.
+ # This function uses process group to ensure command termination.
+ proc = utils.start_standing_subprocess(cmd)
+ result = []
+
+ def WaitForProcess():
+ out, err = proc.communicate()
+ result.append((out, err, proc.returncode))
+
+ wait_thread = threading.Thread(target=WaitForProcess)
+ wait_thread.daemon = True
+ wait_thread.start()
+ try:
+ wait_thread.join(timeout)
+ finally:
+ if proc.poll() is None:
+ utils.kill_process_group(proc)
+ wait_thread.join()
+
+ if len(result) != 1:
+ logging.error("Unexpected command result: %s", result)
+ return "", "", proc.returncode
+ return result[0]
+
+
def RunCommand(command):
"""Runs a unix command and stashes the result.
@@ -40,19 +83,26 @@
return proc.returncode
-def ExecuteOneShellCommand(cmd):
- """Execute one shell command and return (stdout, stderr, exit_code).
+def ExecuteOneShellCommand(cmd, timeout=None):
+ """Executes one shell command and returns (stdout, stderr, exit_code).
Args:
- cmd: string, a shell command
+ cmd: string, a shell command.
+ timeout: float, timeout in seconds.
Returns:
- tuple(string, string, int), containing stdout, stderr, exit_code of the shell command
+ tuple(string, string, int), containing stdout, stderr, exit_code of
+ the shell command.
+ If timeout, exit_code is -15 on Unix; -1073741510 on Windows.
"""
- p = subprocess.Popen(
- str(cmd), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = p.communicate()
- return (stdout, stderr, p.returncode)
+ if timeout is None:
+ p = subprocess.Popen(
+ str(cmd), shell=True,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ return (stdout, stderr, p.returncode)
+ else:
+ return _ExecuteOneShellCommandWithTimeout(str(cmd), timeout)
def ExecuteShellCommand(cmd):
diff --git a/utils/python/common/filter_utils.py b/utils/python/common/filter_utils.py
index 750f7b2..df5121e 100644
--- a/utils/python/common/filter_utils.py
+++ b/utils/python/common/filter_utils.py
@@ -14,9 +14,11 @@
# limitations under the License.
#
+import copy
import logging
import re
from sre_constants import error as regex_error
+import types
from vts.runners.host import const
from vts.utils.python.common import list_utils
@@ -36,8 +38,14 @@
If a filter item contains bitness suffix, only test name with that tag
will be included in output.
- Otherwise, both 32bit and 64bit suffix will be paired to the test name
- in output list.
+ Otherwise, 2 more item with 32bit and 64bit suffix will be added to the output list.
+
+ This method removes duplicated item while keeping item order before returning output.
+
+ Examples of input -> output are:
+ [a_32bit] -> [a_32bit]
+ [a] -> [a, a_32bit, a_64bit]
+ [a_32bit, a] -> [a_32bit, a, a_64bit]
Args:
input_list: list of string, the list to expand
@@ -55,6 +63,50 @@
return list_utils.DeduplicateKeepOrder(result)
+def ExpandAppendix(input_list, appendix_list, filter_pattern):
+ '''Expand each item in input_list with appendix in the appendix_list
+
+ For each item in input_list, expand it to N items (N=size of appendix_list)
+ by attaching it with each appendix form appendix_list.
+ Note, for items end with bitness info (e.g 32bit/63bit/_32bit/_64bit),
+ attach the appendix before the bitness info. (This is to make sure the
+ bitness info is always at the end of each item since the system rely on this
+ assumption to check the bitness info)
+ There are two cases when an item will not be expanded: 1) it is a Regex
+ filter item and 2) it has the pattern described by filter_pattern.
+
+ Examples of input -> output are:
+ [a] [_default] -> [a_default]
+ [a, b] [_default] -> [a_default, b_default]
+ [a] [_default, _test] -> [a_default, a_test]
+ [a, b_32bit] [_default, _test]
+ -> [a_default, a_test, b_default_32bit, b_test_32bit]
+
+ Args:
+ input_list: list of string, the list to expand
+ appendix_list: list of string, the appendix to be append.
+ filter_pattern: string, a Regex pattern to filter out the items that
+ should not expand.
+
+ Returns:
+ A list of string with expanded result.
+ '''
+ result = []
+ for item in input_list:
+ if IsRegexFilter(item) or re.compile(filter_pattern).match(item):
+ result.append(item)
+ continue
+ pos = len(item)
+ if (item.endswith(const.SUFFIX_32BIT) or
+ item.endswith(const.SUFFIX_64BIT)):
+ pos = len(item) - len(const.SUFFIX_32BIT)
+ if item[pos - 1] == "_":
+ pos = pos - 1
+ for appendix in appendix_list:
+ result.append(item[:pos] + appendix + item[pos:])
+ return result
+
+
def SplitFilterList(input_list):
'''Split filter items into exact and regex lists.
@@ -74,7 +126,7 @@
exact = []
regex = []
for item in input_list:
- if item.startswith(REGEX_PREFIX) and item.endswith(REGEX_SUFFIX):
+ if IsRegexFilter(item):
regex_item = item[len(REGEX_PREFIX):-len(REGEX_SUFFIX)]
try:
re.compile(regex_item)
@@ -134,6 +186,18 @@
return False
+def IsRegexFilter(item):
+ '''Checks whether the given item is a regex filter.
+
+ Args:
+ item: string, given string
+
+ Returns:
+ bool: true if the given item is a regex filter.
+ '''
+ return item.startswith(REGEX_PREFIX) and item.endswith(REGEX_SUFFIX)
+
+
class Filter(object):
'''A class to hold test filter rules and filter test names.
@@ -168,6 +232,10 @@
module name prefix matching
module_name: string, test module name for auto module name prefix
matching
+ expand_bitness: bool, whether to append bitness to filter items.
+ Default is False. When set to True, bitness will
+ be added to test name for filtering process, but
+ the original filter list will not be changed.
'''
include_filter_exact = []
include_filter_regex = []
@@ -177,18 +245,16 @@
def __init__(self,
include_filter=[],
exclude_filter=[],
- enable_regex=False,
+ enable_regex=True,
exclude_over_include=None,
enable_negative_pattern=True,
enable_module_name_prefix_matching=False,
- module_name=None):
+ module_name=None,
+ expand_bitness=False):
self.enable_regex = enable_regex
+ self.expand_bitness = expand_bitness
self.enable_negative_pattern = enable_negative_pattern
- if self.enable_negative_pattern:
- include_filter, include_filter_negative = SplitNegativePattern(
- include_filter)
- exclude_filter.extend(include_filter_negative)
self.include_filter = include_filter
self.exclude_filter = exclude_filter
if exclude_over_include is None:
@@ -197,6 +263,8 @@
self.enable_module_name_prefix_matching = enable_module_name_prefix_matching
self.module_name = module_name
+ # @Deprecated. Use expand_bitness parameter in construction method instead.
+ # This method will be removed after all legacy usage has been cleaned up
def ExpandBitness(self):
'''Expand bitness from filter.
@@ -206,14 +274,43 @@
'''
self.include_filter_exact = ExpandBitness(self.include_filter_exact)
self.exclude_filter_exact = ExpandBitness(self.exclude_filter_exact)
+ self.expand_bitness = True
+
+ def IsIncludeFilterEmpty(self):
+ '''Check whether actual include filter is specified.
+
+ Since the input include filter may contain negative patterns,
+ checking self.include_filter is not always correct.
+
+ This method checks include_filter_exact and include_filter_regex.
+ '''
+ return not self.include_filter_exact and not self.include_filter_regex
+
+ def ExpandAppendix(self, appendix_list, filter_pattern):
+ '''Expand filter with appendix from appendix_list.
+
+ Reset both include_filter and exclude_filter by expanding the filters
+ with appendix in appendix_list.
+
+ Args:
+ appendix_list: list of string to be append to the filters.
+ filter_pattern: string, a Regex pattern to filter out the items that
+ should not be expanded.
+ '''
+ self.include_filter = ExpandAppendix(self.include_filter,
+ appendix_list, filter_pattern)
+ self.exclude_filter = ExpandAppendix(self.exclude_filter,
+ appendix_list, filter_pattern)
def Filter(self, item):
'''Filter a given string using the internal filters.
Rule:
- If include_filter is empty, only exclude_filter is checked
- for non-passing. Otherwise, only include_filter is checked
- (include_filter overrides exclude_filter).
+ By default, include_filter overrides exclude_filter. This means:
+ If include_filter is empty, only exclude_filter is checked.
+ Otherwise, only include_filter is checked
+ If exclude_over_include is set to True, exclude filter will first
+ be checked.
Args:
item: string, the string for filter check
@@ -221,15 +318,19 @@
Returns:
bool. True if it passed the filter; False otherwise
'''
- if not self.exclude_over_include:
- return (self.IsInIncludeFilter(item) if self.include_filter else
- not self.IsInExcludeFilter(item))
+ if self.exclude_over_include:
+ if self.IsInExcludeFilter(item):
+ return False
- if self.IsInExcludeFilter(item):
- return False
+ if not self.IsIncludeFilterEmpty():
+ return self.IsInIncludeFilter(item)
- if self.include_filter:
- return self.IsInIncludeFilter(item)
+ return True
+ else:
+ if not self.IsIncludeFilterEmpty():
+ return self.IsInIncludeFilter(item)
+
+ return not self.IsInExcludeFilter(item)
def IsInIncludeFilter(self, item):
'''Check if item is in include filter.
@@ -317,34 +418,131 @@
@property
def include_filter(self):
- '''Getter method for include_filter'''
+ '''Getter method for include_filter.
+
+ Use this method to print include_filter only.
+
+ If the items needed to be added, use add_to_exclude_filter method.
+
+ E.g.
+ self.add_to_exclude_filter('pattern1')
+
+ If the filter needs to be modified without using add_to_exclude_filter,
+ call refresh_filter() after modification. Otherwise, the change will
+ not take effect.
+
+ E.g.
+ Get and modify filter:
+ filter = Filter()
+ filter.include_filter.append('pattern1')
+ Refresh the filter:
+ filter.refresh_filter()
+ '''
return getattr(self, _INCLUDE_FILTER, [])
@include_filter.setter
def include_filter(self, include_filter):
'''Setter method for include_filter'''
setattr(self, _INCLUDE_FILTER, include_filter)
- if self.enable_regex:
- self.include_filter_exact, self.include_filter_regex = SplitFilterList(
- include_filter)
- else:
- self.include_filter_exact = include_filter
+ self.refresh_filter()
@property
def exclude_filter(self):
- '''Getter method for exclude_filter'''
+ '''Getter method for exclude_filter.
+
+ Use this method to print exclude_filter only.
+
+ If the items needed to be added, use add_to_exclude_filter method.
+
+ E.g.
+ self.add_to_exclude_filter('pattern1')
+
+ If the filter needs to be modified without using add_to_exclude_filter,
+ call refresh_filter() after modification. Otherwise, the change will
+ not take effect.
+
+ E.g.
+ Get and modify filter:
+ filter = Filter()
+ filter.exclude_filter.append('pattern1')
+ Refresh the filter:
+ filter.refresh_filter()
+ '''
return getattr(self, _EXCLUDE_FILTER, [])
@exclude_filter.setter
def exclude_filter(self, exclude_filter):
'''Setter method for exclude_filter'''
setattr(self, _EXCLUDE_FILTER, exclude_filter)
+ self.refresh_filter()
+
+ def add_to_include_filter(self, pattern, auto_refresh=True):
+ '''Add an item to include_filter.
+
+ Args:
+ pattern: string or list of string. Item(s) to add
+ auto_refresh: bool, whether to automatically call refresh_filter().
+ Default is True. Use False only if a large number of
+ items are added one by one in a sequence call.
+ In that case, call refresh_filter() at the end of the
+ sequence.
+ '''
+ if not isinstance(pattern, types.ListType):
+ pattern = [pattern]
+
+ self.include_filter.extend(pattern)
+
+ if auto_refresh:
+ self.refresh_filter()
+
+ def add_to_exclude_filter(self, pattern, auto_refresh=True):
+ '''Add an item to exclude_filter.
+
+ Args:
+ pattern: string or list of string. Item(s) to add
+ auto_refresh: bool, whether to automatically call refresh_filter().
+ Default is True. Use False only if a large number of
+ items are added one by one in a sequence call.
+ In that case, call refresh_filter() at the end of the
+ sequence.
+ '''
+ if not isinstance(pattern, types.ListType):
+ pattern = [pattern]
+
+ self.exclude_filter.extend(pattern)
+
+ if auto_refresh:
+ self.refresh_filter()
+
+ def refresh_filter(self):
+ '''Process the filter patterns.
+
+ This method splits filter into exact and regex patterns.
+ Bitness will also be appended if expand_bitness is True.
+ '''
+ include_filter = copy.copy(self.include_filter)
+ exclude_filter = copy.copy(self.exclude_filter)
+
+ if self.enable_negative_pattern:
+ include_filter, include_filter_negative = SplitNegativePattern(
+ include_filter)
+ exclude_filter.extend(include_filter_negative)
+
if self.enable_regex:
+ self.include_filter_exact, self.include_filter_regex = SplitFilterList(
+ include_filter)
self.exclude_filter_exact, self.exclude_filter_regex = SplitFilterList(
exclude_filter)
else:
+ self.include_filter_exact = include_filter
self.exclude_filter_exact = exclude_filter
+ if self.expand_bitness:
+ self.include_filter_exact = ExpandBitness(
+ self.include_filter_exact)
+ self.exclude_filter_exact = ExpandBitness(
+ self.exclude_filter_exact)
+
def __str__(self):
return ('Filter:\nenable_regex: {enable_regex}\n'
'enable_negative_pattern: {enable_negative_pattern}\n'
@@ -356,7 +554,8 @@
'include_filter_exact: {include_filter_exact}\n'
'include_filter_regex: {include_filter_regex}\n'
'exclude_filter_exact: {exclude_filter_exact}\n'
- 'exclude_filter_regex: {exclude_filter_regex}'.format(
+ 'exclude_filter_regex: {exclude_filter_regex}\n'
+ 'expand_bitness: {expand_bitness}'.format(
enable_regex=self.enable_regex,
enable_negative_pattern=self.enable_negative_pattern,
enable_module_name_prefix_matching=
@@ -367,4 +566,5 @@
include_filter_exact=self.include_filter_exact,
include_filter_regex=self.include_filter_regex,
exclude_filter_exact=self.exclude_filter_exact,
- exclude_filter_regex=self.exclude_filter_regex))
+ exclude_filter_regex=self.exclude_filter_regex,
+ expand_bitness=self.expand_bitness))
diff --git a/utils/python/controllers/adb.py b/utils/python/controllers/adb.py
index aaa2936..faea786 100644
--- a/utils/python/controllers/adb.py
+++ b/utils/python/controllers/adb.py
@@ -22,6 +22,7 @@
import time
from vts.runners.host import const
+from vts.utils.python.common import cmd_utils
class AdbError(Exception):
@@ -123,7 +124,7 @@
self.adb_str = "adb"
self.log = log
- def _exec_cmd(self, cmd, no_except=False):
+ def _exec_cmd(self, cmd, no_except=False, timeout=None):
"""Executes adb commands in a new shell.
This is specific to executing adb binary because stderr is not a good
@@ -132,6 +133,8 @@
Args:
cmd: string, the adb command to execute.
no_except: bool, controls whether exception can be thrown.
+ timeout: float, timeout in seconds. If the command times out, the
+ exit code is not 0.
Returns:
The output of the adb command run if the exit code is 0 and if
@@ -142,12 +145,7 @@
AdbError if the adb command exit code is not 0 and exceptions are
allowed.
"""
- proc = subprocess.Popen(cmd,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- shell=True)
- (out, err) = proc.communicate()
- ret = proc.returncode
+ out, err, ret = cmd_utils.ExecuteOneShellCommand(cmd, timeout)
logging.debug("cmd: %s, stdout: %s, stderr: %s, ret: %s", cmd, out,
err, ret)
if no_except:
@@ -186,6 +184,6 @@
clean_name = name.replace('_', '-')
arg_str = ' '.join(str(elem) for elem in args)
return self._exec_cmd(' '.join((self.adb_str, clean_name, arg_str)),
- kwargs)
+ **kwargs)
return adb_call
diff --git a/utils/python/controllers/android_device.py b/utils/python/controllers/android_device.py
index 1983bcc..fe797a9 100644
--- a/utils/python/controllers/android_device.py
+++ b/utils/python/controllers/android_device.py
@@ -24,6 +24,7 @@
import time
import traceback
+from vts.runners.host import asserts
from vts.runners.host import errors
from vts.runners.host import keys
from vts.runners.host import logger as vts_logger
@@ -33,6 +34,7 @@
from vts.utils.python.controllers import adb
from vts.utils.python.controllers import event_dispatcher
from vts.utils.python.controllers import fastboot
+from vts.utils.python.controllers import customflasher
from vts.utils.python.controllers import sl4a_client
from vts.utils.python.mirror import mirror_tracker
@@ -57,6 +59,10 @@
# Max number of attempts that the client can make to connect to the agent
MAX_AGENT_CONNECT_RETRIES = 10
+# The argument to fastboot getvar command to determine whether the device has
+# the slot for vbmeta.img
+_FASTBOOT_VAR_HAS_VBMETA = "has-slot:vbmeta"
+
class AndroidDeviceError(signals.ControllerError):
pass
@@ -339,6 +345,11 @@
adb: An AdbProxy object used for interacting with the device via adb.
fastboot: A FastbootProxy object used for interacting with the device
via fastboot.
+ customflasher: A CustomFlasherProxy object used for interacting with
+ the device via user defined flashing binary.
+ enable_vts_agent: bool, whether VTS agent is used.
+ enable_sl4a: bool, whether SL4A is used.
+ enable_sl4a_ed: bool, whether SL4A Event Dispatcher is used.
host_command_port: the host-side port for runner to agent sessions
(to send commands and receive responses).
host_callback_port: the host-side port for agent to runner sessions
@@ -368,6 +379,7 @@
self.vts_agent_process = None
self.adb = adb.AdbProxy(serial)
self.fastboot = fastboot.FastbootProxy(serial)
+ self.customflasher = customflasher.CustomFlasherProxy(serial)
if not self.isBootloaderMode:
self.rootAdb()
self.host_command_port = None
@@ -386,6 +398,14 @@
def __del__(self):
self.cleanUp()
+ def SetCustomFlasherPath(self, customflasher_path):
+ """Sets customflasher path to use to flash the device.
+
+ Args:
+ customflasher_path: string, path to user-spcified flash binary.
+ """
+ self.customflasher.SetCustomBinaryPath(customflasher_path)
+
def cleanUp(self):
"""Cleans up the AndroidDevice object and releases any resources it
claimed.
@@ -399,6 +419,17 @@
self.sl4a_host_port = None
@property
+ def hasVbmetaSlot(self):
+ """True if the device has the slot for vbmeta."""
+ if not self.isBootloaderMode:
+ self.adb.reboot_bootloader()
+
+ out = self.fastboot.getvar(_FASTBOOT_VAR_HAS_VBMETA).strip()
+ if ("%s: yes" % _FASTBOOT_VAR_HAS_VBMETA) in out:
+ return True
+ return False
+
+ @property
def isBootloaderMode(self):
"""True if the device is in bootloader mode."""
return self.serial in list_fastboot_devices()
@@ -443,6 +474,58 @@
return model
@property
+ def first_api_level(self):
+ """Gets the API level that the device was initially launched with."""
+ return self.getProp("ro.product.first_api_level")
+
+ @property
+ def sdk_version(self):
+ """Gets the SDK version that the device is running with."""
+ return self.getProp("ro.build.version.sdk")
+
+ def getLaunchApiLevel(self, strict=True):
+ """Gets the API level that the device was initially launched with.
+
+ This method reads ro.product.first_api_level from the device. If the
+ value is 0, it then reads ro.build.version.sdk.
+
+ Args:
+ strict: A boolean, whether to fail the test if the property is
+ not an integer or not defined.
+
+ Returns:
+ An integer, the API level.
+ 0 if the property is not an integer or not defined.
+ """
+ level_str = self.first_api_level
+ try:
+ level = int(level_str)
+ except ValueError:
+ error_msg = "Cannot parse first_api_level: %s" % level_str
+ if strict:
+ asserts.fail(error_msg)
+ logging.error(error_msg)
+ return 0
+
+ if level != 0:
+ return level
+
+ level_str = self.sdk_version
+ try:
+ return int(level_str)
+ except ValueError:
+ error_msg = "Cannot parse version.sdk: %s" % level_str
+ if strict:
+ asserts.fail(error_msg)
+ logging.error(error_msg)
+ return 0
+
+ @property
+ def vndk_version(self):
+ """Gets the VNDK version that the vendor partition is using."""
+ return self.getProp("ro.vndk.version")
+
+ @property
def cpu_abi(self):
"""CPU ABI (Application Binary Interface) of the device."""
out = self.getProp("ro.product.cpu.abi")
@@ -630,7 +713,6 @@
self.adb.bugreport(" > %s" % full_out_path)
self.log.info("Bugreport for %s taken at %s", test_name, full_out_path)
- @utils.timeout(15 * 60)
def waitForBootCompletion(self, timeout=900):
"""Waits for Android framework to broadcast ACTION_BOOT_COMPLETED.
@@ -643,26 +725,35 @@
"""
start = time.time()
try:
- self.adb.wait_for_device()
+ self.adb.wait_for_device(timeout=timeout)
except adb.AdbError as e:
# adb wait-for-device is not always possible in the lab
logging.exception(e)
return False
- while not self.hasBooted():
+ while not self.isBootCompleted():
if time.time() - start >= timeout:
logging.error("Timeout while waiting for boot completion.")
return False
- time.sleep(3)
+ time.sleep(1)
return True
+ # Deprecated. Use isBootCompleted instead
def hasBooted(self):
"""Checks whether the device has booted.
Returns:
True if booted, False otherwise.
"""
+ return self.isBootCompleted()
+
+ def isBootCompleted(self):
+ """Checks whether the device has booted.
+
+ Returns:
+ True if booted, False otherwise.
+ """
try:
completed = self.getProp("sys.boot_completed")
if completed == '1':
@@ -670,23 +761,117 @@
except adb.AdbError:
# adb shell calls may fail during certain period of booting
# process, which is normal. Ignoring these errors.
+ pass
+
+ return False
+
+ def isFrameworkRunning(self, check_boot_completion=True):
+ """Checks whether Android framework is started.
+
+ This function will first check boot_completed prop. If boot_completed
+ is 0, then return False meaning framework not started.
+ Then this function will check whether system_server process is running.
+ If yes, then return True meaning framework is started.
+
+ The assumption here is if prop boot_completed is 0 then framework
+ is stopped.
+
+ There are still cases which can make this function return wrong
+ result. For example, boot_completed is set to 0 manually without
+ without stopping framework.
+
+ Args:
+ check_boot_completion: bool, whether to check boot completion
+ before checking framework status. This is an
+ important step for ensuring framework is
+ started. Under most circumstances this value
+ should be set to True.
+ Default True.
+
+ Returns:
+ True if started, False otherwise.
+ """
+ # First, check whether boot has completed.
+ if check_boot_completion and not self.isBootCompleted():
return False
- def start(self):
- """Starts Android runtime and waits for ACTION_BOOT_COMPLETED."""
- logging.info("starting Android Runtime")
- self.adb.shell("start")
- if self.waitForBootCompletion(60 * 2):
- logging.info("Android Runtime started")
- else:
- logging.error("Failed to start Android Runtime.")
+ cmd = 'ps -g system | grep system_server'
+ res = self.adb.shell(cmd)
- def stop(self):
- """Stops Android runtime."""
- logging.info("stopping Android Runtime")
+ return 'system_server' in res
+
+ def startFramework(self,
+ wait_for_completion=True,
+ wait_for_completion_timeout=120):
+ """Starts Android framework.
+
+ By default this function will wait for framework starting process to
+ finish before returning.
+
+ Args:
+ wait_for_completion: bool, whether to wait for framework to complete
+ starting. Default: True
+ wait_for_completion_timeout: timeout in seconds for waiting framework
+ to start. Default: 2 minutes
+
+ Returns:
+ bool, True if framework start success. False otherwise.
+ """
+ logging.info("starting Android framework")
+ self.adb.shell("start")
+
+ if wait_for_completion:
+ return self.waitForFrameworkStartComplete(wait_for_completion_timeout)
+
+ return True
+
+ def start(self):
+ """Starts Android framework and waits for ACTION_BOOT_COMPLETED.
+
+ Returns:
+ bool, True if framework start success. False otherwise.
+ """
+ return self.startFramework()
+
+ def stopFramework(self):
+ """Stops Android framework.
+
+ Method will block until stop is complete.
+ """
+ logging.info("stopping Android framework")
self.adb.shell("stop")
self.setProp("sys.boot_completed", 0)
- logging.info("Android Runtime stopped")
+ logging.info("Android framework stopped")
+
+ def stop(self):
+ """Stops Android framework.
+
+ Method will block until stop is complete.
+ """
+ self.stopFramework()
+
+ def waitForFrameworkStartComplete(self, timeout_secs=120):
+ """Wait for Android framework to complete starting.
+
+ Args:
+ timeout_secs: int, seconds to wait for boot completion. Default is
+ 2 minutes.
+
+ Returns:
+ bool, True if framework is started. False otherwise or timeout
+ """
+ start = time.time()
+
+ # First, wait for boot completion and checks
+ self.waitForBootCompletion(timeout_secs)
+
+ while not self.isFrameworkRunning(check_boot_completion=False):
+ if time.time() - start >= timeout_secs:
+ logging.error("Timeout while waiting for framework to start.")
+ return False
+ time.sleep(1)
+
+ return True
def setProp(self, name, value):
"""Calls setprop shell command.
@@ -775,15 +960,15 @@
2. Start VtsAgent and create HalMirror unless disabled in config.
3. If enabled in config, start sl4a service and create sl4a clients.
"""
- enable_vts_agent = getattr(self, "enable_vts_agent", True)
- enable_sl4a = getattr(self, "enable_sl4a", False)
- enable_sl4a_ed = getattr(self, "enable_sl4a_ed", False)
+ self.enable_vts_agent = getattr(self, "enable_vts_agent", True)
+ self.enable_sl4a = getattr(self, "enable_sl4a", False)
+ self.enable_sl4a_ed = getattr(self, "enable_sl4a_ed", False)
try:
self.startAdbLogcat()
except:
self.log.exception("Failed to start adb logcat!")
raise
- if enable_vts_agent:
+ if self.enable_vts_agent:
self.startVtsAgent()
self.device_command_port = int(
self.adb.shell("cat /data/local/tmp/vts_tcp_server_port"))
@@ -792,14 +977,14 @@
self.host_command_port = adb.get_available_host_port()
self.adb.tcp_forward(self.host_command_port,
self.device_command_port)
- self.hal = mirror_tracker.MirrorTracker(self.host_command_port,
- self.host_callback_port, True)
+ self.hal = mirror_tracker.MirrorTracker(
+ self.host_command_port, self.host_callback_port, True)
self.lib = mirror_tracker.MirrorTracker(self.host_command_port)
self.shell = mirror_tracker.MirrorTracker(
host_command_port=self.host_command_port, adb=self.adb)
- if enable_sl4a:
+ if self.enable_sl4a:
try:
- self.startSl4aClient(enable_sl4a_ed)
+ self.startSl4aClient(eself.enable_sl4a_ed)
except Exception as e:
self.log.exception("Failed to start SL4A!")
self.log.exception(e)
@@ -810,9 +995,11 @@
"""
if self.adb_logcat_process:
self.stopAdbLogcat()
- self._terminateAllSl4aSessions()
- self.stopSl4a()
- self.stopVtsAgent()
+ if getattr(self, "enable_sl4a", False):
+ self._terminateAllSl4aSessions()
+ self.stopSl4a()
+ if getattr(self, "enable_vts_agent", True):
+ self.stopVtsAgent()
if self.hal:
self.hal.CleanUp()
@@ -857,22 +1044,20 @@
bits = ['64', '32'] if self.is64Bit else ['32']
for bitness in bits:
vts_agent_log_path = os.path.join(self.log_path,
- "vts_agent_" + bitness + ".log")
- cmd = (
- 'adb -s {s} shell LD_LIBRARY_PATH={path}/{bitness} '
- '{path}/{bitness}/vts_hal_agent{bitness} '
- '--hal_driver_path_32={path}/32/vts_hal_driver32 '
- '--hal_driver_path_64={path}/64/vts_hal_driver64 '
- '--spec_dir={path}/spec '
- '--shell_driver_path_32={path}/32/vts_shell_driver32 '
- '--shell_driver_path_64={path}/64/vts_shell_driver64 '
- '-l {severity} >> {log} 2>&1'
- ).format(
- s=self.serial,
- bitness=bitness,
- path=DEFAULT_AGENT_BASE_DIR,
- log=vts_agent_log_path,
- severity=log_severity)
+ 'vts_agent_%s_%s.log' % (bitness, self.serial))
+ cmd = ('adb -s {s} shell LD_LIBRARY_PATH={path}/{bitness} '
+ '{path}/{bitness}/vts_hal_agent{bitness} '
+ '--hal_driver_path_32={path}/32/vts_hal_driver32 '
+ '--hal_driver_path_64={path}/64/vts_hal_driver64 '
+ '--spec_dir={path}/spec '
+ '--shell_driver_path_32={path}/32/vts_shell_driver32 '
+ '--shell_driver_path_64={path}/64/vts_shell_driver64 '
+ '-l {severity} >> {log} 2>&1').format(
+ s=self.serial,
+ bitness=bitness,
+ path=DEFAULT_AGENT_BASE_DIR,
+ log=vts_agent_log_path,
+ severity=log_severity)
try:
self.vts_agent_process = utils.start_standing_subprocess(
cmd, check_health_delay=1)
@@ -964,8 +1149,7 @@
def stopSl4a(self):
"""Stops an SL4A apk on a target device."""
try:
- self.adb.shell(
- "am force-stop %s" % SL4A_APK_NAME, ignore_status=True)
+ self.adb.shell("am force-stop %s" % SL4A_APK_NAME)
except adb.AdbError as e:
self.log.warn("Fail to stop package %s: %s", SL4A_APK_NAME, e)
@@ -985,9 +1169,7 @@
"""
for cmd in ("ps -A", "ps"):
try:
- out = self.adb.shell(
- '%s | grep "S %s"' % (cmd, package_name),
- ignore_status=True)
+ out = self.adb.shell('%s | grep "S %s"' % (cmd, package_name))
if package_name not in out:
continue
try:
@@ -1235,3 +1417,7 @@
"""
msg = "[AndroidDevice|%s] %s" % (self.extra["serial"], msg)
return (msg, kwargs)
+
+ def warn(self, msg, *args, **kwargs):
+ """Function call warper for warn() to warning()."""
+ super(AndroidDeviceLoggerAdapter, self).warning(msg, *args, **kwargs)
diff --git a/utils/python/controllers/android_device_test.py b/utils/python/controllers/android_device_test.py
new file mode 100644
index 0000000..cbe6711
--- /dev/null
+++ b/utils/python/controllers/android_device_test.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 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.
+#
+
+import unittest
+import vts.utils.python.controllers.android_device as android_device
+
+
+class AndroidDeviceTest(unittest.TestCase):
+ '''Test methods inside android_device module.'''
+
+ def setUp(self):
+ """SetUp tasks"""
+ available_serials = android_device.list_adb_devices()
+ self.assertGreater(len(available_serials), 0, 'no device available.')
+ self.dut = android_device.AndroidDevice(available_serials[0])
+
+ def tearDown(self):
+ """TearDown tasks"""
+ pass
+
+ def testFrameworkStatusChange(self):
+ '''Test AndroidDevice class startRuntime related functions.'''
+ err_msg = 'Runtime status is wrong'
+ print('step 1 start runtime')
+ self.dut.start()
+
+ print('step 2 check runtime status')
+ self.assertTrue(self.dut.isFrameworkRunning(), err_msg)
+
+ print('step 3 stop runtime')
+ self.dut.stop()
+
+ print('step 4 check runtime status')
+ self.assertFalse(self.dut.isFrameworkRunning(), err_msg)
+
+ print('step 5 start runtime')
+ self.dut.start()
+
+ print('step 6 check runtime status')
+ self.assertTrue(self.dut.isFrameworkRunning(), err_msg)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/utils/python/controllers/customflasher.py b/utils/python/controllers/customflasher.py
new file mode 100644
index 0000000..019c352
--- /dev/null
+++ b/utils/python/controllers/customflasher.py
@@ -0,0 +1,92 @@
+#
+# Copyright (C) 2017 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.
+#
+
+from vts.utils.python.common import cmd_utils
+
+
+class CustomFlasherError(Exception):
+ """Raised when there is an error in operations."""
+
+
+class CustomFlasherProxy():
+ """Proxy class for custom flasher tool.
+
+ Attributes:
+ serial: string containing devices serial.
+ customflasher_str: string containing path to the custom flasher.
+
+ For syntactic reasons, the '-' in commands need to be replaced
+ with '_'. Can directly execute commands on an object:
+ >> fb = Proxy(<serial>)
+ >> fb.devices() # will return the console output of "devices".
+ """
+
+ def __init__(self, serial=None):
+ """Initializes custom flasher proxy."""
+ self.serial = serial
+ self.customflasher_str = None
+
+ def SetCustomBinaryPath(self, customflasher_path=""):
+ """Sets path to flasher binary.
+
+ Args:
+ customflasher_path: string, path to custom flasher binary.
+ """
+ self.customflasher_str = customflasher_path
+
+ def ExecCustomFlasherCmd(self, name, arg_str):
+ """Passes joined shell command line to ExecuteOneShellCommand().
+
+ Args:
+ name: stirng, command to pass to custom flasher binary.
+ arg_str: string, contains additional argument(s).
+
+ Returns:
+ contents of stdout if command line returned without error;
+ stderr otherwise.
+ """
+ out, err, error_code = cmd_utils.ExecuteOneShellCommand(
+ ' '.join((self.customflasher_str, name, arg_str)))
+ if error_code:
+ return err
+ return out
+
+ def __getattr__(self, name):
+ """Passes invoked function's name to ExecCustomFlasherCmd().
+
+ Args:
+ name: stirng, 'name' of invoked method.
+
+ Returns:
+ output string from ExecCustomFlasherCmd().
+ """
+
+ def customflasher_call(*args):
+ """Joins *args into one string and passes the name and joined args
+ to ExecCustomFlasherCmd().
+
+ Replaces '_' characters in name, so if the invoked method name
+ was "__command", this function could pass "--command"
+ to custom flasher as a command.
+
+ Returns:
+ output string from ExecCustomFlasherCmd().
+ """
+ clean_name = name.replace('_', '-')
+ arg_str = ' '.join(str(elem) for elem in args)
+ return self.ExecCustomFlasherCmd(clean_name, arg_str)
+
+ return customflasher_call
diff --git a/utils/python/controllers/customflasher_test.py b/utils/python/controllers/customflasher_test.py
new file mode 100644
index 0000000..db3e789
--- /dev/null
+++ b/utils/python/controllers/customflasher_test.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 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.
+#
+
+import unittest
+
+from vts.utils.python.controllers import customflasher
+
+
+class CustomFlasherTest(unittest.TestCase):
+ """Tests for CustomFlasher."""
+
+ def testExecCmd(self):
+ """Test for __getattr__().
+
+ Tests if CustomFlasherProxy gets binary path and commands
+ to the binary and passes to cmd_util
+ as one joined shell command line.
+ """
+ flashTool = customflasher.CustomFlasherProxy()
+ flashTool.SetCustomBinaryPath("myBinaryPath")
+ flashTool.__arg("aboutSomething")
+ flashTool.assert_called_with("myBinaryPath --arg", "aboutSomething")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/utils/python/controllers/sl4a_client.py b/utils/python/controllers/sl4a_client.py
index f78086a..f4509af 100644
--- a/utils/python/controllers/sl4a_client.py
+++ b/utils/python/controllers/sl4a_client.py
@@ -101,7 +101,7 @@
adb_proxy: adb.AdbProxy, The adb proxy to use for checking.
"""
adb_proxy.shell(
- 'am force-stop com.googlecode.android_scripting', ignore_status=True)
+ 'am force-stop com.googlecode.android_scripting', no_except=True)
def is_sl4a_installed(adb_proxy):
diff --git a/utils/python/coverage/coverage_report.py b/utils/python/coverage/coverage_report.py
index e1f89ba..c176e5f 100644
--- a/utils/python/coverage/coverage_report.py
+++ b/utils/python/coverage/coverage_report.py
@@ -30,30 +30,37 @@
from vts.utils.python.coverage import gcda_parser
from vts.utils.python.coverage import gcno_parser
+GEN_TAG = "/gen/"
-def GenerateLineCoverageVector(src_file_name, gcno_file_summary):
- """Returns a list of invocation counts for each line in the file.
+def GenerateLineCoverageVector(gcno_file_summary, exclude_paths, coverage_dict):
+ """Process the gcno_file_summary and update the coverage dictionary.
- Parses the GCNO and GCDA file specified to calculate the number of times
- each line in the source file specified by src_file_name was executed.
+ Create a coverage vector for each source file contained in gcno_file_summary
+ and update the corresponding item in coverage_dict.
Args:
- src_file_name: string, the source file name.
gcno_file_summary: FileSummary object after gcno and gcda files have
been parsed.
-
- Returns:
- A list of non-negative integers or -1 representing the number of times
- the i-th line was executed. -1 indicates a line that is not executable.
+ exclude_paths: a list of paths should be ignored in the coverage report.
+ coverage_dict: a dictionary for each source file and its corresponding
+ coverage vector.
"""
- src_lines_counts = []
- covered_line_count = 0
for ident in gcno_file_summary.functions:
func = gcno_file_summary.functions[ident]
- if not src_file_name == func.src_file_name:
- logging.debug("GenerateLineCoverageVector: \"%s\" file is skipped \"%s\"",
- func.src_file_name, src_file_name)
+ file_name = func.src_file_name
+ if GEN_TAG in file_name:
+ logging.debug("Skip generated source file %s.", file_name)
continue
+ skip_file = False
+ for path in exclude_paths:
+ if file_name.startswith(path):
+ skip_file = True
+ break
+ if skip_file:
+ logging.debug("Skip excluded source file %s.", file_name)
+ continue
+
+ src_lines_counts = coverage_dict[file_name] if file_name in coverage_dict else []
for block in func.blocks:
for line in block.lines:
if line > len(src_lines_counts):
@@ -62,11 +69,7 @@
if src_lines_counts[line - 1] < 0:
src_lines_counts[line - 1] = 0
src_lines_counts[line - 1] += block.count
- if block.count > 0:
- covered_line_count += 1
- logging.info("GenerateLineCoverageVector: file %s: %s lines covered",
- src_file_name, str(covered_line_count))
- return src_lines_counts
+ coverage_dict[file_name] = src_lines_counts
def GetCoverageStats(src_lines_counts):
diff --git a/utils/python/coverage/coverage_report_test.py b/utils/python/coverage/coverage_report_test.py
index 030a980..049d84c 100644
--- a/utils/python/coverage/coverage_report_test.py
+++ b/utils/python/coverage/coverage_report_test.py
@@ -48,13 +48,15 @@
Runs GenerateLineCoverageVector on sample file and checks
result.
"""
+ coverage_dict = dict()
+ exclude_paths = []
src_lines_counts = coverage_report.GenerateLineCoverageVector(
- 'sample.c', self.gcno_summary)
- expected = [-1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 2,
+ self.gcno_summary, exclude_paths, coverage_dict)
+ expected = {'sample.c': [-1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 2,
2, 2, -1, 2, -1, 2, 0, -1, 2, -1, -1, 2, 2, 502,
500, -1, -1, 2, -1, 2, -1, -1, -1, 2, -1,
- -1, -1, -1, 2, 2, 2]
- self.assertEqual(src_lines_counts, expected)
+ -1, -1, -1, 2, 2, 2]}
+ self.assertEqual(coverage_dict, expected)
if __name__ == "__main__":
diff --git a/utils/python/coverage/coverage_utils.py b/utils/python/coverage/coverage_utils.py
index a95a10c..d4c3a13 100644
--- a/utils/python/coverage/coverage_utils.py
+++ b/utils/python/coverage/coverage_utils.py
@@ -12,17 +12,20 @@
# 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.
+import argparse
import io
import json
import logging
import os
import shutil
+import sys
import time
import zipfile
from vts.proto import VtsReportMessage_pb2 as ReportMsg
from vts.runners.host import keys
from vts.utils.python.archive import archive_parser
+from vts.utils.python.common import cmd_utils
from vts.utils.python.controllers.adb import AdbError
from vts.utils.python.coverage import coverage_report
from vts.utils.python.coverage import gcda_parser
@@ -33,7 +36,7 @@
FLUSH_PATH_VAR = "GCOV_PREFIX" # environment variable for gcov flush path
TARGET_COVERAGE_PATH = "/data/misc/trace/" # location to flush coverage
-LOCAL_COVERAGE_PATH = "/tmp/vts-test-coverage" # locatino to pull coverage to host
+LOCAL_COVERAGE_PATH = "/tmp/vts-test-coverage" # location to pull coverage to host
# Environment for test process
COVERAGE_TEST_ENV = "GCOV_PREFIX_OVERRIDE=true GCOV_PREFIX=/data/misc/trace/self"
@@ -45,11 +48,13 @@
MODULE_NAME = "module_name"
NAME = "name"
PATH = "path"
+GEN_TAG = "/gen/"
-_BUILD_INFO = 'BUILD_INFO' # name of build info artifact
+_BUILD_INFO = "BUILD_INFO" # name of build info artifact
_GCOV_ZIP = "gcov.zip" # name of gcov artifact zip
-_REPO_DICT = 'repo-dict' # name of dictionary from project to revision in BUILD_INFO
+_REPO_DICT = "repo-dict" # name of dictionary from project to revision in BUILD_INFO
+_CLEAN_TRACE_COMMAND = "rm -rf /data/misc/trace/*"
_FLUSH_COMMAND = (
"GCOV_PREFIX_OVERRIDE=true GCOV_PREFIX=/data/local/tmp/flusher "
"/data/local/tmp/vts_coverage_configure flush")
@@ -77,10 +82,17 @@
_OPTIONAL_PARAMS = [
keys.ConfigKeys.IKEY_MODULES,
keys.ConfigKeys.IKEY_OUTPUT_COVERAGE_REPORT,
- keys.ConfigKeys.IKEY_GLOBAL_COVERAGE
+ keys.ConfigKeys.IKEY_GLOBAL_COVERAGE,
+ keys.ConfigKeys.IKEY_EXCLUDE_COVERAGE_PATH,
+ keys.ConfigKeys.IKEY_COVERAGE_REPORT_PATH,
]
- def __init__(self, user_params, web=None, local_coverage_path=None):
+ _DEFAULT_EXCLUDE_PATHS = [
+ "bionic", "external/libcxx", "system/core", "system/libhidl",
+ "system/libfmq"
+ ]
+
+ def __init__(self, user_params, web=None):
"""Initializes the coverage feature.
Args:
@@ -94,17 +106,18 @@
self._device_resource_dict = {}
self._hal_names = None
- if local_coverage_path:
- self.local_coverage_path = local_coverage_path
- else:
- timestamp_seconds = str(int(time.time() * 1000000))
- self.local_coverage_path = os.path.join(LOCAL_COVERAGE_PATH,
- timestamp_seconds)
- if os.path.exists(self.local_coverage_path):
- logging.info("removing existing coverage path: %s",
- self.local_coverage_path)
- shutil.rmtree(self.local_coverage_path)
- os.makedirs(self.local_coverage_path)
+ timestamp_seconds = str(int(time.time() * 1000000))
+ self.local_coverage_path = os.path.join(LOCAL_COVERAGE_PATH,
+ timestamp_seconds)
+ if os.path.exists(self.local_coverage_path):
+ logging.info("removing existing coverage path: %s",
+ self.local_coverage_path)
+ shutil.rmtree(self.local_coverage_path)
+ os.makedirs(self.local_coverage_path)
+
+ self._coverage_report_dir = getattr(
+ self, keys.ConfigKeys.IKEY_COVERAGE_REPORT_PATH, None)
+
self._coverage_report_file_prefix = ""
self.global_coverage = getattr(
@@ -113,51 +126,76 @@
android_devices = getattr(self,
keys.ConfigKeys.IKEY_ANDROID_DEVICE)
if not isinstance(android_devices, list):
- logging.warn('Android device information not available')
+ logging.warn("Android device information not available.")
self.enabled = False
for device in android_devices:
serial = device.get(keys.ConfigKeys.IKEY_SERIAL)
- coverage_resource_path = device.get(keys.ConfigKeys.IKEY_GCOV_RESOURCES_PATH)
- if not serial or not coverage_resource_path:
- logging.warn('Missing coverage information in device: %s',
- device)
+ coverage_resource_path = device.get(
+ keys.ConfigKeys.IKEY_GCOV_RESOURCES_PATH)
+ if not serial:
+ logging.error("Missing serial information in device: %s",
+ device)
continue
- self._device_resource_dict[str(serial)] = str(coverage_resource_path)
+ if not coverage_resource_path:
+ logging.error("Missing coverage resource path in device: %s",
+ device)
+ continue
+ self._device_resource_dict[str(serial)] = str(
+ coverage_resource_path)
logging.info("Coverage enabled: %s", self.enabled)
- def _ExtractSourceName(self, gcno_summary, file_name):
- """Gets the source name from the GCNO summary object.
+ def _FindGcnoSummary(self, gcda_file_path, gcno_file_parsers):
+ """Find the corresponding gcno summary for given gcda file.
- Gets the original source file name from the FileSummary object describing
- a gcno file using the base filename of the gcno/gcda file.
+ Identify the corresponding gcno summary for given gcda file from a list
+ of gcno files with the same checksum as the gcda file by matching
+ the the gcda file path.
+ Note: if none of the gcno summary contains the source file same as the
+ given gcda_file_path (e.g. when the corresponding source file does not
+ contain any executable codes), just return the last gcno summary in the
+ list as a fall back solution.
Args:
- gcno_summary: a FileSummary object describing a gcno file
- file_name: the base filename (without extensions) of the gcno or gcda file
+ gcda_file_path: the path of gcda file (without extensions).
+ gcno_file_parsers: a list of gcno file parser that has the same
+ chechsum.
Returns:
- The relative path to the original source file corresponding to the
- provided gcno summary. The path is relative to the root of the build.
+ The corresponding gcno summary for given gcda file.
"""
- src_file_path = None
- for key in gcno_summary.functions:
- src_file_path = gcno_summary.functions[key].src_file_name
- src_parts = src_file_path.rsplit(".", 1)
- src_file_name = src_parts[0]
- src_extension = src_parts[1] if len(src_parts) > 1 else None
- if src_extension not in ["c", "cpp", "cc"]:
- logging.debug("Found unsupported file type: %s", src_file_path)
- continue
- if src_file_name.endswith(file_name):
- logging.info("Coverage source file: %s", src_file_path)
- return src_file_path
- return None
+ gcno_summary = None
+ # For each gcno files with the matched checksum, compare the
+ # gcda_file_path to find the corresponding gcno summary.
+ for gcno_file_parser in gcno_file_parsers:
+ try:
+ gcno_summary = gcno_file_parser.Parse()
+ except FileFormatError:
+ logging.error("Error parsing gcno for gcda %s", gcda_file_path)
+ break
+ legacy_build = "soong/.intermediates" not in gcda_file_path
+ for key in gcno_summary.functions:
+ src_file_path = gcno_summary.functions[key].src_file_name
+ src_file_name = src_file_path.rsplit(".", 1)[0]
+ # If build with legacy compile system, compare only the base
+ # source file name. Otherwise, compare the full source file name
+ # (with path info).
+ if legacy_build:
+ base_src_file_name = os.path.basename(src_file_name)
+ if gcda_file_path.endswith(base_src_file_name):
+ return gcno_summary
+ else:
+ if gcda_file_path.endswith(src_file_name):
+ return gcno_summary
+ # If no gcno file matched with the gcda_file_name, return the last
+ # gcno summary as a fall back solution.
+ return gcno_summary
def _GetChecksumGcnoDict(self, cov_zip):
"""Generates a dictionary from gcno checksum to GCNOParser object.
Processes the gcnodir files in the zip file to produce a mapping from gcno
checksum to the GCNOParser object wrapping the gcno content.
+ Note there might be multiple gcno files corresponds to the same checksum.
Args:
cov_zip: the zip file containing gcnodir files from the device build
@@ -181,15 +219,18 @@
continue
for gcno_file_path in archive.files:
- file_name_path = gcno_file_path.rsplit(".", 1)[0]
- file_name = os.path.basename(file_name_path)
gcno_stream = io.BytesIO(archive.files[gcno_file_path])
gcno_file_parser = gcno_parser.GCNOParser(gcno_stream)
- checksum_gcno_dict[
- gcno_file_parser.checksum] = gcno_file_parser
+ if gcno_file_parser.checksum in checksum_gcno_dict:
+ checksum_gcno_dict[gcno_file_parser.checksum].append(
+ gcno_file_parser)
+ else:
+ checksum_gcno_dict[gcno_file_parser.checksum] = [
+ gcno_file_parser
+ ]
return checksum_gcno_dict
- def _ClearTargetGcov(self, dut, path_suffix=None):
+ def _ClearTargetGcov(self, dut, serial, path_suffix=None):
"""Removes gcov data from the device.
Finds and removes all gcda files relative to TARGET_COVERAGE_PATH.
@@ -200,12 +241,9 @@
path = TARGET_COVERAGE_PATH
if path_suffix:
path = path_utils.JoinTargetPath(path, path_suffix)
- try:
- dut.adb.shell("rm -rf %s/*" % TARGET_COVERAGE_PATH)
- except AdbError as e:
- logging.warn('Gcov cleanup error: \"%s\"', e)
+ self._ExecuteOneAdbShellCommand(dut, serial, _CLEAN_TRACE_COMMAND)
- def InitializeDeviceCoverage(self, dut):
+ def InitializeDeviceCoverage(self, dut=None, serial=None):
"""Initializes the device for coverage before tests run.
Flushes, then finds and removes all gcda files under
@@ -214,14 +252,11 @@
Args:
dut: the device under test.
"""
- try:
- dut.adb.shell(_FLUSH_COMMAND)
- except AdbError as e:
- logging.warn('Command failed: \"%s\"', _FLUSH_COMMAND)
+ self._ExecuteOneAdbShellCommand(dut, serial, _FLUSH_COMMAND)
logging.info("Removing existing gcda files.")
- self._ClearTargetGcov(dut)
+ self._ClearTargetGcov(dut, serial)
- def GetGcdaDict(self, dut):
+ def _GetGcdaDict(self, dut, serial):
"""Retrieves GCDA files from device and creates a dictionary of files.
Find all GCDA files on the target device, copy them to the host using
@@ -237,10 +272,8 @@
logging.info("Creating gcda dictionary")
gcda_dict = {}
logging.info("Storing gcda tmp files to: %s", self.local_coverage_path)
- try:
- dut.adb.shell(_FLUSH_COMMAND)
- except AdbError as e:
- logging.warn('Command failed: \"%s\"', _FLUSH_COMMAND)
+
+ self._ExecuteOneAdbShellCommand(dut, serial, _FLUSH_COMMAND)
gcda_files = set()
if self._hal_names:
@@ -248,16 +281,14 @@
entries = []
try:
entries = dut.adb.shell(
- 'lshal -itp 2> /dev/null | grep -E \"{0}\"'.format(
+ "lshal -itp 2> /dev/null | grep -E \"{0}\"".format(
searchString)).splitlines()
except AdbError as e:
- logging.error('failed to get pid entries')
+ logging.error("failed to get pid entries")
- pids = set([
- pid.strip()
- for pid in map(lambda entry: entry.split()[-1], entries)
- if pid.isdigit()
- ])
+ pids = set(pid.strip()
+ for pid in map(lambda entry: entry.split()[-1], entries)
+ if pid.isdigit())
pids.add(_SP_COVERAGE_PATH)
for pid in pids:
path = path_utils.JoinTargetPath(TARGET_COVERAGE_PATH, pid)
@@ -265,48 +296,62 @@
files = dut.adb.shell("find %s -name \"*.gcda\"" % path)
gcda_files.update(files.split("\n"))
except AdbError as e:
- logging.info('No gcda files found in path: \"%s\"', path)
-
+ logging.info("No gcda files found in path: \"%s\"", path)
else:
- try:
- gcda_files.update(
- dut.adb.shell("find %s -name \"*.gcda\"" %
- TARGET_COVERAGE_PATH).split("\n"))
- except AdbError as e:
- logging.warn('No gcda files found in path: \"%s\"',
- TARGET_COVERAGE_PATH)
+ cmd = ("find %s -name \"*.gcda\"" % TARGET_COVERAGE_PATH)
+ result = self._ExecuteOneAdbShellCommand(dut, serial, cmd)
+ if result:
+ gcda_files.update(result.split("\n"))
for gcda in gcda_files:
if gcda:
basename = os.path.basename(gcda.strip())
file_name = os.path.join(self.local_coverage_path, basename)
- dut.adb.pull("%s %s" % (gcda, file_name))
+ if dut is None:
+ results = cmd_utils.ExecuteShellCommand(
+ "adb -s %s pull %s %s " % (serial, gcda, file_name))
+ if (results[cmd_utils.EXIT_CODE][0]):
+ logging.error(
+ "Fail to execute command: %s. error: %s" %
+ (cmd, str(results[cmd_utils.STDERR][0])))
+ else:
+ dut.adb.pull("%s %s" % (gcda, file_name))
gcda_content = open(file_name, "rb").read()
- gcda_dict[basename] = gcda_content
- self._ClearTargetGcov(dut)
+ gcda_dict[gcda.strip()] = gcda_content
+ self._ClearTargetGcov(dut, serial)
return gcda_dict
- def _OutputCoverageReport(self, isGlobal):
+ def _OutputCoverageReport(self, isGlobal, coverage_report_msg=None):
logging.info("outputing coverage data")
timestamp_seconds = str(int(time.time() * 1000000))
coverage_report_file_name = "coverage_report_" + timestamp_seconds + ".txt"
if self._coverage_report_file_prefix:
coverage_report_file_name = "coverage_report_" + self._coverage_report_file_prefix + ".txt"
- coverage_report_file = os.path.join(self.local_coverage_path,
+ coverage_report_file = None
+ if (self._coverage_report_dir):
+ if not os.path.exists(self._coverage_report_dir):
+ os.makedirs(self._coverage_report_dir)
+ coverage_report_file = os.path.join(self._coverage_report_dir,
coverage_report_file_name)
- logging.info("Storing coverage report to: %s", coverage_report_file)
- coverage_report_msg = ReportMsg.TestReportMessage()
- if isGlobal:
- for c in self.web.report_msg.coverage:
- coverage = coverage_report_msg.coverage.add()
- coverage.CopyFrom(c)
else:
- for c in self.web.current_test_report_msg.coverage:
- coverage = coverage_report_msg.coverage.add()
- coverage.CopyFrom(c)
- with open(coverage_report_file, 'w+') as f:
- f.write(str(coverage_report_msg))
+ coverage_report_file = os.path.join(self.local_coverage_path,
+ coverage_report_file_name)
+
+ logging.info("Storing coverage report to: %s", coverage_report_file)
+ if self.web and self.web.enabled:
+ coverage_report_msg = ReportMsg.TestReportMessage()
+ if isGlobal:
+ for c in self.web.report_msg.coverage:
+ coverage = coverage_report_msg.coverage.add()
+ coverage.CopyFrom(c)
+ else:
+ for c in self.web.current_test_report_msg.coverage:
+ coverage = coverage_report_msg.coverage.add()
+ coverage.CopyFrom(c)
+ if coverage_report_msg is not None:
+ with open(coverage_report_file, "w+") as f:
+ f.write(str(coverage_report_msg))
def _AutoProcess(self, cov_zip, revision_dict, gcda_dict, isGlobal):
"""Process coverage data and appends coverage reports to the report message.
@@ -335,27 +380,35 @@
checksum_gcno_dict = self._GetChecksumGcnoDict(cov_zip)
output_coverage_report = getattr(
self, keys.ConfigKeys.IKEY_OUTPUT_COVERAGE_REPORT, False)
+ exclude_coverage_path = getattr(
+ self, keys.ConfigKeys.IKEY_EXCLUDE_COVERAGE_PATH, [])
+ for idx, path in enumerate(exclude_coverage_path):
+ base_name = os.path.basename(path)
+ if base_name and "." not in base_name:
+ path = path if path.endswith("/") else path + "/"
+ exclude_coverage_path[idx] = path
+ exclude_coverage_path.extend(self._DEFAULT_EXCLUDE_PATHS)
+
+ coverage_dict = dict()
+ coverage_report_message = ReportMsg.TestReportMessage()
for gcda_name in gcda_dict:
+ if GEN_TAG in gcda_name:
+ # skip coverage measurement for intermediate code.
+ logging.warn("Skip for gcda file: %s", gcda_name)
+ continue
+
gcda_stream = io.BytesIO(gcda_dict[gcda_name])
gcda_file_parser = gcda_parser.GCDAParser(gcda_stream)
+ file_name = gcda_name.rsplit(".", 1)[0]
if not gcda_file_parser.checksum in checksum_gcno_dict:
logging.info("No matching gcno file for gcda: %s", gcda_name)
continue
- gcno_file_parser = checksum_gcno_dict[gcda_file_parser.checksum]
-
- try:
- gcno_summary = gcno_file_parser.Parse()
- except FileFormatError:
- logging.error("Error parsing gcno for gcda %s", gcda_name)
- continue
-
- file_name = gcda_name.rsplit(".", 1)[0]
- src_file_path = self._ExtractSourceName(gcno_summary, file_name)
-
- if not src_file_path:
- logging.error("No source file found for gcda %s.", gcda_name)
+ gcno_file_parsers = checksum_gcno_dict[gcda_file_parser.checksum]
+ gcno_summary = self._FindGcnoSummary(file_name, gcno_file_parsers)
+ if gcno_summary is None:
+ logging.error("No gcno file found for gcda %s.", gcda_name)
continue
# Process and merge gcno/gcda data
@@ -365,6 +418,10 @@
logging.error("Error parsing gcda file %s", gcda_name)
continue
+ coverage_report.GenerateLineCoverageVector(
+ gcno_summary, exclude_coverage_path, coverage_dict)
+
+ for src_file_path in coverage_dict:
# Get the git project information
# Assumes that the project name and path to the project root are similar
revision = None
@@ -387,24 +444,36 @@
revision = str(revision_dict[project_name])
logging.info("Source file '%s' matched with project '%s'",
src_file_path, git_project_name)
+ break
if not revision:
logging.info("Could not find git info for %s", src_file_path)
continue
+ coverage_vec = coverage_dict[src_file_path]
+ total_count, covered_count = coverage_report.GetCoverageStats(
+ coverage_vec)
if self.web and self.web.enabled:
- coverage_vec = coverage_report.GenerateLineCoverageVector(
- src_file_path, gcno_summary)
- total_count, covered_count = coverage_report.GetCoverageStats(
- coverage_vec)
self.web.AddCoverageReport(coverage_vec, src_file_path,
git_project_name, git_project_path,
revision, covered_count,
total_count, isGlobal)
+ else:
+ coverage = coverage_report_message.coverage.add()
+ coverage.total_line_count = total_count
+ coverage.covered_line_count = covered_count
+ coverage.line_coverage_vector.extend(coverage_vec)
+
+ src_file_path = os.path.relpath(src_file_path,
+ git_project_path)
+ coverage.file_path = src_file_path
+ coverage.revision = revision
+ coverage.project_name = git_project_name
if output_coverage_report:
- self._OutputCoverageReport(isGlobal)
+ self._OutputCoverageReport(isGlobal, coverage_report_message)
+ # TODO: consider to deprecate the manual process.
def _ManualProcess(self, cov_zip, revision_dict, gcda_dict, isGlobal):
"""Process coverage data and appends coverage reports to the report message.
@@ -476,8 +545,8 @@
logging.error("No gcda file found %s.", gcda_name)
continue
- src_file_path = self._ExtractSourceName(gcno_summary,
- file_name)
+ src_file_path = self._ExtractSourceName(
+ gcno_summary, file_name)
if not src_file_path:
logging.error("No source file found for %s.",
@@ -506,7 +575,7 @@
if output_coverage_report:
self._OutputCoverageReport(isGlobal)
- def SetCoverageData(self, dut, isGlobal=False):
+ def SetCoverageData(self, dut=None, serial=None, isGlobal=False):
"""Sets and processes coverage data.
Organizes coverage data and processes it into a coverage report in the
@@ -522,19 +591,22 @@
if not self.enabled:
return
- serial = dut.adb.shell('getprop ro.serialno').strip()
- if not serial in self._device_resource_dict:
- logging.error('Invalid device provided: %s', serial)
- return
+ if serial is None:
+ serial = "default" if dut is None else dut.adb.shell(
+ "getprop ro.serialno").strip()
- gcda_dict = self.GetGcdaDict(dut)
- logging.info("coverage file paths %s", str([fp for fp in gcda_dict]))
+ if not serial in self._device_resource_dict:
+ logging.error("Invalid device provided: %s", serial)
+ return
resource_path = self._device_resource_dict[serial]
if not resource_path:
- logging.error('coverage resource path not found.')
+ logging.error("coverage resource path not found.")
return
+ gcda_dict = self._GetGcdaDict(dut, serial)
+ logging.info("coverage file paths %s", str([fp for fp in gcda_dict]))
+
cov_zip = zipfile.ZipFile(os.path.join(resource_path, _GCOV_ZIP))
revision_dict = json.load(
@@ -547,6 +619,13 @@
# explicitly process coverage data for the specified modules
self._ManualProcess(cov_zip, revision_dict, gcda_dict, isGlobal)
+ # cleanup the downloaded gcda files.
+ logging.info("cleanup gcda files.")
+ files = os.listdir(self.local_coverage_path)
+ for item in files:
+ if item.endswith(".gcda"):
+ os.remove(os.path.join(self.local_coverage_path, item))
+
def SetHalNames(self, names=[]):
"""Sets the HAL names for which to process coverage.
@@ -562,3 +641,101 @@
prefix: strings, prefix of the coverage report file.
"""
self._coverage_report_file_prefix = prefix
+
+ def SetCoverageReportDirectory(self, corverage_report_dir):
+ """Sets the path for storing the coverage report file.
+
+ Args:
+ corverage_report_dir: strings, dir to store the coverage report file.
+ """
+ self._coverage_report_dir = corverage_report_dir
+
+ def _ExecuteOneAdbShellCommand(self, dut, serial, cmd):
+ """Helper method to execute a shell command and return results.
+
+ Args:
+ dut: the device under test.
+ cmd: string, command to execute.
+ Returns:
+ stdout result of the command, None if command fails.
+ """
+ if dut is None:
+ results = cmd_utils.ExecuteShellCommand("adb -s %s shell %s" %
+ (serial, cmd))
+ if (results[cmd_utils.EXIT_CODE][0]):
+ logging.error("Fail to execute command: %s. error: %s" %
+ (cmd, str(results[cmd_utils.STDERR][0])))
+ return None
+ else:
+ return results[cmd_utils.STDOUT][0]
+ else:
+ try:
+ return dut.adb.shell(cmd)
+ except AdbError as e:
+ logging.warn("Fail to execute command: %s. error: %s" %
+ (cmd, str(e)))
+ return None
+
+
+if __name__ == '__main__':
+ """ Tools to process coverage data.
+
+ Usage:
+ python coverage_utils.py operation [--serial=device_serial_number]
+ [--report_prefix=prefix_of_coverage_report]
+
+ Example:
+ python coverage_utils.py init_coverage
+ python coverage_utils.py get_coverage --serial HT7821A00243
+ python coverage_utils.py get_coverage --serial HT7821A00243 --report_prefix=test
+ """
+ logging.basicConfig(level=logging.INFO)
+ parser = argparse.ArgumentParser(description="Coverage process tool.")
+ parser.add_argument(
+ "--report_prefix",
+ dest="report_prefix",
+ required=False,
+ help="Prefix of the coverage report.")
+ parser.add_argument(
+ "--report_path",
+ dest="report_path",
+ required=False,
+ help="directory to store the coverage reports.")
+ parser.add_argument(
+ "--serial", dest="serial", required=True, help="Device serial number.")
+ parser.add_argument(
+ "--gcov_rescource_path",
+ dest="gcov_rescource_path",
+ required=True,
+ help="Directory that stores gcov resource files.")
+ parser.add_argument(
+ "operation",
+ help=
+ "Operation for processing coverage data, e.g. 'init_coverage', get_coverage'"
+ )
+ args = parser.parse_args()
+
+ if args.operation != "init_coverage" and args.operation != "get_coverage":
+ print "Unsupported operation. Exiting..."
+ sys.exit(1)
+ user_params = {
+ keys.ConfigKeys.IKEY_ENABLE_COVERAGE:
+ True,
+ keys.ConfigKeys.IKEY_ANDROID_DEVICE: [{
+ keys.ConfigKeys.IKEY_SERIAL:args.serial,
+ keys.ConfigKeys.IKEY_GCOV_RESOURCES_PATH:args.gcov_rescource_path,
+ }],
+ keys.ConfigKeys.IKEY_OUTPUT_COVERAGE_REPORT:
+ True,
+ keys.ConfigKeys.IKEY_GLOBAL_COVERAGE:
+ True
+ }
+ coverage = CoverageFeature(user_params)
+ if args.operation == "init_coverage":
+ coverage.InitializeDeviceCoverage(serial=args.serial)
+ elif args.operation == "get_coverage":
+ if args.report_prefix:
+ coverage.SetCoverageReportFilePrefix(args.report_prefix)
+ if args.report_path:
+ coverage.SetCoverageReportDirectory(args.report_path)
+ coverage.SetCoverageData(serial=args.serial, isGlobal=True)
diff --git a/utils/python/coverage/gcda_parser.py b/utils/python/coverage/gcda_parser.py
index 99e7820..b2dbc3c 100644
--- a/utils/python/coverage/gcda_parser.py
+++ b/utils/python/coverage/gcda_parser.py
@@ -29,7 +29,7 @@
import sys
from vts.utils.python.coverage import parser
-
+from vts.utils.python.coverage import gcno_parser
class GCDAParser(parser.GcovStreamParserUtil):
"""Parser object class stores stateful information for parsing GCDA files.
@@ -182,3 +182,11 @@
with open(file_name, 'rb') as stream:
return GCDAParser(stream).Parse(file_summary)
+
+
+if __name__ == '__main__':
+ if len(sys.argv) != 2:
+ print('usage: gcda_parser.py [gcda file name] [gcno file name]')
+ else:
+ file_summary = gcno_parser.ParseGcnoFile(sys.argv[2])
+ print(str(ParseGcdaFile(sys.argv[1], file_summary)))
diff --git a/utils/python/coverage/gcno_parser.py b/utils/python/coverage/gcno_parser.py
index ed5addd..954cc3d 100644
--- a/utils/python/coverage/gcno_parser.py
+++ b/utils/python/coverage/gcno_parser.py
@@ -237,6 +237,6 @@
if __name__ == '__main__':
if len(sys.argv) < 3 or sys.argv[1] != '-f':
- print('usage: GCNOparser.py -f [file name]')
+ print('usage: gcno_parser.py -f [file name]')
else:
- print(str(parse(sys.argv[2])))
+ print(str(ParseGcnoFile(sys.argv[2])))
diff --git a/utils/python/coverage/sancov_utils.py b/utils/python/coverage/sancov_utils.py
index ab15b47..5cc11db 100644
--- a/utils/python/coverage/sancov_utils.py
+++ b/utils/python/coverage/sancov_utils.py
@@ -94,62 +94,66 @@
self._device_resource_dict[serial] = sancov_resource_path
logging.info('Sancov enabled: %s', self.enabled)
- def InitializeDeviceCoverage(self, dut, hal_name):
+ def InitializeDeviceCoverage(self, dut, hals):
"""Initializes the sanitizer coverage on the device for the provided HAL.
Args:
dut: The device under test.
- hal_name: The HAL name and version (string) for which to measure coverage
- (e.g. 'android.hardware.light@2.0-service')
+ hals: A list of the HAL name and version (string) for which to
+ measure coverage (e.g. ['android.hardware.light@2.0'])
"""
serial = dut.adb.shell('getprop ro.serialno').strip()
if serial not in self._device_resource_dict:
logging.error("Invalid device provided: %s", serial)
return
- entries = dut.adb.shell('lshal -itp 2> /dev/null | grep {0}'.format(
- hal_name)).splitlines()
- pids = set([pid.strip()
- for pid in map(lambda entry: entry.split()[-1], entries)
- if pid.isdigit()])
- if len(pids) == 0:
- logging.warn('No matching processes IDs found for HAL %s',
- hal_name)
- return
- processes = dut.adb.shell('ps -p {0} -o comm='.format(' '.join(
- pids))).splitlines()
- process_names = set(
- [name.strip() for name in processes
- if name.strip() and not name.endswith(' (deleted)')])
- if len(process_names) == 0:
- logging.warn('No matching processes names found for HAL %s',
- hal_name)
- return
+ for hal in hals:
+ entries = dut.adb.shell('lshal -itp 2> /dev/null | grep {0}'.format(
+ hal)).splitlines()
+ pids = set([pid.strip()
+ for pid in map(lambda entry: entry.split()[-1], entries)
+ if pid.isdigit()])
- for process_name in process_names:
- cmd = self._PROCESS_INIT_COMMAND.format(
- process_name, self._TARGET_SANCOV_PATH, hal_name)
- try:
- dut.adb.shell(cmd.format(process_name))
- except AdbError as e:
- logging.error('Command failed: \"%s\"', cmd)
- continue
+ if len(pids) == 0:
+ logging.warn('No matching processes IDs found for HAL %s',
+ hal)
+ return
+ processes = dut.adb.shell('ps -p {0} -o comm='.format(' '.join(
+ pids))).splitlines()
+ process_names = set(
+ [name.strip() for name in processes
+ if name.strip() and not name.endswith(' (deleted)')])
- def FlushDeviceCoverage(self, dut, hal_name=None):
+ if len(process_names) == 0:
+ logging.warn('No matching processes names found for HAL %s',
+ hal)
+ return
+
+ for process_name in process_names:
+ cmd = self._PROCESS_INIT_COMMAND.format(
+ process_name, self._TARGET_SANCOV_PATH, hal)
+ try:
+ dut.adb.shell(cmd.format(process_name))
+ except AdbError as e:
+ logging.error('Command failed: \"%s\"', cmd)
+ continue
+
+ def FlushDeviceCoverage(self, dut, hals):
"""Flushes the sanitizer coverage on the device for the provided HAL.
Args:
dut: The device under test.
- hal_name: The HAL name and version (string) for which to flush coverage
- (e.g. 'android.hardware.light@2.0-service')
+ hals: A list of HAL name and version (string) for which to flush
+ coverage (e.g. ['android.hardware.light@2.0-service'])
"""
serial = dut.adb.shell('getprop ro.serialno').strip()
if serial not in self._device_resource_dict:
logging.error('Invalid device provided: %s', serial)
return
- dut.adb.shell(
- self._FLUSH_COMMAND.format('' if hal_name is None else hal_name))
+ for hal in hals:
+ dut.adb.shell(
+ self._FLUSH_COMMAND.format(hal))
def _InitializeFileVectors(self, serial, binary_path):
"""Parse the binary and read the debugging information.
@@ -267,7 +271,7 @@
git_project_name, git_project_path, revision,
covered_count, total_count, True)
- def ProcessDeviceCoverage(self, dut, hal_name):
+ def ProcessDeviceCoverage(self, dut, hals):
"""Process device coverage.
Fetch sancov files from the target, parse the sancov files, symbolize the output,
@@ -275,8 +279,8 @@
Args:
dut: The device under test.
- hal_name: The HAL name and version (string) for which to process coverage
- (e.g. 'android.hardware.light@2.0')
+ hals: A list of HAL name and version (string) for which to process
+ coverage (e.g. ['android.hardware.light@2.0'])
"""
serial = dut.adb.shell('getprop ro.serialno').strip()
product = dut.adb.shell('getprop ro.build.product').strip()
@@ -292,8 +296,11 @@
os.path.join(self._device_resource_dict[serial],
self._SYMBOLS_ZIP))
- sancov_files = dut.adb.shell('find {0}/{1} -name \"*.sancov\"'.format(
- self._TARGET_SANCOV_PATH, hal_name)).splitlines()
+
+ sancov_files = []
+ for hal in hals:
+ sancov_files.extend(dut.adb.shell('find {0}/{1} -name \"*.sancov\"'.format(
+ self._TARGET_SANCOV_PATH, hal)).splitlines())
temp_dir = tempfile.mkdtemp()
binary_to_sancov = {}
@@ -304,8 +311,9 @@
os.path.join(temp_dir, os.path.basename(file)))
binary_to_sancov[binary] = (bitness, offsets)
- dut.adb.shell('rm -rf {0}/{1}'.format(self._TARGET_SANCOV_PATH,
- hal_name))
+ for hal in hals:
+ dut.adb.shell('rm -rf {0}/{1}'.format(self._TARGET_SANCOV_PATH,
+ hal))
search_root = os.path.join('out', 'target', 'product', product,
'symbols')
diff --git a/utils/python/cpu/cpu_frequency_scaling.py b/utils/python/cpu/cpu_frequency_scaling.py
index b24721d..5ce6b0e 100644
--- a/utils/python/cpu/cpu_frequency_scaling.py
+++ b/utils/python/cpu/cpu_frequency_scaling.py
@@ -39,6 +39,11 @@
_theoretical_max_frequency: a dict where its key is the CPU number and
its value is an integer containing the
theoretical max CPU frequency.
+ _perf_override: boolean, true if this module has switched the device from
+ its normal cpufreq governor to the performance
+ governor.
+ _saved_governors: list of strings, the saved cpufreq governor for each
+ CPU on the device.
"""
def __init__(self, dut):
@@ -49,10 +54,11 @@
"""Creates a shell mirror object and reads the configuration values."""
if self._init:
return
- self._dut.shell.InvokeTerminal("cpu_frequency_scaling")
- self._shell = self._dut.shell.cpu_frequency_scaling
+ self._shell = self._dut.shell
self._min_cpu_number, self._max_cpu_number = self._LoadMinAndMaxCpuNo()
self._theoretical_max_frequency = {}
+ self._perf_override = False
+ self._saved_governors = None
self._init = True
def _LoadMinAndMaxCpuNo(self):
@@ -110,30 +116,76 @@
" not set.", cpu_no)
return None
- def ChangeCpuGovernor(self, mode):
+ def ChangeCpuGovernor(self, modes):
"""Changes the CPU governor mode of all the CPUs on the device.
Args:
- mode: expected CPU governor mode, e.g., 'performance' or 'interactive'.
+ modes: list of expected CPU governor modes, e.g., 'performance'
+ or 'schedutil'. The length of the list must be equal to
+ the number of CPUs on the device.
+
+ Returns:
+ A list of the previous governor modes if successful, None otherwise.
"""
self.Init()
+ asserts.assertEqual(self._max_cpu_number - self._min_cpu_number,
+ len(modes))
+ # save current governor settings
+ target_cmd = []
+ prev_govs = []
for cpu_no in range(self._min_cpu_number, self._max_cpu_number):
- results = self._shell.Execute(
- "echo %s > /sys/devices/system/cpu/cpu%s/"
- "cpufreq/scaling_governor" % (mode, cpu_no))
- asserts.assertEqual(1, len(results[const.EXIT_CODE]))
- if results[const.EXIT_CODE][0]:
- logging.warn("Can't change CPU governor.")
- logging.warn("Stderr for scaling_governor: %s",
- results[const.STDERR][0])
+ target_cmd.append("cat /sys/devices/system/cpu/cpu%s/cpufreq/"
+ "scaling_governor" % cpu_no)
+ results = self._shell.Execute(target_cmd)
+ asserts.assertEqual(self._max_cpu_number - self._min_cpu_number,
+ len(results[const.STDOUT]))
+ if any(results[const.EXIT_CODE]):
+ logging.warn("Unable to save governors")
+ logging.warn("Stderr for saving scaling_governor: %s",
+ results[const.STDERR])
+ return
+ for cpu_no in range(self._min_cpu_number, self._max_cpu_number):
+ prev_govs.append(results[const.STDOUT][cpu_no].rstrip())
+ # set new governor
+ target_cmd = []
+ for cpu_no in range(self._min_cpu_number, self._max_cpu_number):
+ target_cmd.append("echo %s > /sys/devices/system/cpu/cpu%s/cpufreq/"
+ "scaling_governor" % (modes[cpu_no], cpu_no))
+ results = self._shell.Execute(target_cmd)
+ asserts.assertEqual(self._max_cpu_number - self._min_cpu_number,
+ len(results[const.STDOUT]))
+ if any(results[const.EXIT_CODE]):
+ logging.warn("Can't change CPU governor.")
+ logging.warn("Stderr for changing scaling_governor: %s",
+ results[const.STDERR])
+ return
+ return prev_govs
def DisableCpuScaling(self):
"""Disable CPU frequency scaling on the device."""
- self.ChangeCpuGovernor("performance")
+ self.Init()
+ if self._perf_override:
+ logging.warn("DisableCpuScaling called while scaling already disabled.")
+ return;
+ new_govs = []
+ for cpu_no in range(self._min_cpu_number, self._max_cpu_number):
+ new_govs.append("performance")
+ prev_govs = self.ChangeCpuGovernor(new_govs)
+ if prev_govs is not None:
+ self._saved_governors = prev_govs
+ self._perf_override = True
def EnableCpuScaling(self):
"""Enable CPU frequency scaling on the device."""
- self.ChangeCpuGovernor("interactive")
+ self.Init()
+ if not self._perf_override:
+ logging.warn("EnableCpuScaling called while scaling already enabled.")
+ return;
+ if self._saved_governors is None:
+ logging.warn("EnableCpuScaling called and _saved_governors is None.")
+ return;
+ self.ChangeCpuGovernor(self._saved_governors)
+ self._perf_override = False
def IsUnderThermalThrottling(self):
"""Checks whether a target device is under thermal throttling.
@@ -155,16 +207,16 @@
return False
configurable_max_frequency = results[const.STDOUT][0].strip()
current_frequency = results[const.STDOUT][1].strip()
- if configurable_max_frequency != current_frequency:
+ if configurable_max_frequency > current_frequency:
logging.error(
- "CPU%s: Configurable max frequency %s != current frequency %s",
+ "CPU%s: Configurable max frequency %s > current frequency %s",
cpu_no, configurable_max_frequency, current_frequency)
return True
theoretical_max_frequency = self._GetTheoreticalMaxFrequency(cpu_no)
if (theoretical_max_frequency is not None and
- theoretical_max_frequency != int(current_frequency)):
+ theoretical_max_frequency > int(current_frequency)):
logging.error(
- "CPU%s, Theoretical max frequency %d != scaling current frequency %s",
+ "CPU%s, Theoretical max frequency %d > scaling current frequency %s",
cpu_no, theoretical_max_frequency, current_frequency)
return True
return False
diff --git a/utils/python/file/target_file_utils.py b/utils/python/file/target_file_utils.py
index c744bc5..a24b3fe 100644
--- a/utils/python/file/target_file_utils.py
+++ b/utils/python/file/target_file_utils.py
@@ -23,25 +23,6 @@
_EXECUTE_PERMISSION = 1
-def Exists(filepath, shell):
- """Determines if a file exists.
-
- Args:
- filepath: string, path to file
- shell: an instance of the VTS shell
-
- Returns:
- True if the file exists, False otherwise
- """
- cmd = "ls %s" % filepath
- results = shell.Execute(cmd)
- if results[const.EXIT_CODE][0] != 0:
- return False
-
- out_str = str(results[const.STDOUT][0]).strip()
- return out_str.find(filepath) == 0
-
-
def _Test(shell, *args):
"""Executes test command on device.
@@ -57,6 +38,19 @@
return results[const.EXIT_CODE][0] == 0
+def Exists(filepath, shell):
+ """Determines if a file or directory exists.
+
+ Args:
+ filepath: string, the path to a file or a directory.
+ shell: an instance of the VTS shell.
+
+ Returns:
+ True if exists, False otherwise.
+ """
+ return _Test(shell, "-e", filepath)
+
+
def IsDirectory(path, shell):
"""Determines if a path is a directory.
diff --git a/utils/python/hal/hal_service_name_utils.py b/utils/python/hal/hal_service_name_utils.py
index 0651a9b..ec17233 100644
--- a/utils/python/hal/hal_service_name_utils.py
+++ b/utils/python/hal/hal_service_name_utils.py
@@ -15,6 +15,7 @@
#
import json
+import logging
from vts.runners.host import asserts
from vts.runners.host import const
@@ -22,6 +23,7 @@
VTS_TESTABILITY_CHECKER_32 = "/data/local/tmp/vts_testability_checker32"
VTS_TESTABILITY_CHECKER_64 = "/data/local/tmp/vts_testability_checker64"
+
def GetHalServiceName(shell, hal, bitness="64", run_as_compliance_test=False):
"""Determine whether to run a VTS test against a HAL and get the service
names of the given hal if determine to run.
@@ -46,8 +48,8 @@
cmd += " -b " + bitness + " " + hal
cmd_results = shell.Execute(str(cmd))
asserts.assertFalse(
- any(cmd_results[const.EXIT_CODE]),
- "Failed to run vts_testability_checker.")
+ any(cmd_results[const.EXIT_CODE]),
+ "Failed to run vts_testability_checker. Error: %s" % cmd_results[const.STDERR][0])
result = json.loads(cmd_results[const.STDOUT][0])
if str(result['Testable']).lower() == "true":
return True, set(result['instances'])
@@ -55,9 +57,46 @@
return False, ()
-def GetServiceInstancesCombinations(services, service_instances):
+class CombMode(object):
+ """Enum for service name combination mode"""
+ FULL_PERMUTATION = 0
+ NAME_MATCH = 1
+ NO_COMBINATION = 2
+
+
+def GetServiceInstancesCombinations(services,
+ service_instances,
+ mode=CombMode.FULL_PERMUTATION):
+ """Create combinations of instances for all services.
+
+ Args:
+ services: list, all services used in the test. e.g. [s1, s2]
+ service_instances: dictionary, mapping of each service and the
+ corresponding service name(s).
+ e.g. {"s1": ["n1"], "s2": ["n2", "n3"]}
+ mode: CombMode that determines the combination strategy.
+
+ Returns:
+ A list of service instance combinations.
+ """
+ if mode == CombMode.FULL_PERMUTATION:
+ return GetServiceInstancesFullCombinations(services, service_instances)
+ elif mode == CombMode.NAME_MATCH:
+ return GetServiceInstancesNameMatchCombinations(services,
+ service_instances)
+ else:
+ logging.warning("Unknown comb mode, use default comb mode instead.")
+ return GetServiceInstancesFullCombinations(services, service_instances)
+
+
+def GetServiceInstancesFullCombinations(services, service_instances):
"""Create all combinations of instances for all services.
+ Create full permutation for registered service instances, e.g.
+ s1 have instances (n1, n2) and s2 have instances (n3, n4), return all
+ permutations of s1 and s2, i.e. (s1/n1, s2/n3), (s1/n1, s2/n4),
+ (s1/n2, s2/n3) and (s1/n2, s2/n4)
+
Args:
services: list, all services used in the test. e.g. [s1, s2]
service_instances: dictionary, mapping of each service and the
@@ -87,3 +126,42 @@
service_instance_combinations.append(new_instance_comb)
return service_instance_combinations
+
+
+def GetServiceInstancesNameMatchCombinations(services, service_instances):
+ """Create service instance combinations with same name for services.
+
+ Create combinations for services with the same instance name, e.g.
+ both s1 and s2 have two instances with name n1, and n2, return
+ the service instance combination of s1 and s2 with same instance name,
+ i.e. (s1/n1, s2/n1) and (s1/n2, s2/n2)
+
+ Args:
+ services: list, all services used in the test. e.g. [s1, s2]
+ service_instances: dictionary, mapping of each service and the
+ corresponding service name(s).
+ e.g. {"s1": ["n1", "n2"], "s2": ["n1", "n2"]}
+
+ Returns:
+ A list of service instance combinations.
+ e.g. [[s1/n1, s2/n1], [s1/n2, s2/n2]]
+ """
+ service_instance_combinations = []
+ instance_names = set()
+ for service in services:
+ if service not in service_instances or not service_instances[service]:
+ logging.error("Does not found instance for service: %s", service)
+ return []
+ if not instance_names:
+ instance_names = set(service_instances[service])
+ else:
+ instance_names.intersection_update(set(service_instances[service]))
+
+ for name in instance_names:
+ instance_comb = []
+ for service in services:
+ new_instance = [service + '/' + name]
+ instance_comb.extend(new_instance)
+ service_instance_combinations.append(instance_comb)
+
+ return service_instance_combinations
diff --git a/utils/python/hal/hal_service_name_utils_unittest.py b/utils/python/hal/hal_service_name_utils_unittest.py
index 28285da..71f017d 100644
--- a/utils/python/hal/hal_service_name_utils_unittest.py
+++ b/utils/python/hal/hal_service_name_utils_unittest.py
@@ -22,7 +22,7 @@
class HalServiceNameUtilsUnitTest(unittest.TestCase):
"""Tests for hal hidl gtest template"""
- def testGetServiceInstancesCombinations(self):
+ def testGetServiceInstancesFullCombinations(self):
"""Test the function to get service instance combinations"""
comb1 = hal_service_name_utils.GetServiceInstancesCombinations([], {})
@@ -57,6 +57,50 @@
"s2": ["n1", "n2"]})
self.assertEqual([["s2/n1"], ["s2/n2"]], comb9)
+ def testGetServiceInstancesNameMatchCombinations(self):
+ """Test the function to get service instance combinations"""
+
+ mode = hal_service_name_utils.CombMode.NAME_MATCH
+ comb1 = hal_service_name_utils.GetServiceInstancesCombinations([], {},
+ mode)
+ self.assertEquals(0, len(comb1))
+ comb2 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1"], {}, mode)
+ self.assertEquals(0, len(comb2))
+ comb3 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1"], {"s1": ["n1"]}, mode)
+ #self.assertEqual([["s1/n1"]], comb3)
+ comb4 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1"], {"s1": ["n1", "n2"]}, mode)
+ self.assertEqual([["s1/n1"], ["s1/n2"]], comb4)
+ comb5 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": ["n1", "n2"]}, mode)
+ self.assertEqual(0, len(comb5))
+ comb6 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": ["n1", "n2"],
+ "s2": ["n3"]}, mode)
+ self.assertEqual(0, len(comb6))
+ comb7 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": ["n1", "n2"],
+ "s2": ["n3", "n4"]}, mode)
+ self.assertEqual(0, len(comb7))
+ comb8 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": ["n1", "n2"],
+ "s2": []}, mode)
+ self.assertEqual(0, len(comb8))
+ comb9 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": [],
+ "s2": ["n1", "n2"]}, mode)
+ self.assertEqual(0, len(comb9))
+ comb10 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": ["n1"],
+ "s2": ["n1", "n2"]}, mode)
+ self.assertEqual([["s1/n1", "s2/n1"]], comb10)
+ comb11 = hal_service_name_utils.GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": ["n1", "n2"],
+ "s2": ["n1", "n2"]}, mode)
+ self.assertEqual([["s1/n1", "s2/n1"], ["s1/n2", "s2/n2"]], comb11)
+
if __name__ == '__main__':
unittest.main()
diff --git a/utils/python/retry/__init__.py b/utils/python/io/__init__.py
similarity index 100%
rename from utils/python/retry/__init__.py
rename to utils/python/io/__init__.py
diff --git a/utils/python/io/capture_printout.py b/utils/python/io/capture_printout.py
new file mode 100644
index 0000000..d1df4d0
--- /dev/null
+++ b/utils/python/io/capture_printout.py
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2017 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.
+#
+
+
+from cStringIO import StringIO
+import sys
+
+
+class CaptureStdout(list):
+ '''Capture system stdout as a list of string.
+
+ Usage example:
+ with CaptureStdout() as output:
+ print 'something'
+
+ print 'Got output list: %s' % output
+ '''
+
+ def __enter__(self):
+ self.sys_stdout = sys.stdout
+ sys.stdout = StringIO()
+ return self
+
+ def __exit__(self, *args):
+ self.extend(sys.stdout.getvalue().splitlines())
+ sys.stdout = self.sys_stdout
\ No newline at end of file
diff --git a/utils/python/io/file_util.py b/utils/python/io/file_util.py
new file mode 100644
index 0000000..082ee5d
--- /dev/null
+++ b/utils/python/io/file_util.py
@@ -0,0 +1,95 @@
+#
+# Copyright (C) 2017 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.
+#
+
+import logging
+import os
+import shutil
+import tempfile
+
+
+def FindFile(directory, filename):
+ '''Find a file under directory given the filename.
+
+ Args:
+ directory: string, directory path
+ filename: string, file name to find
+
+ Returns:
+ String, path to the file found. None if not found.
+ '''
+ for (dirpath, dirnames, filenames) in os.walk(
+ directory, followlinks=False):
+ for fn in filenames:
+ if fn == filename:
+ return os.path.join(dirpath, filename)
+
+ return None
+
+
+def Rmdirs(path, ignore_errors=False):
+ '''Remove the given directory and its contents recursively.
+
+ Args:
+ path: string, directory to delete
+ ignore_errors: bool, whether to ignore errors. Defaults to False
+
+ Returns:
+ bool, True if directory is deleted.
+ False if errors occur or directory does not exist.
+ '''
+ return_value = False
+ if os.path.exists(path):
+ try:
+ shutil.rmtree(path, ignore_errors=ignore_errors)
+ return_value = True
+ except OSError as e:
+ logging.exception(e)
+ return return_value
+
+
+def Makedirs(path, skip_if_exists=True):
+ '''Make directories lead to the given path.
+
+ Args:
+ path: string, directory to make
+ skip_if_exists: bool, True for ignoring exisitng dir. False for throwing
+ error from os.mkdirs. Defaults to True
+
+ Returns:
+ bool, True if directory is created.
+ False if errors occur or directory already exist.
+ '''
+ return_value = False
+ if not skip_if_exists or not os.path.exists(path):
+ try:
+ os.makedirs(path)
+ return_value = True
+ except OSError as e:
+ logging.exception(e)
+ return return_value
+
+
+def MakeTempDir(base_dir):
+ """Make a temp directory based on the given path and return its path.
+
+ Args:
+ base_dir: string, base directory to make temp directory.
+
+ Returns:
+ string, relative path to created temp directory
+ """
+ Makedirs(base_dir)
+ return tempfile.mkdtemp(dir=base_dir)
\ No newline at end of file
diff --git a/utils/python/io/file_util_test.py b/utils/python/io/file_util_test.py
new file mode 100644
index 0000000..bb59a3c
--- /dev/null
+++ b/utils/python/io/file_util_test.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 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.
+#
+
+import os
+import random
+import string
+import unittest
+
+from vts.utils.python.io import file_util
+
+
+class FileUtilTest(unittest.TestCase):
+ def setUp(self):
+ """Resets generated directory list"""
+ self._dirs = []
+
+ def tearDown(self):
+ """Removes existing directories"""
+ for path in self._dirs:
+ file_util.Rmdirs(path)
+
+ def testMakeAndRemoveDirs(self):
+ """Tests making and removing directories """
+ dir_name = ''.join(
+ random.choice(string.ascii_lowercase + string.digits)
+ for _ in range(12))
+ self._dirs.append(dir_name)
+
+ # make non-existing directory
+ result = file_util.Makedirs(dir_name)
+ self.assertEqual(True, result)
+
+ # make existing directory
+ result = file_util.Makedirs(dir_name)
+ self.assertEqual(False, result)
+
+ # delete existing directory
+ result = file_util.Rmdirs(dir_name)
+ self.assertEqual(True, result)
+
+ # delete non-existing directory
+ result = file_util.Rmdirs(dir_name)
+ self.assertEqual(False, result)
+
+ def testMakeTempDir(self):
+ """Tests making temp directory """
+ base_dir = ''.join(
+ random.choice(string.ascii_lowercase + string.digits)
+ for _ in range(12))
+ self._dirs.append(base_dir)
+
+ # make temp directory
+ result = file_util.MakeTempDir(base_dir)
+ self.assertTrue(os.path.join(base_dir, "tmp"))
+
+ def testMakeException(self):
+ """Tests making directory and raise exception """
+ dir_name = ''.join(
+ random.choice(string.ascii_lowercase + string.digits)
+ for _ in range(12))
+ self._dirs.append(dir_name)
+
+ file_util.Makedirs(dir_name)
+ self.assertRaises(Exception,
+ file_util.Makedirs(dir_name, skip_if_exists=False))
+
+ def testRemoveException(self):
+ """Tests removing directory and raise exception """
+ dir_name = ''.join(
+ random.choice(string.ascii_lowercase + string.digits)
+ for _ in range(12))
+ self._dirs.append(dir_name)
+
+ link_name = ''.join(
+ random.choice(string.ascii_lowercase + string.digits)
+ for _ in range(12))
+
+ file_util.Makedirs(dir_name)
+ os.symlink(dir_name, link_name)
+ try:
+ self.assertRaises(Exception,
+ file_util.Rmdirs(link_name, ignore_errors=False))
+ finally:
+ os.remove(link_name)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/utils/python/library/vtable_parser.py b/utils/python/library/vtable_parser.py
index cf582b4..a489aa3 100644
--- a/utils/python/library/vtable_parser.py
+++ b/utils/python/library/vtable_parser.py
@@ -17,6 +17,7 @@
import logging
import os
import re
+import stat
from vts.runners.host import utils
from vts.utils.python.common import cmd_utils
@@ -53,8 +54,19 @@
"^(\\d+) +" + re.escape("(int (*)(...))") + " (.+)$")
def __init__(self, dumper_path):
+ """Initializes the dumper path and its permission."""
self._dumper_path = dumper_path
+ if not utils.is_on_windows():
+ bin_path = os.path.join(
+ self._dumper_path, "bin", self.VNDK_VTABLE_DUMPER)
+ try:
+ mode = os.stat(bin_path).st_mode
+ os.chmod(bin_path,
+ mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
+ except OSError as e:
+ logging.warning("Fail to chmod vtable dumper: %s", e)
+
def CallVtableDumper(self, lib_path):
"""Calls vndk-vtable-dumper and returns its output.
diff --git a/utils/python/mirror/py2pb.py b/utils/python/mirror/py2pb.py
index ec2a396..933a42b 100644
--- a/utils/python/mirror/py2pb.py
+++ b/utils/python/mirror/py2pb.py
@@ -163,6 +163,11 @@
logging.error("PyDict2PbStruct: unsupported type %s",
attr.type)
sys.exit(-1)
+ else:
+ # TODO: instead crash the test, consider to generate default value
+ # in case not provided in the py_value.
+ logging.error("PyDict2PbStruct: attr %s not provided", attr.name)
+ sys.exit(-1)
if len(provided_attrs) > 0:
logging.error("PyDict2PbStruct: provided dictionary included elements" +
" not part of the type being converted to: %s",
diff --git a/utils/python/performance/benchmark_parser.py b/utils/python/performance/benchmark_parser.py
index e837838..a6fcdeb 100644
--- a/utils/python/performance/benchmark_parser.py
+++ b/utils/python/performance/benchmark_parser.py
@@ -78,7 +78,7 @@
Returns:
A list of integers.
"""
- return [x[self._REAL_TIME] for x in self._benchmarks]
+ return [int(float(x[self._REAL_TIME])) for x in self._benchmarks]
def ToTable(self):
"""Returns the benchmarks in a table.
diff --git a/utils/python/precondition/precondition_utils.py b/utils/python/precondition/precondition_utils.py
index a891c18..b1f70c2 100644
--- a/utils/python/precondition/precondition_utils.py
+++ b/utils/python/precondition/precondition_utils.py
@@ -103,9 +103,95 @@
if hal:
testable, _ = hal_service_name_utils.GetHalServiceName(
shell, hal, bitness, run_as_compliance_test)
- if not testable:
- logging.warn("The required hal %s is not testable.", hal)
- return False
+ return testable
logging.info("Precondition check pass.")
return True
+
+
+def MeetFirstApiLevelPrecondition(test_instance, dut=None):
+ """Checks first API level precondition of a test instance.
+
+ If the device's ro.product.first_api_level is 0, this function checks
+ ro.build.version.sdk.
+
+ Args:
+ test_instance: the test instance which inherits BaseTestClass.
+ dut: the AndroidDevice under test.
+
+ Returns:
+ True if the device's first API level is greater than or equal to the
+ value of the precondition; False otherwise.
+ """
+ opt_params = [keys.ConfigKeys.IKEY_PRECONDITION_FIRST_API_LEVEL]
+ test_instance.getUserParams(opt_param_names=opt_params)
+ if not hasattr(test_instance,
+ keys.ConfigKeys.IKEY_PRECONDITION_FIRST_API_LEVEL):
+ return True
+
+ precond_level_attr = getattr(
+ test_instance, keys.ConfigKeys.IKEY_PRECONDITION_FIRST_API_LEVEL, 0)
+ try:
+ precond_level = int(precond_level_attr)
+ except ValueError:
+ logging.error("Cannot parse first API level precondition: %s",
+ precond_level_attr)
+ return True
+
+ if not dut:
+ logging.info("Read first API level from the first device.")
+ dut = test_instance.android_devices[0]
+ device_level = dut.getLaunchApiLevel(strict=False)
+ if not device_level:
+ logging.error("Cannot read first API level from device. "
+ "Assume it meets the precondition.")
+ return True
+
+ logging.info("Device's first API level=%d; precondition=%d",
+ device_level, precond_level)
+ return device_level >= precond_level
+
+
+def CheckSysPropPrecondition(test_instance,
+ dut,
+ shell=None):
+ """Checks sysprop precondition of a test instance.
+
+ Args:
+ test_instance: the test instance which inherits BaseTestClass.
+ dut: the AndroidDevice under test.
+ shell: the ShellMirrorObject to execute command on the device.
+ If not specified, the function creates one from dut.
+
+ Returns:
+ False if precondition is not met (i.e., to skip tests),
+ True otherwise (e.g., when no sysprop precondition is set;
+ the precondition is satisfied;
+ there is an error in retrieving the target sysprop; or
+ the specified sysprop is undefined)
+ """
+ if not hasattr(test_instance, keys.ConfigKeys.IKEY_PRECONDITION_SYSPROP):
+ return True
+
+ precond_sysprop = str(getattr(
+ test_instance, keys.ConfigKeys.IKEY_PRECONDITION_SYSPROP, ''))
+ if "=" not in precond_sysprop:
+ logging.error("precondition-sysprop value is invalid.")
+ return True
+
+ if shell is None:
+ dut.shell.InvokeTerminal("check_sysprop_precondition")
+ shell = dut.shell.check_sysprop_precondition
+
+ sysprop_key, sysprop_value = precond_sysprop.split('=')
+ cmd_results = shell.Execute('getprop %s' % sysprop_key)
+ if any(cmd_results[const.EXIT_CODE]):
+ logging.error('Failed to read sysprop:\n%s', sysprop_key)
+ return True
+ else:
+ value = cmd_results[const.STDOUT][0].strip()
+ if len(value) == 0:
+ return True
+ elif value != sysprop_value:
+ return False
+ return True
diff --git a/utils/python/profiling/profiling_utils.py b/utils/python/profiling/profiling_utils.py
index b3e4562..d3234c3 100644
--- a/utils/python/profiling/profiling_utils.py
+++ b/utils/python/profiling/profiling_utils.py
@@ -154,16 +154,17 @@
hal_instrumentation_lib_path: string, the path of directory that stores
profiling libraries.
"""
- if hal_instrumentation_lib_path is None:
+ hal_instrumentation_lib_path_32 = HAL_INSTRUMENTATION_LIB_PATH_32
+ hal_instrumentation_lib_path_64 = HAL_INSTRUMENTATION_LIB_PATH_64
+ if hal_instrumentation_lib_path is not None:
bitness = getattr(self, keys.ConfigKeys.IKEY_ABI_BITNESS, None)
if bitness == '64':
- hal_instrumentation_lib_path = HAL_INSTRUMENTATION_LIB_PATH_64
+ hal_instrumentation_lib_path_64 = hal_instrumentation_lib_path
elif bitness == '32':
- hal_instrumentation_lib_path = HAL_INSTRUMENTATION_LIB_PATH_32
+ hal_instrumentation_lib_path_32 = hal_instrumentation_lib_path
else:
logging.error('Unknown abi bitness "%s". Using 64bit hal '
'instrumentation lib path.', bitness)
- hal_instrumentation_lib_path = HAL_INSTRUMENTATION_LIB_PATH_64
# cleanup any existing traces.
shell.Execute("rm " + os.path.join(TARGET_PROFILING_TRACE_PATH,
@@ -173,8 +174,11 @@
# give permission to write the trace file.
shell.Execute("chmod 777 " + TARGET_PROFILING_TRACE_PATH)
- shell.Execute("setprop hal.instrumentation.lib.path " +
- hal_instrumentation_lib_path)
+ shell.Execute("setprop hal.instrumentation.lib.path.32 " +
+ hal_instrumentation_lib_path_32)
+ shell.Execute("setprop hal.instrumentation.lib.path.64 " +
+ hal_instrumentation_lib_path_64)
+
shell.Execute("setprop hal.instrumentation.enable true")
def DisableVTSProfiling(self, shell):
@@ -207,7 +211,7 @@
trace_processor_lib = os.path.join(data_file_path, "host", "lib64")
trace_processor_cmd = [
"chmod a+x %s" % trace_processor_binary,
- "LD_LIBRARY_PATH=%s %s --profiling %s" %
+ "LD_LIBRARY_PATH=%s %s -m profiling_trace %s" %
(trace_processor_lib, trace_processor_binary, trace_file)
]
diff --git a/utils/python/reporting/report_file_utils.py b/utils/python/reporting/report_file_utils.py
index 437fa8a..899a9a1 100644
--- a/utils/python/reporting/report_file_utils.py
+++ b/utils/python/reporting/report_file_utils.py
@@ -20,6 +20,9 @@
import shutil
+PYTHON_OUTPUT_ADDITIONAL = 'additional_output_files'
+
+
def NotNoneStr(item):
'''Convert a veriable to string only if it is not None'''
return str(item) if item is not None else None
@@ -200,3 +203,12 @@
return urls
except IOError as e:
logging.exception(e)
+
+ def GetAdditioanlOutputDirectory(self):
+ '''Returns a directory to store additional output files.
+
+ Files under this directory will be included in log output folder.
+ All files will be uploaded to VTS dashboard if enabled;
+ Only files with recognized file types will be included in TradeFed output.
+ '''
+ return os.path.join(logging.log_path, PYTHON_OUTPUT_ADDITIONAL)
\ No newline at end of file
diff --git a/utils/python/retry/retry.py b/utils/python/retry/retry.py
deleted file mode 100644
index 1494742..0000000
--- a/utils/python/retry/retry.py
+++ /dev/null
@@ -1,129 +0,0 @@
-#
-# Copyright (C) 2016 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.
-#
-import sys
-import time
-
-def GenericRetry(handler, max_retry, functor,
- sleep=0, backoff_factor=1, success_functor=lambda x: None,
- raise_first_exception_on_failure=True, *args, **kwargs):
- """Generic retry loop w/ optional break out depending on exceptions.
-
- To retry based on the return value of |functor| see the timeout_util module.
-
- Keep in mind that the total sleep time will be the triangular value of
- max_retry multiplied by the sleep value. e.g. max_retry=5 and sleep=10
- will be T5 (i.e. 5+4+3+2+1) times 10, or 150 seconds total. Rather than
- use a large sleep value, you should lean more towards large retries and
- lower sleep intervals, or by utilizing backoff_factor.
-
- Args:
- handler: A functor invoked w/ the exception instance that
- functor(*args, **kwargs) threw. If it returns True, then a
- retry is attempted. If False, the exception is re-raised.
- max_retry: A positive integer representing how many times to retry
- the command before giving up. Worst case, the command is invoked
- max_retry + 1) times before failing.
- functor: A callable to pass args and kwargs to.
- sleep: Optional keyword. Multiplier for how long to sleep between
- retries; will delay (1*sleep) the first time, then (2*sleep),
- continuing via attempt * sleep.
- backoff_factor: Optional keyword. If supplied and > 1, subsequent sleeps
- will be of length (backoff_factor ^ (attempt - 1)) * sleep,
- rather than the default behavior of attempt * sleep.
- success_functor: Optional functor that accepts 1 argument. Will be called
- after successful call to |functor|, with the argument
- being the number of attempts (1 = |functor| succeeded on
- first try).
- raise_first_exception_on_failure: Optional boolean which determines which
- exception is raised upon failure after
- retries. If True, the first exception
- that was encountered. If False, the
- final one. Default: True.
- *args: Positional args passed to functor.
- **kwargs: Optional args passed to functor.
-
- Returns:
- Whatever functor(*args, **kwargs) returns.
-
- Raises:
- Exception: Whatever exceptions functor(*args, **kwargs) throws and
- isn't suppressed is raised. Note that the first exception encountered
- is what's thrown.
- """
-
- if max_retry < 0:
- raise ValueError('max_retry needs to be zero or more: %s' % max_retry)
-
- if backoff_factor < 1:
- raise ValueError('backoff_factor must be 1 or greater: %s'
- % backoff_factor)
-
- ret, success = (None, False)
- attempt = 0
-
- exc_info = None
- for attempt in xrange(max_retry + 1):
- if attempt and sleep:
- if backoff_factor > 1:
- sleep_time = sleep * backoff_factor ** (attempt - 1)
- else:
- sleep_time = sleep * attempt
- time.sleep(sleep_time)
- try:
- ret = functor(*args, **kwargs)
- success = True
- break
- except Exception as e:
- # Note we're not snagging BaseException, so MemoryError/KeyboardInterrupt
- # and friends don't enter this except block.
- if not handler(e):
- raise
- # If raise_first_exception_on_failure, we intentionally ignore
- # any failures in later attempts since we'll throw the original
- # failure if all retries fail.
- if exc_info is None or not raise_first_exception_on_failure:
- exc_info = sys.exc_info()
-
- if success:
- success_functor(attempt + 1)
- return ret
-
- raise exc_info[0], exc_info[1], exc_info[2]
-
-def RetryException(exc_retry, max_retry, functor, *args, **kwargs):
- """Convenience wrapper for GenericRetry based on exceptions.
-
- Args:
- exc_retry: A class (or tuple of classes). If the raised exception
- is the given class(es), a retry will be attempted. Otherwise,
- the exception is raised.
- max_retry: See GenericRetry.
- functor: See GenericRetry.
- *args: See GenericRetry.
- **kwargs: See GenericRetry.
-
- Returns:
- Return what functor returns.
-
- Raises:
- TypeError, if exc_retry is of an unexpected type.
- """
- if not isinstance(exc_retry, (tuple, type)):
- raise TypeError("exc_retry should be an exception (or tuple), not %r" %
- exc_retry)
- def _Handler(exc, values=exc_retry):
- return isinstance(exc, values)
- return GenericRetry(_Handler, max_retry, functor, *args, **kwargs)
diff --git a/utils/python/systrace/systrace_utils.py b/utils/python/systrace/systrace_utils.py
index 215c71d..74e00b0 100644
--- a/utils/python/systrace/systrace_utils.py
+++ b/utils/python/systrace/systrace_utils.py
@@ -111,8 +111,7 @@
process = controller.process_name
time = feature_utils.GetTimestamp()
report_path = getattr(self, keys.ConfigKeys.IKEY_SYSTRACE_REPORT_PATH)
- report_destination_file_name = '{module}_{test}_{process}_{time}.html'.format(
- module=test_module_name,
+ report_destination_file_name = 'systrace_{test}_{process}_{time}.html'.format(
test=test_name,
process=process,
time=time)
diff --git a/utils/python/retry/__init__.py b/utils/python/vndk/__init__.py
similarity index 100%
copy from utils/python/retry/__init__.py
copy to utils/python/vndk/__init__.py
diff --git a/utils/python/vndk/vndk_utils.py b/utils/python/vndk/vndk_utils.py
new file mode 100644
index 0000000..d52686d
--- /dev/null
+++ b/utils/python/vndk/vndk_utils.py
@@ -0,0 +1,95 @@
+#
+# Copyright (C) 2017 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.
+#
+
+import logging
+
+from vts.utils.python.android import api
+
+
+def IsVndkRuntimeEnforced(dut):
+ """Returns whether VNDK runtime should be enabled on the device.
+
+ VNDK runtime is optional in O-MR1 (API 27); enforced after O-MR1. If it is
+ enabled, the device has the property of vndk_version.
+ The usage of this function is to decide whether to skip VNDK test cases.
+
+ Args:
+ dut: The AndroidDevice under test.
+
+ Returns:
+ A boolean, whether VNDK runtime should be enabled.
+ """
+ api_level = dut.getLaunchApiLevel(strict=False)
+ if not api_level:
+ logging.error("Cannot get first API level. "
+ "Assume VNDK runtime to be enforced.")
+ return True
+ return bool(api_level > api.PLATFORM_API_LEVEL_O_MR1 or dut.vndk_version)
+
+
+def FormatVndkPath(pattern, bitness, version=""):
+ """Formats a VNDK path.
+
+ Args:
+ pattern: The path pattern containing {LIB} and {VER}.
+ bitness: A string or an integer, 32 or 64.
+ version: A string, the VNDK version.
+
+ Returns:
+ A string, the formatted path.
+ """
+ return pattern.format(
+ LIB=("lib64" if str(bitness) == "64" else "lib"),
+ VER=("-" + version if version and version != "current" else ""))
+
+
+def GetVndkCoreDirectory(bitness, version):
+ """Returns the path to VNDK-core directory on device.
+
+ Args:
+ bitness: A string or an integer, 32 or 64.
+ version: A string, the VNDK version.
+
+ Returns:
+ A string, the path to VNDK-core directory.
+ """
+ return FormatVndkPath("/system/{LIB}/vndk{VER}", bitness, version)
+
+
+def GetVndkSpDirectory(bitness, version):
+ """Returns the path to VNDK-SP directory on device.
+
+ Args:
+ bitness: A string or an integer, 32 or 64.
+ version: A string, the VNDK version.
+
+ Returns:
+ A string, the path to VNDK-SP directory.
+ """
+ return FormatVndkPath("/system/{LIB}/vndk-sp{VER}", bitness, version)
+
+
+def GetVndkSpExtDirectories(bitness):
+ """Returns the paths to VNDK-SP extension directories on device.
+
+ Args:
+ bitness: A string or an integer, 32 or 64.
+
+ Returns:
+ A list of strings, the paths to VNDK-SP extension directories.
+ """
+ return [FormatVndkPath("/odm/{LIB}/vndk-sp", bitness),
+ FormatVndkPath("/vendor/{LIB}/vndk-sp", bitness)]
diff --git a/utils/python/web/web_utils.py b/utils/python/web/web_utils.py
index 43f2433..ebcc762 100644
--- a/utils/python/web/web_utils.py
+++ b/utils/python/web/web_utils.py
@@ -33,7 +33,7 @@
"""Feature object for web functionality.
Attributes:
- enabled: boolean, True if systrace is enabled, False otherwise
+ enabled: boolean, True if web feature is enabled, False otherwise
report_msg: TestReportMessage, Proto summarizing the test run
current_test_report_msg: TestCaseReportMessage, Proto summarizing the current test case
rest_client: DashboardRestClient, client to which data will be posted
@@ -47,7 +47,10 @@
keys.ConfigKeys.IKEY_ANDROID_DEVICE, keys.ConfigKeys.IKEY_ABI_NAME,
keys.ConfigKeys.IKEY_ABI_BITNESS
]
- _OPTIONAL_PARAMS = []
+ _OPTIONAL_PARAMS = [
+ keys.ConfigKeys.RUN_AS_VTS_SELFTEST,
+ keys.ConfigKeys.IKEY_ENABLE_PROFILING,
+ ]
def __init__(self, user_params):
"""Initializes the web feature.
@@ -77,6 +80,11 @@
self.report_msg = ReportMsg.TestReportMessage()
self.report_msg.test = str(
getattr(self, keys.ConfigKeys.KEY_TESTBED_NAME))
+
+ if getattr(self, keys.ConfigKeys.IKEY_ENABLE_PROFILING, False):
+ logging.info("Profiling test")
+ self.report_msg.test += "Profiling"
+
self.report_msg.test_type = ReportMsg.VTS_HOST_DRIVEN_STRUCTURAL
self.report_msg.start_timestamp = feature_utils.GetTimestamp()
self.report_msg.host_info.hostname = socket.gethostname()
@@ -386,7 +394,8 @@
return None
# Handle case when runner fails, tests aren't executed
- if (executed and executed[-1].test_name == "setup_class"):
+ if (not getattr(self, keys.ConfigKeys.RUN_AS_VTS_SELFTEST, False)
+ and executed and executed[-1].test_name == "setup_class"):
# Test failed during setup, all tests were not executed
start_index = 0
else: