Merge "[Atest] Set raw data mode to be default while running robolectric test."
diff --git a/.classpath b/.classpath
index 6eee727..5ed457d 100644
--- a/.classpath
+++ b/.classpath
@@ -28,5 +28,6 @@
<classpathentry kind="var" path="TRADEFED_ROOT/out/soong/.intermediates/external/jacoco/jacoco-cli/linux_glibc_common/combined/jacoco-cli.jar"/>
<classpathentry exported="true" kind="var" path="TRADEFED_ROOT/prebuilts/tools/common/google-api-services-storage/1.23.0/google-api-services-storage-v1-rev114-1.23.0.jar"/>
<classpathentry kind="var" path="TRADEFED_ROOT/out/soong/.intermediates/tools/tradefederation/core/tradefed-protos/linux_glibc_common/combined/tradefed-protos.jar"/>
+ <classpathentry kind="var" path="TRADEFED_ROOT/prebuilts/tools/common/m2/repository/com/google/code/gson/gson/2.8.0/gson-2.8.0.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/atest/Android.bp b/atest/Android.bp
index d67972b..f1facb3 100644
--- a/atest/Android.bp
+++ b/atest/Android.bp
@@ -52,6 +52,7 @@
exclude_srcs: [
"*_unittest.py",
"*/*_unittest.py",
+ "asuite_lib_test/*.py",
"proto/*_pb2.py",
"proto/__init__.py",
],
@@ -111,6 +112,7 @@
"unittest_data/**/.*",
],
exclude_srcs: [
+ "asuite_lib_test/*.py",
"proto/*_pb2.py",
"proto/__init__.py",
],
@@ -174,3 +176,4 @@
"asuite_metrics",
],
}
+
diff --git a/atest/TEST_MAPPING b/atest/TEST_MAPPING
index 0769294..5ea63b3 100644
--- a/atest/TEST_MAPPING
+++ b/atest/TEST_MAPPING
@@ -3,6 +3,22 @@
{
"name": "atest_unittests",
"host": true
+ },
+ {
+ "name": "asuite_metrics_lib_tests",
+ "host": true
+ },
+ {
+ "name": "asuite_metrics_lib_py3_tests",
+ "host": true
+ },
+ {
+ "name": "asuite_cc_lib_tests",
+ "host": true
+ },
+ {
+ "name": "asuite_cc_lib_py3_tests",
+ "host": true
}
]
}
diff --git a/atest/asuite_lib_test/Android.bp b/atest/asuite_lib_test/Android.bp
new file mode 100644
index 0000000..ba93d93
--- /dev/null
+++ b/atest/asuite_lib_test/Android.bp
@@ -0,0 +1,83 @@
+// Copyright (C) 2019 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.
+
+// Separate asuite_metrics and asuite_cc_client libs to different tests, due to asuite_cc_client
+// also include asuite_metrics and other needed python files, in order to make sure asuite_metrics
+// tests result is accurate, separate them to two different test modules.
+
+// For testing asuite_metrics python2 libs
+python_test_host {
+ name: "asuite_metrics_lib_tests",
+ main: "asuite_lib_run_test.py",
+ // These tests primarily check that the metric libs can be imported properly (see b/132086641).
+ // Specify a different pkg_path so that we can properly test them in isolation.
+ pkg_path: "asuite_test",
+ srcs: [
+ "asuite_lib_run_test.py",
+ "asuite_metrics_test.py",
+ ],
+ libs: [
+ "asuite_metrics",
+ ],
+ test_suites: ["general-tests"],
+ defaults: ["atest_py2_default"],
+}
+
+// For testing asuite_metrics python3 libs
+python_test_host {
+ name: "asuite_metrics_lib_py3_tests",
+ main: "asuite_lib_run_test.py",
+ pkg_path: "asuite_test",
+ srcs: [
+ "asuite_lib_run_test.py",
+ "asuite_metrics_test.py",
+ ],
+ libs: [
+ "asuite_metrics",
+ ],
+ test_suites: ["general-tests"],
+ defaults: ["atest_lib_default"],
+}
+
+// For testing asuite_cc_client python2 libs
+python_test_host {
+ name: "asuite_cc_lib_tests",
+ main: "asuite_lib_run_test.py",
+ pkg_path: "asuite_test",
+ srcs: [
+ "asuite_lib_run_test.py",
+ "asuite_cc_client_test.py",
+ ],
+ libs: [
+ "asuite_cc_client",
+ ],
+ test_suites: ["general-tests"],
+ defaults: ["atest_py2_default"],
+}
+
+// For testing asuite_cc_client python3 libs
+python_test_host {
+ name: "asuite_cc_lib_py3_tests",
+ main: "asuite_lib_run_test.py",
+ pkg_path: "asuite_test",
+ srcs: [
+ "asuite_lib_run_test.py",
+ "asuite_cc_client_test.py",
+ ],
+ libs: [
+ "asuite_cc_client",
+ ],
+ test_suites: ["general-tests"],
+ defaults: ["atest_lib_default"],
+}
diff --git a/atest/asuite_lib_test/asuite_cc_client_test.py b/atest/asuite_lib_test/asuite_cc_client_test.py
new file mode 100755
index 0000000..8ae1068
--- /dev/null
+++ b/atest/asuite_lib_test/asuite_cc_client_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+#
+# Copyright 2019, 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.
+
+"""Unittest for atest_execution_info."""
+
+import unittest
+
+
+class AsuiteCCLibTest(unittest.TestCase):
+ """Tests for verify asuite_metrics libs"""
+
+ def test_import_asuite_cc_lib(self):
+ """Test asuite_cc_lib."""
+ # pylint: disable=import-error, unused-variable
+ from asuite.metrics import metrics
+ from asuite.metrics import metrics_base
+ from asuite.metrics import metrics_utils
+
+ # TODO (b/132602907): Add the real usage for checking if metrics pass or fail.
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/atest/asuite_lib_test/asuite_lib_run_test.py b/atest/asuite_lib_test/asuite_lib_run_test.py
new file mode 100644
index 0000000..ad98ae8
--- /dev/null
+++ b/atest/asuite_lib_test/asuite_lib_run_test.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+#
+# Copyright 2019 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.
+"""Main entrypoint for all of atest's unittest."""
+
+import os
+import sys
+import unittest
+from importlib import import_module
+
+
+def get_test_modules():
+ """Returns a list of test modules.
+
+ Finds all the test files (*_test.py) and get their relative
+ path (internal/lib/utils_test.py) and translate it to an import path and
+ strip the py ext (internal.lib.utils_test).
+
+ Returns:
+ List of strings (the testable module import path).
+ """
+ testable_modules = []
+ base_path = os.path.dirname(os.path.realpath(__file__))
+
+ for dirpath, _, files in os.walk(base_path):
+ for f in files:
+ if f.endswith("_test.py"):
+ # Now transform it into a relative import path.
+ full_file_path = os.path.join(dirpath, f)
+ rel_file_path = os.path.relpath(full_file_path, base_path)
+ rel_file_path, _ = os.path.splitext(rel_file_path)
+ rel_file_path = rel_file_path.replace(os.sep, ".")
+ testable_modules.append(rel_file_path)
+
+ return testable_modules
+
+
+def main(_):
+ """Main unittest entry.
+
+ Args:
+ argv: A list of system arguments. (unused)
+
+ Returns:
+ 0 if success. None-zero if fails.
+ """
+ # Force remove syspath related to atest to make sure the env is clean.
+ # These tests need to run in isolation (to find bugs like b/132086641)
+ # so we scrub out all atest modules.
+ for path in sys.path:
+ if path.endswith('/atest'):
+ sys.path.remove(path)
+ test_modules = get_test_modules()
+ for mod in test_modules:
+ import_module(mod)
+
+ loader = unittest.defaultTestLoader
+ test_suite = loader.loadTestsFromNames(test_modules)
+ runner = unittest.TextTestRunner(verbosity=2)
+ result = runner.run(test_suite)
+ sys.exit(not result.wasSuccessful())
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/atest/asuite_lib_test/asuite_metrics_test.py b/atest/asuite_lib_test/asuite_metrics_test.py
new file mode 100755
index 0000000..b150f7f
--- /dev/null
+++ b/atest/asuite_lib_test/asuite_metrics_test.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# Copyright 2019, 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.
+
+"""Unittest for atest_execution_info."""
+
+import unittest
+
+
+class AsuiteMetricsTest(unittest.TestCase):
+ """Tests for verify asuite_metrics libs"""
+
+ def test_import_asuite_metrics_lib(self):
+ """Test asuite_metrics_lib."""
+ # pylint: disable=import-error, unused-variable
+ from asuite import asuite_metrics
+
+ # TODO (b/132602907): Add the real usage for checking if metrics pass or fail.
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/atest/test_finders/module_finder.py b/atest/test_finders/module_finder.py
index e3767e4..6c3ecd6 100644
--- a/atest/test_finders/module_finder.py
+++ b/atest/test_finders/module_finder.py
@@ -212,13 +212,12 @@
return test_config
return rel_config
- def _get_test_info_filter(self, path, methods, module_name, **kwargs):
+ def _get_test_info_filter(self, path, methods, **kwargs):
"""Get test info filter.
Args:
path: A string of the test's path.
methods: A set of method name strings.
- module_name: A string of the module name.
rel_module_dir: Optional. A string of the module dir relative to
root.
class_name: Optional. A string of the class name.
@@ -251,7 +250,6 @@
kwargs.get('class_name', '*'), methods), frozenset())])
# Path to non-module dir, treat as package.
elif (not file_name
- and not self.module_info.is_auto_gen_test_config(module_name)
and kwargs.get('rel_module_dir', None) !=
os.path.relpath(path, self.root_dir)):
dir_items = [os.path.join(path, f) for f in os.listdir(path)]
@@ -371,7 +369,7 @@
if not test_path:
return None
test_filter = self._get_test_info_filter(
- test_path, methods, module_name, class_name=class_name,
+ test_path, methods, class_name=class_name,
is_native_test=is_native_test)
tinfo = self._get_test_info(test_path, rel_config, module_name,
test_filter)
@@ -488,7 +486,7 @@
if not rel_module_dir:
return None
rel_config = os.path.join(rel_module_dir, constants.MODULE_CONFIG)
- test_filter = self._get_test_info_filter(path, methods, None,
+ test_filter = self._get_test_info_filter(path, methods,
rel_module_dir=rel_module_dir)
return self._get_test_info(path, rel_config, None, test_filter)
diff --git a/proto/summary_record.proto b/proto/summary_record.proto
deleted file mode 100644
index a3a72b7..0000000
--- a/proto/summary_record.proto
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-syntax = "proto3";
-
-import "google/protobuf/any.proto";
-import "google/protobuf/timestamp.proto";
-import "tools/tradefederation/core/proto/metric_measurement.proto";
-
-option java_package = "com.android.tradefed.result.proto";
-option java_outer_classname = "SummaryRecordProto";
-
-package android_summary_record;
-
-// A Summary of the top level information related to an invocation.
-message SummaryRecord {
-
- // The total number of expected test cases.
- int64 num_expected_tests = 1;
-
- // The total number of executed test cases.
- int64 num_total_tests = 2;
-
- // The total number of failed test cases.
- int64 num_failed_tests = 3;
-
- // The total number of failed test runs.
- int64 num_failed_runs = 4;
-
- // Extra debugging information for the invocation level, if set an invocation
- // failure occurred and this field contains the error.
- string error_message = 5;
-
- // A short summary message or link associated with the invocation.
- string summary_message = 6;
-
- // The time at which this invocation started.
- google.protobuf.Timestamp start_time = 7;
-
- // The time at which this invocation finished.
- google.protobuf.Timestamp end_time = 8;
-
- // Metadata describing the invocation that was run.
- google.protobuf.Any description = 9;
-}
\ No newline at end of file
diff --git a/remote/.classpath b/remote/.classpath
index b59b5c8..74e2efb 100644
--- a/remote/.classpath
+++ b/remote/.classpath
@@ -10,7 +10,6 @@
<classpathentry exported="true" kind="var" path="TRADEFED_ROOT/prebuilts/misc/common/sdklib/sdklib-prebuilt.jar"/>
<classpathentry exported="true" kind="var" path="TRADEFED_ROOT/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
- <classpathentry kind="var" path="TRADEFED_ROOT/out/soong/.intermediates/external/guava/guava/linux_glibc_common/combined/guava.jar"/>
<classpathentry kind="var" path="TRADEFED_ROOT/external/error_prone/error_prone/error_prone_annotations-2.3.2.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/src/com/android/tradefed/device/NativeDevice.java b/src/com/android/tradefed/device/NativeDevice.java
index 92c2c83..a1d307a 100644
--- a/src/com/android/tradefed/device/NativeDevice.java
+++ b/src/com/android/tradefed/device/NativeDevice.java
@@ -37,6 +37,7 @@
import com.android.tradefed.device.contentprovider.ContentProviderHandler;
import com.android.tradefed.host.IHostOptions;
import com.android.tradefed.log.ITestLogger;
+import com.android.tradefed.log.LogUtil;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.ByteArrayInputStreamSource;
import com.android.tradefed.result.FileInputStreamSource;
@@ -222,6 +223,8 @@
/** Keep track of the last time Tradefed itself triggered a reboot. */
private long mLastTradefedRebootTime = 0L;
+ private File mExecuteShellCommandLogs = null;
+
/**
* Interface for a generic device communication attempt.
*/
@@ -713,7 +716,29 @@
CollectingOutputReceiver receiver = new CollectingOutputReceiver();
executeShellCommand(command, receiver);
String output = receiver.getOutput();
- CLog.v("%s on %s returned %s", command, getSerialNumber(), output);
+ if (mExecuteShellCommandLogs != null) {
+ // Log all output to a dedicated file as it can be very verbose.
+ String formatted =
+ LogUtil.getLogFormatString(
+ LogLevel.VERBOSE,
+ "NativeDevice",
+ String.format(
+ "%s on %s returned %s\n==== END OF OUTPUT ====\n",
+ command, getSerialNumber(), output));
+ try {
+ FileUtil.writeToFile(formatted, mExecuteShellCommandLogs, true);
+ } catch (IOException e) {
+ // Ignore the full error
+ CLog.e("Failed to log to executeShellCommand log: %s", e.getMessage());
+ }
+ }
+ if (output.length() > 80) {
+ CLog.v(
+ "%s on %s returned %s <truncated - See executeShellCommand log for full trace>",
+ command, getSerialNumber(), output.substring(0, 80));
+ } else {
+ CLog.v("%s on %s returned %s", command, getSerialNumber(), output);
+ }
return output;
}
@@ -4083,6 +4108,13 @@
// Default implementation
mContentProvider = null;
mShouldSkipContentProviderSetup = false;
+ try {
+ mExecuteShellCommandLogs =
+ FileUtil.createTempFile("TestDevice_ExecuteShellCommands", ".txt");
+ } catch (IOException e) {
+ throw new TargetSetupError(
+ "Failed to create the executeShellCommand log file.", e, getDeviceDescriptor());
+ }
}
/**
@@ -4090,6 +4122,8 @@
*/
@Override
public void postInvocationTearDown() {
+ FileUtil.deleteFile(mExecuteShellCommandLogs);
+ mExecuteShellCommandLogs = null;
// Default implementation
if (getIDevice() instanceof StubDevice) {
return;
@@ -4434,4 +4468,9 @@
void resetContentProviderSetup() {
mShouldSkipContentProviderSetup = false;
}
+
+ /** The log that contains all the {@link #executeShellCommand(String)} logs. */
+ public final File getExecuteShellCommandLog() {
+ return mExecuteShellCommandLogs;
+ }
}
diff --git a/src/com/android/tradefed/device/metric/HostStatsdMetricCollector.java b/src/com/android/tradefed/device/metric/HostStatsdMetricCollector.java
index 70ea199..4f2e029 100644
--- a/src/com/android/tradefed/device/metric/HostStatsdMetricCollector.java
+++ b/src/com/android/tradefed/device/metric/HostStatsdMetricCollector.java
@@ -16,6 +16,7 @@
package com.android.tradefed.device.metric;
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;
@@ -36,6 +37,7 @@
* commands. It has basic push metrics and dump report functions. It can be extended by subclasses
* to process statsd metric report based on the needs.
*/
+@OptionClass(alias = "host-statsd-collector")
public class HostStatsdMetricCollector extends BaseDeviceMetricCollector {
@Option(name = "binary-stats-config", description = "Path to the binary Statsd config file")
diff --git a/src/com/android/tradefed/invoker/RemoteInvocationExecution.java b/src/com/android/tradefed/invoker/RemoteInvocationExecution.java
index 3051db9..f615387 100644
--- a/src/com/android/tradefed/invoker/RemoteInvocationExecution.java
+++ b/src/com/android/tradefed/invoker/RemoteInvocationExecution.java
@@ -42,7 +42,6 @@
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.result.proto.FileProtoResultReporter;
import com.android.tradefed.result.proto.ProtoResultParser;
-import com.android.tradefed.result.proto.SummaryProtoResultReporter;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
import com.android.tradefed.util.CommandResult;
@@ -78,7 +77,6 @@
public static final String REMOTE_USER_DIR = "/home/{$USER}/";
public static final String PROTO_RESULT_NAME = "output.pb";
- public static final String PROTO_SUMMARY_NAME = "summary-output.pb";
public static final String STDOUT_FILE = "screen-VM_tradefed-stdout.txt";
public static final String STDERR_FILE = "screen-VM_tradefed-stderr.txt";
public static final String REMOTE_CONFIG = "configuration";
@@ -524,10 +522,6 @@
FileProtoResultReporter protoReporter = new FileProtoResultReporter();
protoReporter.setFileOutput(new File(resultDirPath + PROTO_RESULT_NAME));
reporters.add(protoReporter);
- // Setup a summary reporter
- SummaryProtoResultReporter summaryReporter = new SummaryProtoResultReporter();
- summaryReporter.setFileOutput(new File(resultDirPath + PROTO_SUMMARY_NAME));
- reporters.add(summaryReporter);
config.setTestInvocationListeners(reporters);
diff --git a/src/com/android/tradefed/invoker/TestInvocation.java b/src/com/android/tradefed/invoker/TestInvocation.java
index f8f96ac..b7b2599 100644
--- a/src/com/android/tradefed/invoker/TestInvocation.java
+++ b/src/com/android/tradefed/invoker/TestInvocation.java
@@ -25,9 +25,12 @@
import com.android.tradefed.device.DeviceUnresponsiveException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.ITestDevice.RecoveryMode;
+import com.android.tradefed.device.NativeDevice;
import com.android.tradefed.device.StubDevice;
import com.android.tradefed.device.TestDeviceState;
import com.android.tradefed.device.cloud.ManagedRemoteDevice;
+import com.android.tradefed.device.cloud.NestedRemoteDevice;
+import com.android.tradefed.device.cloud.RemoteAndroidVirtualDevice;
import com.android.tradefed.guice.InvocationScope;
import com.android.tradefed.invoker.sandbox.ParentSandboxInvocationExecution;
import com.android.tradefed.invoker.sandbox.SandboxedInvocationExecution;
@@ -35,9 +38,11 @@
import com.android.tradefed.log.BaseLeveledLogOutput;
import com.android.tradefed.log.ILeveledLogOutput;
import com.android.tradefed.log.ILogRegistry;
+import com.android.tradefed.log.ITestLogger;
import com.android.tradefed.log.LogRegistry;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.postprocessor.IPostProcessor;
+import com.android.tradefed.result.FileInputStreamSource;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.InputStreamSource;
import com.android.tradefed.result.LogDataType;
@@ -50,6 +55,7 @@
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IResumableTest;
import com.android.tradefed.testtype.IRetriableTest;
+import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.IRunUtil;
import com.android.tradefed.util.PrettyPrintDelimiter;
import com.android.tradefed.util.RunInterruptedException;
@@ -58,6 +64,7 @@
import com.google.common.annotations.VisibleForTesting;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -303,6 +310,9 @@
takeBugreport(badDevice, listener, bugreportName);
}
}
+ // Save the device executeShellCommand logs
+ logExecuteShellCommand(context.getDevices(), listener);
+
mStatus = "tearing down";
try {
invocationPath.doTeardown(context, config, listener, exception);
@@ -527,6 +537,11 @@
if (testDevice.getIDevice() instanceof StubDevice) {
continue;
}
+ if (testDevice instanceof RemoteAndroidVirtualDevice
+ || testDevice instanceof NestedRemoteDevice) {
+ // Vritual devices have a fake battery there is no point in logging it.
+ continue;
+ }
Integer batteryLevel = testDevice.getBattery();
if (batteryLevel == null) {
CLog.v("Failed to get battery level for %s", testDevice.getSerialNumber());
@@ -812,4 +827,30 @@
String message = String.format("===== %s PHASE %s =====", phase, startEnd);
PrettyPrintDelimiter.printStageDelimiter(message);
}
+
+ private void logExecuteShellCommand(List<ITestDevice> devices, ITestLogger logger) {
+ for (ITestDevice device : devices) {
+ if (!(device instanceof NativeDevice)) {
+ return;
+ }
+ File log = ((NativeDevice) device).getExecuteShellCommandLog();
+ if (log == null || !log.exists()) {
+ return;
+ }
+ try {
+ if (log != null && !FileUtil.readStringFromFile(log).isEmpty()) {
+ try (InputStreamSource source = new FileInputStreamSource(log)) {
+ logger.testLog(
+ String.format(
+ "executeShellCommandLog_%s", device.getSerialNumber()),
+ LogDataType.TEXT,
+ source);
+ }
+ }
+ } catch (IOException e) {
+ // Ignored
+ CLog.e(e);
+ }
+ }
+ }
}
diff --git a/src/com/android/tradefed/result/IResultSummaryReceiver.java b/src/com/android/tradefed/result/IResultSummaryReceiver.java
deleted file mode 100644
index 23644e8..0000000
--- a/src/com/android/tradefed/result/IResultSummaryReceiver.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2019 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.result;
-
-import com.android.tradefed.result.proto.SummaryRecordProto.SummaryRecord;
-
-/**
- * Interface describing an {@link ITestInvocationListener} that can receive a summary of the
- * invocation only instead of the full results.
- */
-public interface IResultSummaryReceiver {
-
- /**
- * Callback where the {@link SummaryRecord} of the results is passed. Will always be called
- * before {@link ITestInvocationListener#invocationEnded(long)}.
- *
- * @param summary a {@link SummaryRecord} containing the summary of the invocation.
- */
- public void setResultSummary(SummaryRecord summary);
-}
diff --git a/src/com/android/tradefed/result/LogSaverResultForwarder.java b/src/com/android/tradefed/result/LogSaverResultForwarder.java
index 14d9f84..6e379a2 100644
--- a/src/com/android/tradefed/result/LogSaverResultForwarder.java
+++ b/src/com/android/tradefed/result/LogSaverResultForwarder.java
@@ -18,14 +18,12 @@
import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.result.proto.SummaryRecordProto.SummaryRecord;
import java.io.IOException;
import java.util.List;
/** A {@link ResultForwarder} for saving logs with the global file saver. */
-public class LogSaverResultForwarder extends ResultForwarder
- implements ILogSaverListener, IResultSummaryReceiver {
+public class LogSaverResultForwarder extends ResultForwarder implements ILogSaverListener {
ILogSaver mLogSaver;
@@ -134,20 +132,4 @@
}
}
}
-
- /** {@inheritDoc} */
- @Override
- public void setResultSummary(SummaryRecord summary) {
- for (ITestInvocationListener listener : getListeners()) {
- try {
- // Forward the logAssociation call
- if (listener instanceof IResultSummaryReceiver) {
- ((IResultSummaryReceiver) listener).setResultSummary(summary);
- }
- } catch (RuntimeException e) {
- CLog.e("Failed to setResultSummary on %s", listener);
- CLog.e(e);
- }
- }
- }
}
\ No newline at end of file
diff --git a/src/com/android/tradefed/result/proto/SummaryProtoParser.java b/src/com/android/tradefed/result/proto/SummaryProtoParser.java
deleted file mode 100644
index 7b635e8..0000000
--- a/src/com/android/tradefed/result/proto/SummaryProtoParser.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2019 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.result.proto;
-
-import com.android.tradefed.result.proto.SummaryRecordProto.SummaryRecord;
-import com.android.tradefed.util.ByteArrayList;
-
-import com.google.protobuf.CodedInputStream;
-import com.google.protobuf.InvalidProtocolBufferException;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-public class SummaryProtoParser {
-
- /**
- * Pick a 4MB default size to allow the buffer to grow for big protobuf. The default value could
- * fail in some cases.
- */
- private static final int DEFAULT_SIZE_BYTES = 4 * 1024 * 1024;
-
- /**
- * Read {@link SummaryRecord} from a file and return it.
- *
- * @param protoFile The {@link File} containing the record
- * @return a {@link SummaryRecord} created from the file.
- * @throws IOException, InvalidProtocolBufferException
- */
- public static SummaryRecord readFromFile(File protoFile)
- throws IOException, InvalidProtocolBufferException {
- SummaryRecord record = null;
- try (InputStream stream = new FileInputStream(protoFile)) {
- CodedInputStream is = CodedInputStream.newInstance(stream);
- is.setSizeLimit(Integer.MAX_VALUE);
- ByteArrayList data = new ByteArrayList(DEFAULT_SIZE_BYTES);
- while (!is.isAtEnd()) {
- int size = is.readRawVarint32();
- byte[] dataByte = is.readRawBytes(size);
- data.addAll(dataByte);
- }
- record = SummaryRecord.parseFrom(data.getContents());
- data.clear();
- }
- return record;
- }
-}
diff --git a/src/com/android/tradefed/result/proto/SummaryProtoResultReporter.java b/src/com/android/tradefed/result/proto/SummaryProtoResultReporter.java
deleted file mode 100644
index dc63a04..0000000
--- a/src/com/android/tradefed/result/proto/SummaryProtoResultReporter.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2019 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.result.proto;
-
-import com.android.tradefed.config.Option;
-import com.android.tradefed.invoker.IInvocationContext;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.result.CollectingTestListener;
-import com.android.tradefed.result.proto.SummaryRecordProto.SummaryRecord;
-import com.android.tradefed.util.StreamUtil;
-
-import com.google.protobuf.Any;
-import com.google.protobuf.Timestamp;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Reporters that creates a summary proto from an invocation. The summary contains some minimal
- * informations about the invocation.
- */
-public class SummaryProtoResultReporter extends CollectingTestListener {
-
- @Option(
- name = "summary-proto-output-file",
- description = "File where the proto output will be saved",
- mandatory = true
- )
- private File mOutputFile;
-
- private Throwable mInvocationFailure = null;
- private long mStartTimeMs;
- private long mEndTimeMs;
-
- @Override
- public void invocationStarted(IInvocationContext context) {
- mStartTimeMs = System.currentTimeMillis();
- super.invocationStarted(context);
- }
-
- @Override
- public void invocationFailed(Throwable cause) {
- super.invocationFailed(cause);
- mInvocationFailure = cause;
- }
-
- @Override
- public void invocationEnded(long elapsedTime) {
- mEndTimeMs = System.currentTimeMillis();
- super.invocationEnded(elapsedTime);
- writeSummaryProto();
- }
-
- /** Sets the file where to output the result. */
- public void setFileOutput(File output) {
- mOutputFile = output;
- }
-
- private void writeSummaryProto() {
- if (mOutputFile == null) {
- return;
- }
- SummaryRecord.Builder builder = SummaryRecord.newBuilder();
- // Populate the proto
- builder.setNumExpectedTests(getExpectedTests());
- builder.setNumTotalTests(getNumTotalTests());
- builder.setNumFailedTests(getNumAllFailedTests());
- builder.setNumFailedRuns(getNumAllFailedTestRuns());
- if (mInvocationFailure != null) {
- builder.setErrorMessage(StreamUtil.getStackTrace(mInvocationFailure));
- }
- builder.setStartTime(createTimeStamp(mStartTimeMs));
- builder.setEndTime(createTimeStamp(mEndTimeMs));
- builder.setDescription(Any.pack(getInvocationContext().toProto()));
- // Build and write the proto
- SummaryRecord record = builder.build();
- try {
- record.writeDelimitedTo(new FileOutputStream(mOutputFile));
- } catch (IOException e) {
- CLog.e(e);
- throw new RuntimeException(e);
- }
- }
-
- /** Create and populate Timestamp as recommended in the javadoc of the Timestamp proto. */
- private Timestamp createTimeStamp(long currentTimeMs) {
- return Timestamp.newBuilder()
- .setSeconds(currentTimeMs / 1000)
- .setNanos((int) ((currentTimeMs % 1000) * 1000000))
- .build();
- }
-}
diff --git a/src/com/android/tradefed/result/suite/XmlSuiteResultFormatter.java b/src/com/android/tradefed/result/suite/XmlSuiteResultFormatter.java
index 1d8e981..1aa9997 100644
--- a/src/com/android/tradefed/result/suite/XmlSuiteResultFormatter.java
+++ b/src/com/android/tradefed/result/suite/XmlSuiteResultFormatter.java
@@ -15,6 +15,7 @@
*/
package com.android.tradefed.result.suite;
+import com.android.annotations.VisibleForTesting;
import com.android.ddmlib.testrunner.TestResult.TestStatus;
import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.invoker.InvocationContext;
@@ -53,6 +54,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -121,7 +124,7 @@
private static final String LOG_FILE_NAME_ATTR = "file_name";
/** Helper object for JSON conversion. */
- private static final class RunHistory {
+ public static final class RunHistory {
public long startTime;
public long endTime;
}
@@ -266,8 +269,9 @@
serializer.attribute(NS, MODULES_TOTAL_ATTR, Integer.toString(holder.totalModules));
serializer.endTag(NS, SUMMARY_TAG);
+ List<TestRunResult> sortedModuleList = sortModules(holder.runResults, holder.modulesAbi);
// Results
- for (TestRunResult module : holder.runResults) {
+ for (TestRunResult module : sortedModuleList) {
serializer.startTag(NS, MODULE_TAG);
// To be compatible of CTS strip the abi from the module name when available.
if (holder.modulesAbi.get(module.getName()) != null) {
@@ -521,6 +525,40 @@
return invocation;
}
+ /** Sort the list of results based on their name without abi primarily then secondly on abi. */
+ @VisibleForTesting
+ List<TestRunResult> sortModules(
+ Collection<TestRunResult> results, Map<String, IAbi> moduleAbis) {
+ List<TestRunResult> sortedList = new ArrayList<>(results);
+ Collections.sort(
+ sortedList,
+ new Comparator<TestRunResult>() {
+ @Override
+ public int compare(TestRunResult o1, TestRunResult o2) {
+ String module1NameStripped = o1.getName();
+ String module1Abi = "";
+ if (moduleAbis.get(module1NameStripped) != null) {
+ module1Abi = moduleAbis.get(module1NameStripped).getName();
+ module1NameStripped = module1NameStripped.replace(module1Abi + " ", "");
+ }
+
+ String module2NameStripped = o2.getName();
+ String module2Abi = "";
+ if (moduleAbis.get(module2NameStripped) != null) {
+ module2Abi = moduleAbis.get(module2NameStripped).getName();
+ module2NameStripped = module2NameStripped.replace(module2Abi + " ", "");
+ }
+ int res = module1NameStripped.compareTo(module2NameStripped);
+ if (res != 0) {
+ return res;
+ }
+ // Use the Abi as discriminant to always sort abi in the same order.
+ return module1Abi.compareTo(module2Abi);
+ }
+ });
+ return sortedList;
+ }
+
/** Handle the parsing and replay of all run history information. */
private void handleRunHistoryLevel(XmlPullParser parser)
throws IOException, XmlPullParserException {
diff --git a/src/com/android/tradefed/testtype/AndroidJUnitTest.java b/src/com/android/tradefed/testtype/AndroidJUnitTest.java
index bc70bb6..adee140 100644
--- a/src/com/android/tradefed/testtype/AndroidJUnitTest.java
+++ b/src/com/android/tradefed/testtype/AndroidJUnitTest.java
@@ -145,11 +145,14 @@
private Integer mMaxShard = null;
@Option(
- name = "device-listeners",
- description =
- "Specify a device side instrumentation listener to be added for the run. "
- + "Can be repeated.")
- private Set<String> mExtraDeviceListeners = new HashSet<>();
+ name = "device-listeners",
+ description =
+ "Specify device side instrumentation listeners to be added for the run. "
+ + "Can be repeated. Note that while the ordering here is followed for "
+ + "now, future versions of AndroidJUnitRunner might not preserve the "
+ + "listener ordering."
+ )
+ private List<String> mExtraDeviceListeners = new ArrayList<>();
@Option(
name = "use-new-run-listener-order",
@@ -329,6 +332,8 @@
mDeviceIncludeFile = mTestFilterDir.replaceAll("/$", "") + "/" + INCLUDE_FILE;
pushTestFile(mIncludeTestFile, mDeviceIncludeFile, listener);
pushedFile = true;
+ // If an explicit include file filter is provided, do not use the package
+ setTestPackageName(null);
}
// if mExcludeTestFile is set, perform filtering with this file
diff --git a/src/com/android/tradefed/testtype/InstrumentationTest.java b/src/com/android/tradefed/testtype/InstrumentationTest.java
index 99f8441..f468fdc 100644
--- a/src/com/android/tradefed/testtype/InstrumentationTest.java
+++ b/src/com/android/tradefed/testtype/InstrumentationTest.java
@@ -56,7 +56,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -298,7 +297,7 @@
private ListInstrumentationParser mListInstrumentationParser = null;
- private Set<String> mExtraDeviceListener = new HashSet<>();
+ private List<String> mExtraDeviceListener = new ArrayList<>();
private boolean mIsRerun = false;
@@ -635,7 +634,7 @@
}
/** Allows to add more custom listeners to the runner */
- public void addDeviceListeners(Set<String> extraListeners) {
+ public void addDeviceListeners(List<String> extraListeners) {
mExtraDeviceListener.addAll(extraListeners);
}
diff --git a/src/com/android/tradefed/testtype/suite/SuiteModuleLoader.java b/src/com/android/tradefed/testtype/suite/SuiteModuleLoader.java
index dbc3d9f..78d7b2f 100644
--- a/src/com/android/tradefed/testtype/suite/SuiteModuleLoader.java
+++ b/src/com/android/tradefed/testtype/suite/SuiteModuleLoader.java
@@ -203,7 +203,8 @@
IModuleParameter mForcedParameter = null;
if (mForcedModuleParameter != null) {
mForcedParameter =
- ModuleParametersHelper.getParameterHandler(mForcedModuleParameter);
+ ModuleParametersHelper.getParameterHandler(
+ mForcedModuleParameter, /* optionalParams */ false);
}
// Invokes parser to process the test module config file
@@ -547,7 +548,9 @@
CLog.d("'%s' was excluded via exclude-module-parameters.");
continue;
}
- IModuleParameter handler = ModuleParametersHelper.getParameterHandler(suiteParam);
+ IModuleParameter handler =
+ ModuleParametersHelper.getParameterHandler(
+ suiteParam, /* optionalParams */ false);
params.add(handler);
}
return params;
diff --git a/src/com/android/tradefed/testtype/suite/params/InstantAppHandler.java b/src/com/android/tradefed/testtype/suite/params/InstantAppHandler.java
index 532d51f..5744f64 100644
--- a/src/com/android/tradefed/testtype/suite/params/InstantAppHandler.java
+++ b/src/com/android/tradefed/testtype/suite/params/InstantAppHandler.java
@@ -19,6 +19,7 @@
import android.platform.test.annotations.AppModeInstant;
import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.IDeviceConfiguration;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.targetprep.TestAppInstallSetup;
import com.android.tradefed.testtype.IRemoteTest;
@@ -40,9 +41,11 @@
@Override
public void applySetup(IConfiguration moduleConfiguration) {
// First, force target_preparers if they support it to install app in instant mode.
- for (ITargetPreparer preparer : moduleConfiguration.getTargetPreparers()) {
- if (preparer instanceof TestAppInstallSetup) {
- ((TestAppInstallSetup) preparer).setInstantMode(true);
+ for (IDeviceConfiguration deviceConfig : moduleConfiguration.getDeviceConfig()) {
+ for (ITargetPreparer preparer : deviceConfig.getTargetPreparers()) {
+ if (preparer instanceof TestAppInstallSetup) {
+ ((TestAppInstallSetup) preparer).setInstantMode(true);
+ }
}
}
// TODO: Second, notify HostTest that instant mode might be needed for apks.
diff --git a/src/com/android/tradefed/testtype/suite/params/ModuleParameters.java b/src/com/android/tradefed/testtype/suite/params/ModuleParameters.java
index 71c7b9b..8fca54d 100644
--- a/src/com/android/tradefed/testtype/suite/params/ModuleParameters.java
+++ b/src/com/android/tradefed/testtype/suite/params/ModuleParameters.java
@@ -22,7 +22,9 @@
NOT_INSTANT_APP("not_instant_app", "instant_app_family"),
MULTI_ABI("multi_abi", "multi_abi_family"),
- NOT_MULTI_ABI("not_multi_abi", "multi_abi_family");
+ NOT_MULTI_ABI("not_multi_abi", "multi_abi_family"),
+
+ SECONDARY_USER("secondary_user", "secondary_user_family");
public static final String INSTANT_APP_FAMILY = "instant_app_family";
public static final String MULTI_ABI_FAMILY = "multi_abi_family";
diff --git a/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelper.java b/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelper.java
index 517c6f0..e009976 100644
--- a/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelper.java
+++ b/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelper.java
@@ -31,8 +31,29 @@
sHandlerMap.put(ModuleParameters.NOT_MULTI_ABI, new NotMultiAbiHandler());
}
- /** Returns the {@link IModuleParameter} associated with the requested parameter. */
- public static IModuleParameter getParameterHandler(ModuleParameters param) {
- return sHandlerMap.get(param);
+ /**
+ * Optional parameters are params that will not automatically be created when the module
+ * parameterization is enabled. They will need to be explicitly enabled. They represent a second
+ * set of parameterization that is less commonly requested to run. They could be upgraded to
+ * main parameters in the future by moving them above.
+ */
+ private static Map<ModuleParameters, IModuleParameter> sOptionalHandlerMap = new HashMap<>();
+
+ static {
+ sOptionalHandlerMap.put(ModuleParameters.SECONDARY_USER, new SecondaryUserHandler());
+ }
+
+ /**
+ * Returns the {@link IModuleParameter} associated with the requested parameter.
+ *
+ * @param withOptional Whether or not to also check optional params.
+ */
+ public static IModuleParameter getParameterHandler(
+ ModuleParameters param, boolean withOptional) {
+ IModuleParameter value = sHandlerMap.get(param);
+ if (value == null && withOptional) {
+ return sOptionalHandlerMap.get(param);
+ }
+ return value;
}
}
diff --git a/src/com/android/tradefed/testtype/suite/params/SecondaryUserHandler.java b/src/com/android/tradefed/testtype/suite/params/SecondaryUserHandler.java
new file mode 100644
index 0000000..f4a133d
--- /dev/null
+++ b/src/com/android/tradefed/testtype/suite/params/SecondaryUserHandler.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 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.testtype.suite.params;
+
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.IDeviceConfiguration;
+import com.android.tradefed.targetprep.CreateUserPreparer;
+import com.android.tradefed.targetprep.ITargetPreparer;
+
+import java.util.List;
+
+/** Handler for {@link ModuleParameters#SECONDARY_USER}. */
+public class SecondaryUserHandler implements IModuleParameter {
+
+ @Override
+ public String getParameterIdentifier() {
+ return "secondary_user";
+ }
+
+ @Override
+ public void applySetup(IConfiguration moduleConfiguration) {
+ for (IDeviceConfiguration deviceConfig : moduleConfiguration.getDeviceConfig()) {
+ List<ITargetPreparer> preparers = deviceConfig.getTargetPreparers();
+ preparers.add(0, new CreateUserPreparer());
+ }
+ }
+}
diff --git a/tests/src/com/android/tradefed/UnitTests.java b/tests/src/com/android/tradefed/UnitTests.java
index 1f130b3..c84ef69 100644
--- a/tests/src/com/android/tradefed/UnitTests.java
+++ b/tests/src/com/android/tradefed/UnitTests.java
@@ -163,7 +163,6 @@
import com.android.tradefed.result.proto.ProtoResultParserTest;
import com.android.tradefed.result.proto.ProtoResultReporterTest;
import com.android.tradefed.result.proto.StreamProtoResultReporterTest;
-import com.android.tradefed.result.proto.SummaryProtoResultReporterTest;
import com.android.tradefed.result.suite.FormattedGeneratorReporterTest;
import com.android.tradefed.result.suite.XmlSuiteResultFormatterTest;
import com.android.tradefed.sandbox.SandboxConfigDumpTest;
@@ -562,7 +561,6 @@
ProtoResultParserTest.class,
ProtoResultReporterTest.class,
StreamProtoResultReporterTest.class,
- SummaryProtoResultReporterTest.class,
// result.suite
FormattedGeneratorReporterTest.class,
diff --git a/tests/src/com/android/tradefed/device/cloud/NestedRemoteDeviceTest.java b/tests/src/com/android/tradefed/device/cloud/NestedRemoteDeviceTest.java
index efe6c23..4ac2b17 100644
--- a/tests/src/com/android/tradefed/device/cloud/NestedRemoteDeviceTest.java
+++ b/tests/src/com/android/tradefed/device/cloud/NestedRemoteDeviceTest.java
@@ -30,6 +30,7 @@
import com.android.tradefed.util.CommandStatus;
import com.android.tradefed.util.IRunUtil;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -71,6 +72,11 @@
};
}
+ @After
+ public void tearDown() throws Exception {
+ mDevice.postInvocationTearDown();
+ }
+
/** Test that reset device returns true in case of success */
@Test
public void testResetVirtualDevice() throws DeviceNotAvailableException {
diff --git a/tests/src/com/android/tradefed/invoker/RemoteInvocationExecutionTest.java b/tests/src/com/android/tradefed/invoker/RemoteInvocationExecutionTest.java
index 7427f71..bb688b0 100644
--- a/tests/src/com/android/tradefed/invoker/RemoteInvocationExecutionTest.java
+++ b/tests/src/com/android/tradefed/invoker/RemoteInvocationExecutionTest.java
@@ -34,7 +34,6 @@
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.result.proto.ProtoResultReporter;
-import com.android.tradefed.result.proto.SummaryProtoResultReporter;
import com.android.tradefed.util.FileUtil;
import org.junit.Before;
@@ -98,9 +97,8 @@
ConfigurationFactory.getInstance()
.createConfigurationFromArgs(new String[] {res.getAbsolutePath()});
List<ITestInvocationListener> listeners = reparse.getTestInvocationListeners();
- assertEquals(2, listeners.size());
+ assertEquals(1, listeners.size());
assertTrue(listeners.get(0) instanceof ProtoResultReporter);
- assertTrue(listeners.get(1) instanceof SummaryProtoResultReporter);
// Ensure the requested type is reset
assertNull(
((DeviceSelectionOptions)
diff --git a/tests/src/com/android/tradefed/result/proto/SummaryProtoResultReporterTest.java b/tests/src/com/android/tradefed/result/proto/SummaryProtoResultReporterTest.java
deleted file mode 100644
index 59aaa93..0000000
--- a/tests/src/com/android/tradefed/result/proto/SummaryProtoResultReporterTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2019 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.result.proto;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tradefed.build.BuildInfo;
-import com.android.tradefed.config.ConfigurationDef;
-import com.android.tradefed.config.ConfigurationDescriptor;
-import com.android.tradefed.invoker.IInvocationContext;
-import com.android.tradefed.invoker.InvocationContext;
-import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
-import com.android.tradefed.result.proto.SummaryRecordProto.SummaryRecord;
-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 java.io.File;
-import java.util.HashMap;
-
-/** Unit tests for {@link SummaryProtoResultReporter}. */
-@RunWith(JUnit4.class)
-public class SummaryProtoResultReporterTest {
-
- private SummaryProtoResultReporter mReporter;
- private File mOutputFile;
- private IInvocationContext mContext;
-
- @Before
- public void setUp() throws Exception {
- mOutputFile = FileUtil.createTempFile("test-summary-proto", ".pb");
- mReporter = new SummaryProtoResultReporter();
- mReporter.setFileOutput(mOutputFile);
-
- mContext = new InvocationContext();
- mContext.addDeviceBuildInfo(ConfigurationDef.DEFAULT_DEVICE_NAME, new BuildInfo());
- mContext.setConfigurationDescriptor(new ConfigurationDescriptor());
- }
-
- @After
- public void tearDown() {
- FileUtil.deleteFile(mOutputFile);
- }
-
- @Test
- public void testReportSummary() throws Exception {
- mReporter.invocationStarted(mContext);
- mReporter.testRunStarted("run1", 5);
- mReporter.testRunEnded(5L, new HashMap<String, Metric>());
- mReporter.invocationEnded(500L);
-
- assertTrue(FileUtil.readStringFromFile(mOutputFile).length() > 50);
-
- SummaryRecord summary = SummaryProtoParser.readFromFile(mOutputFile);
- assertEquals(5, summary.getNumExpectedTests());
- assertEquals(0, summary.getNumTotalTests());
- }
-}
diff --git a/tests/src/com/android/tradefed/result/suite/XmlSuiteResultFormatterTest.java b/tests/src/com/android/tradefed/result/suite/XmlSuiteResultFormatterTest.java
index ef697dd..8f61d29 100644
--- a/tests/src/com/android/tradefed/result/suite/XmlSuiteResultFormatterTest.java
+++ b/tests/src/com/android/tradefed/result/suite/XmlSuiteResultFormatterTest.java
@@ -50,6 +50,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -538,6 +539,34 @@
assertEquals(RUN_HISTORY, holder.context.getAttributes().getUniqueMap().get("run_history"));
}
+ /** Ensure the order is sorted according to module name and abi. */
+ @Test
+ public void testSortModules() {
+ List<TestRunResult> originalList = new ArrayList<>();
+ originalList.add(createFakeResult("armeabi-v7a module1", 1, 0, 0, 0));
+ originalList.add(createFakeResult("arm64-v8a module3", 1, 0, 0, 0));
+ originalList.add(createFakeResult("armeabi-v7a module2", 1, 0, 0, 0));
+ originalList.add(createFakeResult("arm64-v8a module1", 1, 0, 0, 0));
+ originalList.add(createFakeResult("armeabi-v7a module4", 1, 0, 0, 0));
+ originalList.add(createFakeResult("arm64-v8a module2", 1, 0, 0, 0));
+ Map<String, IAbi> moduleAbis = new HashMap<>();
+ moduleAbis.put("armeabi-v7a module1", new Abi("armeabi-v7a", "32"));
+ moduleAbis.put("arm64-v8a module1", new Abi("arm64-v8a", "64"));
+ moduleAbis.put("armeabi-v7a module2", new Abi("armeabi-v7a", "32"));
+ moduleAbis.put("arm64-v8a module2", new Abi("arm64-v8a", "64"));
+ moduleAbis.put("arm64-v8a module3", new Abi("arm64-v8a", "64"));
+ moduleAbis.put("armeabi-v7a module4", new Abi("armeabi-v7a", "32"));
+
+ List<TestRunResult> sortedResult = mFormatter.sortModules(originalList, moduleAbis);
+ assertEquals(6, sortedResult.size());
+ assertEquals("arm64-v8a module1", sortedResult.get(0).getName());
+ assertEquals("armeabi-v7a module1", sortedResult.get(1).getName());
+ assertEquals("arm64-v8a module2", sortedResult.get(2).getName());
+ assertEquals("armeabi-v7a module2", sortedResult.get(3).getName());
+ assertEquals("arm64-v8a module3", sortedResult.get(4).getName());
+ assertEquals("armeabi-v7a module4", sortedResult.get(5).getName());
+ }
+
private TestRunResult createResultWithLog(String runName, int count, LogDataType type) {
TestRunResult fakeRes = new TestRunResult();
fakeRes.testRunStarted(runName, count);
diff --git a/tests/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelperTest.java b/tests/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelperTest.java
index 34ef701..bd1f3fb 100644
--- a/tests/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelperTest.java
+++ b/tests/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelperTest.java
@@ -29,7 +29,8 @@
@Test
public void testHandlersExists() {
for (ModuleParameters param : ModuleParameters.values()) {
- IModuleParameter handler = ModuleParametersHelper.getParameterHandler(param);
+ IModuleParameter handler =
+ ModuleParametersHelper.getParameterHandler(param, /* Include optional */ true);
assertNotNull(handler);
}
}