Merge "Update CrashUtils regex to be reluctant." into pi-dev
am: 4ee20c64f2
Change-Id: I2db24fad614653fa3b6ef6fba546cb7aaa6b6e0b
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 94a0e94..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# 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 $(call all-subdir-makefiles)
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..d5f07b9
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,14 @@
+# Android EngProd Approvers
+guangzhu@google.com
+fdeng@google.com
+moonk@google.com
+jdesprez@google.com
+sbasi@google.com
+
+# Android Partner Eng Approvers
+aaronholden@google.com
+yuji@google.com
+nickrose@google.com
+
+# File Specific Approvers
+per-file Backup* = anniemeng@google.com, brufino@google.com, nathch@google.com, rthakohov@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..12604f9
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,11 @@
+[Builtin Hooks]
+google_java_format = true
+
+[Tool Paths]
+google-java-format = ${REPO_ROOT}/prebuilts/tools/common/google-java-format/google-java-format
+google-java-format-diff = ${REPO_ROOT}/prebuilts/tools/common/google-java-format/google-java-format-diff.py
+
+[Hook Scripts]
+# `^.` is a RegExr that matches any character at the beginning, so this hook
+# is basically applied to ALL files in a git commit.
+aospcheck_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^."
diff --git a/build/Android.bp b/build/Android.bp
new file mode 100644
index 0000000..fcf438f
--- /dev/null
+++ b/build/Android.bp
@@ -0,0 +1,16 @@
+bootstrap_go_package {
+ name: "soong-suite-harness",
+ pkgPath: "android/soong/suite_harness",
+ deps: [
+ "blueprint",
+ "blueprint-pathtools",
+ "blueprint-proptools",
+ "soong",
+ "soong-android",
+ "soong-java",
+ ],
+ srcs: [
+ "tradefed_binary.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/build/tradefed_binary.go b/build/tradefed_binary.go
new file mode 100644
index 0000000..6e11eac
--- /dev/null
+++ b/build/tradefed_binary.go
@@ -0,0 +1,156 @@
+// Copyright 2018 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.
+
+package suite_harness
+
+import (
+ "strings"
+
+ "github.com/google/blueprint"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+var pctx = android.NewPackageContext("android/soong/suite_harness")
+
+func init() {
+ android.RegisterModuleType("tradefed_binary_host", tradefedBinaryFactory)
+
+ pctx.Import("android/soong/android")
+}
+
+type TradefedBinaryProperties struct {
+ Short_name string
+ Full_name string
+ Version string
+}
+
+// tradefedBinaryFactory creates an empty module for the tradefed_binary module type,
+// which is a java_binary with some additional processing in tradefedBinaryLoadHook.
+func tradefedBinaryFactory() android.Module {
+ props := &TradefedBinaryProperties{}
+ module := java.BinaryHostFactory()
+ module.AddProperties(props)
+ android.AddLoadHook(module, tradefedBinaryLoadHook(props))
+
+ return module
+}
+
+const genSuffix = "-gen"
+
+// tradefedBinaryLoadHook adds extra resources and libraries to tradefed_binary modules.
+func tradefedBinaryLoadHook(tfb *TradefedBinaryProperties) func(ctx android.LoadHookContext) {
+ return func(ctx android.LoadHookContext) {
+ genName := ctx.ModuleName() + genSuffix
+
+ // Create a submodule that generates the test-suite-info.properties file
+ // and copies DynamicConfig.xml if it is present.
+ ctx.CreateModule(android.ModuleFactoryAdaptor(tradefedBinaryGenFactory),
+ &TradefedBinaryGenProperties{
+ Name: &genName,
+ Short_name: tfb.Short_name,
+ Full_name: tfb.Full_name,
+ Version: tfb.Version,
+ })
+
+ props := struct {
+ Java_resources []string
+ Libs []string
+ }{}
+
+ // Add dependencies required by all tradefed_binary modules.
+ props.Libs = []string{
+ "tradefed",
+ "loganalysis",
+ "hosttestlib",
+ "compatibility-host-util",
+ }
+
+ // Add the files generated by the submodule created above to the resources.
+ props.Java_resources = []string{":" + genName}
+
+ ctx.AppendProperties(&props)
+
+ }
+}
+
+type TradefedBinaryGenProperties struct {
+ Name *string
+ Short_name string
+ Full_name string
+ Version string
+}
+
+type tradefedBinaryGen struct {
+ android.ModuleBase
+
+ properties TradefedBinaryGenProperties
+
+ gen android.Paths
+}
+
+func tradefedBinaryGenFactory() android.Module {
+ tfg := &tradefedBinaryGen{}
+ tfg.AddProperties(&tfg.properties)
+ android.InitAndroidModule(tfg)
+ return tfg
+}
+
+func (tfg *tradefedBinaryGen) DepsMutator(android.BottomUpMutatorContext) {}
+
+var tradefedBinaryGenRule = pctx.StaticRule("tradefedBinaryGenRule", blueprint.RuleParams{
+ Command: `rm -f $out && touch $out && ` +
+ `echo "# This file is auto generated by Android.mk. Do not modify." >> $out && ` +
+ `echo "build_number = ${buildNumber}" >> $out && ` +
+ `echo "target_arch = ${arch}" >> $out && ` +
+ `echo "name = ${name}" >> $out && ` +
+ `echo "fullname = ${fullname}" >> $out && ` +
+ `echo "version = ${version}" >> $out`,
+}, "buildNumber", "arch", "name", "fullname", "version")
+
+func (tfg *tradefedBinaryGen) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ outputFile := android.PathForModuleOut(ctx, "test-suite-info.properties")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: tradefedBinaryGenRule,
+ Output: outputFile,
+ Args: map[string]string{
+ "buildNumber": ctx.Config().BuildNumberFromFile(),
+ "arch": ctx.Config().DevicePrimaryArchType().String(),
+ "name": tfg.properties.Short_name,
+ "fullname": tfg.properties.Full_name,
+ "version": tfg.properties.Version,
+ },
+ })
+
+ tfg.gen = append(tfg.gen, outputFile)
+
+ dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml")
+ if dynamicConfig.Valid() {
+ outputFile := android.PathForModuleOut(ctx, strings.TrimSuffix(ctx.ModuleName(), genSuffix)+".dynamic")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: dynamicConfig.Path(),
+ Output: outputFile,
+ })
+
+ tfg.gen = append(tfg.gen, outputFile)
+ }
+}
+
+func (tfg *tradefedBinaryGen) Srcs() android.Paths {
+ return append(android.Paths(nil), tfg.gen...)
+}
+
+var _ android.SourceFileProducer = (*tradefedBinaryGen)(nil)
diff --git a/common/Android.mk b/common/Android.mk
deleted file mode 100644
index a8b6af7..0000000
--- a/common/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (C) 2014 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 $(call all-subdir-makefiles)
diff --git a/common/host-side/Android.mk b/common/host-side/Android.mk
deleted file mode 100644
index a8b6af7..0000000
--- a/common/host-side/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (C) 2014 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 $(call all-subdir-makefiles)
diff --git a/common/host-side/manifest-generator/Android.bp b/common/host-side/manifest-generator/Android.bp
new file mode 100644
index 0000000..9d6cdb8
--- /dev/null
+++ b/common/host-side/manifest-generator/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2015 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.
+
+java_library_host {
+ name: "compatibility-manifest-generator",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: ["kxml2-2.3.0"],
+
+ manifest: "MANIFEST.mf",
+
+ use_tools_jar: true,
+}
diff --git a/common/host-side/manifest-generator/Android.mk b/common/host-side/manifest-generator/Android.mk
deleted file mode 100644
index b976329..0000000
--- a/common/host-side/manifest-generator/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := kxml2-2.3.0
-
-LOCAL_JAR_MANIFEST := MANIFEST.mf
-
-LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
-
-LOCAL_MODULE := compatibility-manifest-generator
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/common/host-side/manifest-generator/tests/Android.bp b/common/host-side/manifest-generator/tests/Android.bp
new file mode 100644
index 0000000..b8f012d
--- /dev/null
+++ b/common/host-side/manifest-generator/tests/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2015 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.
+
+java_test_host {
+ name: "compatibility-manifest-generator-tests",
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "compatibility-manifest-generator",
+ "junit",
+ ],
+}
diff --git a/common/host-side/manifest-generator/tests/Android.mk b/common/host-side/manifest-generator/tests/Android.mk
deleted file mode 100644
index 1601fc8..0000000
--- a/common/host-side/manifest-generator/tests/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := compatibility-manifest-generator junit-host
-
-LOCAL_MODULE := compatibility-manifest-generator-tests
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/tradefed/.classpath b/common/host-side/tradefed/.classpath
index 2c7514c..52d464a 100644
--- a/common/host-side/tradefed/.classpath
+++ b/common/host-side/tradefed/.classpath
@@ -6,14 +6,15 @@
<classpathentry kind="src" path="res"/>
<classpathentry kind="src" path="tests/src"/>
<classpathentry kind="lib" path="tests/res/testtype/testJar1.jar"/>
- <classpathentry kind="lib" path="tests/res/testtype/testJar2.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
<classpathentry combineaccessrules="false" kind="src" path="/tradefederation"/>
<classpathentry combineaccessrules="false" kind="src" path="/cts-common-util"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
- <classpathentry kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/jsonlib_intermediates/classes.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/cts-hostside-util"/>
- <classpathentry kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/google-api-java-client-min-repackaged_intermediates/classes.jar"/>
<classpathentry kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/host-libprotobuf-java-full_intermediates/classes.jar"/>
+ <classpathentry kind="var" path="TRADEFED_ROOT/out/soong/.intermediates/cts/libs/json/json/linux_glibc_common/javac/json.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/google-api-java-client/1.23.0/google-api-java-client-min-repackaged-1.23.0.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/common/host-side/tradefed/Android.bp b/common/host-side/tradefed/Android.bp
new file mode 100644
index 0000000..aba4209
--- /dev/null
+++ b/common/host-side/tradefed/Android.bp
@@ -0,0 +1,25 @@
+// 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.
+
+java_library_host {
+ name: "compatibility-tradefed",
+ srcs: ["src/**/*.java"],
+ java_resource_dirs: ["res"],
+ defaults: ["tradefed_errorprone_defaults"],
+ libs: [
+ "tradefed",
+ "compatibility-host-util",
+ "google-api-java-client-min-repackaged",
+ ],
+}
diff --git a/common/host-side/tradefed/Android.mk b/common/host-side/tradefed/Android.mk
deleted file mode 100644
index 3ed225e..0000000
--- a/common/host-side/tradefed/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (C) 2015 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 $(call all-subdir-makefiles)
\ No newline at end of file
diff --git a/common/host-side/tradefed/res/config/common-compatibility-config.xml b/common/host-side/tradefed/res/config/common-compatibility-config.xml
index f72efb8..8182ddf 100644
--- a/common/host-side/tradefed/res/config/common-compatibility-config.xml
+++ b/common/host-side/tradefed/res/config/common-compatibility-config.xml
@@ -15,7 +15,6 @@
-->
<configuration description="Common config for Compatibility suites">
<option name="dynamic-sharding" value="true" />
- <option name="disable-strict-sharding" value="true" />
<device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
<build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
<test class="com.android.compatibility.common.tradefed.testtype.suite.CompatibilityTestSuite" />
@@ -29,6 +28,6 @@
<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.ResultReporter" />
- <result_reporter class="com.android.tradefed.result.suite.SuiteResultReporter" />
+ <result_reporter class="com.android.compatibility.common.tradefed.result.suite.CompatibilityProtoResultReporter" />
+ <result_reporter class="com.android.compatibility.common.tradefed.result.suite.CertificationSuiteResultReporter" />
</configuration>
diff --git a/common/host-side/tradefed/res/report/compatibility_failures.xsl b/common/host-side/tradefed/res/report/compatibility_failures.xsl
index 46055d8..2c94ac8 100644
--- a/common/host-side/tradefed/res/report/compatibility_failures.xsl
+++ b/common/host-side/tradefed/res/report/compatibility_failures.xsl
@@ -128,6 +128,8 @@
<th>Module</th>
<th>Passed</th>
<th>Failed</th>
+ <th>Assumption Failure</th>
+ <th>Ignored</th>
<th>Total Tests</th>
<th>Done</th>
</tr>
@@ -149,7 +151,13 @@
<xsl:value-of select="count(TestCase/Test[@result = 'fail'])"/>
</td>
<td>
- <xsl:value-of select="count(TestCase/Test[@result = 'fail']) + @pass"/>
+ <xsl:value-of select="count(TestCase/Test[@result = 'ASSUMPTION_FAILURE'])"/>
+ </td>
+ <td>
+ <xsl:value-of select="count(TestCase/Test[@result = 'IGNORED'])"/>
+ </td>
+ <td>
+ <xsl:value-of select="@total_tests"/>
</td>
<td>
<xsl:value-of select="@done"/>
@@ -210,6 +218,15 @@
<td class="failuredetails"/>
</xsl:if>
+ <xsl:if test="@result='IGNORED'">
+ <td class="pass">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </td>
+ <td class="failuredetails"/>
+ </xsl:if>
+
<xsl:if test="@result='fail'">
<td class="failed">
<div style="text-align: center; margin-left:auto; margin-right:auto;">
@@ -223,6 +240,19 @@
</td>
</xsl:if>
+ <xsl:if test="@result='ASSUMPTION_FAILURE'">
+ <td class="pass">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </td>
+ <td class="failuredetails">
+ <div class="details">
+ <xsl:value-of select="Failure/@message"/>
+ </div>
+ </td>
+ </xsl:if>
+
<xsl:if test="@result='not_executed'">
<td class="not_executed">
<div style="text-align: center; margin-left:auto; margin-right:auto;">
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsl b/common/host-side/tradefed/res/report/compatibility_result.xsl
index df981c0..531107f 100644
--- a/common/host-side/tradefed/res/report/compatibility_result.xsl
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsl
@@ -128,6 +128,8 @@
<th>Module</th>
<th>Passed</th>
<th>Failed</th>
+ <th>Assumption Failure</th>
+ <th>Ignored</th>
<th>Total Tests</th>
<th>Done</th>
</tr>
@@ -144,6 +146,12 @@
<xsl:value-of select="count(TestCase/Test[@result = 'fail'])"/>
</td>
<td>
+ <xsl:value-of select="count(TestCase/Test[@result = 'ASSUMPTION_FAILURE'])"/>
+ </td>
+ <td>
+ <xsl:value-of select="count(TestCase/Test[@result = 'IGNORED'])"/>
+ </td>
+ <td>
<xsl:value-of select="count(TestCase/Test)"/>
</td>
<td>
@@ -224,6 +232,15 @@
<td class="failuredetails"/>
</xsl:if>
+ <xsl:if test="@result='IGNORED'">
+ <td class="pass">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </td>
+ <td class="failuredetails"/>
+ </xsl:if>
+
<xsl:if test="@result='fail'">
<td class="failed">
<div style="text-align: center; margin-left:auto; margin-right:auto;">
@@ -244,6 +261,26 @@
</td>
</xsl:if>
+ <xsl:if test="@result='ASSUMPTION_FAILURE'">
+ <td class="pass">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </td>
+ <td class="failuredetails">
+ <div class="details">
+ <xsl:choose>
+ <xsl:when test="boolean($fullStackTrace)=true()">
+ <xsl:value-of select="Failure/StackTrace" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="Failure/@message"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </div>
+ </td>
+ </xsl:if>
+
<xsl:if test="@result='not_executed'">
<td class="not_executed">
<div style="text-align: center; margin-left:auto; margin-right:auto;">
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
index 1b20fdd..0cb312a 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
@@ -19,10 +19,13 @@
import com.android.tradefed.build.IDeviceBuildInfo;
import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.build.VersionedFile;
+import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.util.FileUtil;
+
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
@@ -47,8 +50,6 @@
private static final String DYNAMIC_CONFIG_OVERRIDE_URL = "DYNAMIC_CONFIG_OVERRIDE_URL";
private static final String BUSINESS_LOGIC_HOST_FILE = "BUSINESS_LOGIC_HOST_FILE";
private static final String RETRY_COMMAND_LINE_ARGS = "retry_command_line_args";
- private static final String ALT_HOST_TESTCASE_DIR = "ANDROID_HOST_OUT_TESTCASES";
- private static final String ALT_TARGET_TESTCASE_DIR = "ANDROID_TARGET_OUT_TESTCASES";
private static final String CONFIG_PATH_PREFIX = "DYNAMIC_CONFIG_FILE:";
@@ -118,8 +119,25 @@
CONFIG_PATH_PREFIX + moduleName /* version */);
}
+ /**
+ * Set the business logic file for this invocation.
+ *
+ * @param hostFile The business logic host file.
+ */
public void setBusinessLogicHostFile(File hostFile) {
- mBuildInfo.addBuildAttribute(BUSINESS_LOGIC_HOST_FILE, hostFile.getAbsolutePath());
+ setBusinessLogicHostFile(hostFile, null);
+ }
+
+ /**
+ * Set the business logic file with specific module id for this invocation.
+ *
+ * @param hostFile The business logic host file.
+ * @param moduleId The name of the moduleId.
+ */
+ public void setBusinessLogicHostFile(File hostFile, String moduleId) {
+ String key = (moduleId == null) ? "" : moduleId;
+ mBuildInfo.setFile(BUSINESS_LOGIC_HOST_FILE + key, hostFile,
+ hostFile.getName()/* version */);
}
public void setModuleIds(String[] moduleIds) {
@@ -145,7 +163,19 @@
* @return whether the business logic file has been set for this invocation.
*/
public boolean hasBusinessLogicHostFile() {
- return mBuildInfo.getBuildAttributes().get(BUSINESS_LOGIC_HOST_FILE) != null;
+ return hasBusinessLogicHostFile(null);
+ }
+
+ /**
+ * Check whether the business logic file has been set with specific module id for this
+ * invocation.
+ *
+ * @param moduleId The name of the moduleId.
+ * @return True if the business logic file has been set. False otherwise.
+ */
+ public boolean hasBusinessLogicHostFile(String moduleId) {
+ String key = (moduleId == null) ? "" : moduleId;
+ return mBuildInfo.getFile(BUSINESS_LOGIC_HOST_FILE + key) != null;
}
/**
@@ -153,8 +183,19 @@
* invocation, or null if the business logic file has not been set.
*/
public File getBusinessLogicHostFile() {
- return (hasBusinessLogicHostFile()) ?
- new File(mBuildInfo.getBuildAttributes().get(BUSINESS_LOGIC_HOST_FILE)) : null;
+ return getBusinessLogicHostFile(null);
+ }
+
+ /**
+ * Get the file containing business logic data with specific module id for this invocation.
+ *
+ * @param moduleId The name of the moduleId.
+ * @return a {@link File} representing the file containing business logic data with
+ * specific module id for this invocation , or null if the business logic file has not been set.
+ */
+ public File getBusinessLogicHostFile(String moduleId) {
+ String key = (moduleId == null) ? "" : moduleId;
+ return mBuildInfo.getFile(BUSINESS_LOGIC_HOST_FILE + key);
}
/**
@@ -237,12 +278,13 @@
* @throws FileNotFoundException if the directory structure is not valid.
*/
public File getTestsDir() throws FileNotFoundException {
- // We have 3 options that can be the test modules dir (and we're going
+ // We have 2 options that can be the test modules dir (and we're going
// look for them in the following order):
// 1. ../android-*ts/testcases/
- // 2. ALT_HOST_TESTCASE_DIR
- // 3. ALT_TARGET_TESTCASE_DIR (we'll skip this since if #2 fails, this
- // will inevitably fail as well.)
+ // 2. The build info tests dir
+ // ANDROID_HOST_OUT and ANDROID_TARGET_OUT are already linked
+ // by tradefed to the tests dir when they exists so there is
+ // no need to explicitly search them.
File testsDir = null;
try {
@@ -258,13 +300,6 @@
}
}
- if (testsDir == null) {
- String altTestsDir = System.getenv().get(ALT_HOST_TESTCASE_DIR);
- if (altTestsDir != null) {
- testsDir = new File(altTestsDir);
- }
- }
-
// This just means we have no signs of where to check for the test dir.
if (testsDir == null) {
throw new FileNotFoundException(
@@ -285,31 +320,26 @@
* @throws FileNotFoundException if the test file cannot be found
*/
public File getTestFile(String filename) throws FileNotFoundException {
- // We have a lot of places to check for the test file.
- // 1. ../android-*ts/testcases/
- // 2. ALT_HOST_TESTCASE_DIR/
- // 3. ALT_TARGET_TESTCASE_DIR/
+ return getTestFile(filename, null);
+ }
- // Our search depends on our run env, if we're in *ts, then we only want
- // to check #1. If we're in gen tf, then we only want to check #2/3.
- // In *ts mode, getTestsDir will return #1, in gen tf mode, it'll return
- // #2. In the event we're in *ts mode and the file isn't in #1, #2 or
- // #3, then the user probably needs to run lunch to setup the env.
- String altTargetTestDir = System.getenv().get(ALT_TARGET_TESTCASE_DIR);
- if (altTargetTestDir == null) {
- altTargetTestDir = "";
- }
- String[] testDirs = {getTestsDir().toString(), altTargetTestDir};
+ /**
+ * @return a {@link File} representing the test file in the test modules directory.
+ * @throws FileNotFoundException if the test file cannot be found
+ */
+ public File getTestFile(String filename, IAbi abi) throws FileNotFoundException {
+ File[] testDirs = {getTestsDir()};
- File testFile;
- for (String testDir: testDirs) {
- testFile = new File(testDir, filename);
- if (testFile.exists()) {
- return testFile;
+ // The file may be in a subdirectory so do a more through search
+ // if it did not exist.
+ File testFile = null;
+ for (File testDir: testDirs) {
+ try {
+ testFile = FileUtil.findFile(filename, abi, testDir);
+ } catch (IOException e) {
+ throw new FileNotFoundException(String.format(
+ "Failure in finding compatibility test file %s due to %s", filename, e));
}
- // The file may be in a subdirectory so do a more through search
- // if it did not exist.
- testFile = FileUtil.findFile(new File(testDir), filename);
if (testFile != null) {
return testFile;
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
index 2216b2a..cfbfa1c 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
@@ -32,6 +32,7 @@
import com.android.tradefed.testtype.IInvocationContextReceiver;
import com.android.tradefed.testtype.suite.TestSuiteInfo;
import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.VersionParser;
import java.io.File;
import java.io.IOException;
@@ -73,6 +74,12 @@
@Option(name="build-flavor", description="build flavor name to supply.")
private String mBuildFlavor = null;
+ @Option(
+ name = "build-flavor-prefix",
+ description = "allow for a prefix to be inserted into build flavor."
+ )
+ private String mBuildFlavorPrefix = null;
+
@Option(name="build-target", description="build target name to supply.")
private String mBuildTarget = null;
@@ -141,7 +148,11 @@
ctsBuild.setBuildBranch(mBranch);
}
if (mBuildFlavor != null) {
- ctsBuild.setBuildFlavor(mBuildFlavor);
+ String buildFlavor = mBuildFlavor;
+ if (mBuildFlavorPrefix != null) {
+ buildFlavor = mBuildFlavorPrefix + buildFlavor;
+ }
+ ctsBuild.setBuildFlavor(buildFlavor);
}
injectBuildAttributes(ctsBuild);
addCompatibilitySuiteInfo(ctsBuild);
@@ -162,8 +173,12 @@
if (mBuildId == null) {
mBuildId = device.getBuildId();
}
- if (mBuildFlavor == null) {
- mBuildFlavor = device.getBuildFlavor();
+ String buildFlavor = mBuildFlavor;
+ if (buildFlavor == null) {
+ buildFlavor = device.getBuildFlavor();
+ }
+ if (mBuildFlavorPrefix != null) {
+ buildFlavor = mBuildFlavorPrefix + buildFlavor;
}
if (mBuildTarget == null) {
String name = device.getProperty("ro.product.name");
@@ -181,7 +196,7 @@
device.getProperty("ro.build.version.release"));
}
info.setBuildBranch(mBranch);
- info.setBuildFlavor(mBuildFlavor);
+ info.setBuildFlavor(buildFlavor);
String buildAlias = device.getBuildAlias();
if (RELEASE_BUILD.matcher(buildAlias).matches()) {
info.addBuildAttribute("build_alias", buildAlias);
@@ -296,7 +311,12 @@
* Return the SuiteInfo build number generated at build time. Exposed for testing.
*/
protected String getSuiteInfoBuildNumber() {
- return TestSuiteInfo.getInstance().getBuildNumber();
+ String buildNumber = TestSuiteInfo.getInstance().getBuildNumber();
+ String versionFile = VersionParser.fetchVersion();
+ if (versionFile != null) {
+ buildNumber = versionFile;
+ }
+ return buildNumber;
}
/**
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
index 5dcf2dd..7747ca5 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
@@ -18,30 +18,41 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
import com.android.compatibility.common.tradefed.result.SubPlanHelper;
+import com.android.compatibility.common.tradefed.result.suite.CertificationResultXml;
import com.android.compatibility.common.tradefed.testtype.ModuleRepo;
-import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.tradefed.testtype.suite.CompatibilityTestSuite;
import com.android.compatibility.common.util.ResultHandler;
-import com.android.compatibility.common.util.TestStatus;
import com.android.tradefed.build.BuildRetrievalError;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.command.Console;
import com.android.tradefed.config.ArgsOptionParser;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.ConfigurationFactory;
import com.android.tradefed.config.IConfiguration;
import com.android.tradefed.config.IConfigurationFactory;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.suite.SuiteResultHolder;
+import com.android.tradefed.testtype.Abi;
+import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IRuntimeHintProvider;
import com.android.tradefed.testtype.suite.TestSuiteInfo;
-import com.android.tradefed.util.ArrayUtil;
+import com.android.tradefed.util.AbiUtils;
import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.MultiMap;
import com.android.tradefed.util.Pair;
import com.android.tradefed.util.RegexTrie;
import com.android.tradefed.util.TableFormatter;
import com.android.tradefed.util.TimeUtil;
+import com.android.tradefed.util.VersionParser;
+
+import com.google.common.base.Joiner;
import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -49,6 +60,8 @@
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -67,16 +80,26 @@
MODULE_SPLIT_EXCLUSIONS.add("CtsDeqpTestCases");
}
private final static String ADD_PATTERN = "a(?:dd)?";
+ private static final String LATEST_RESULT_DIR = "latest";
private CompatibilityBuildHelper mBuildHelper;
+ private IBuildInfo mBuildInfo;
/**
* {@inheritDoc}
*/
@Override
public void run() {
- printLine(String.format("Android %s %s (%s)", TestSuiteInfo.getInstance().getFullName(),
- TestSuiteInfo.getInstance().getVersion(),
- TestSuiteInfo.getInstance().getBuildNumber()));
+ String buildNumber = TestSuiteInfo.getInstance().getBuildNumber();
+ String versionFile = VersionParser.fetchVersion();
+ if (versionFile != null) {
+ buildNumber = versionFile;
+ }
+ printLine(
+ String.format(
+ "Android %s %s (%s)",
+ TestSuiteInfo.getInstance().getFullName(),
+ TestSuiteInfo.getInstance().getVersion(),
+ buildNumber));
printLine("Use \"help\" or \"help all\" to get more information on running commands.");
super.run();
}
@@ -225,24 +248,25 @@
}
private void listModules() {
- File[] files = null;
- try {
- files = getBuildHelper().getTestsDir().listFiles(new ModuleRepo.ConfigFilter());
- } catch (FileNotFoundException e) {
- printLine(e.getMessage());
- e.printStackTrace();
- }
- if (files != null && files.length > 0) {
- List<String> modules = new ArrayList<>();
- for (File moduleFile : files) {
- modules.add(FileUtil.getBaseName(moduleFile.getName()));
+ CompatibilityTestSuite test = new CompatibilityTestSuite() {
+ @Override
+ public Set<IAbi> getAbis(ITestDevice device) throws DeviceNotAvailableException {
+ Set<String> abiStrings = getAbisForBuildTargetArch();
+ Set<IAbi> abis = new LinkedHashSet<>();
+ for (String abi : abiStrings) {
+ if (AbiUtils.isAbiSupportedByCompatibility(abi)) {
+ abis.add(new Abi(abi, AbiUtils.getBitness(abi)));
+ }
+ }
+ return abis;
}
- Collections.sort(modules);
- for (String module : modules) {
- printLine(module);
- }
+ };
+ if (getBuild() != null) {
+ test.setBuild(getBuild());
+ LinkedHashMap<String, IConfiguration> configs = test.loadTests();
+ printLine(String.format("%s", Joiner.on("\n").join(configs.keySet())));
} else {
- printLine("No modules found");
+ printLine("Error fetching information about modules.");
}
}
@@ -346,48 +370,70 @@
private void listResults() {
TableFormatter tableFormatter = new TableFormatter();
List<List<String>> table = new ArrayList<>();
- List<IInvocationResult> results = null;
+
+ List<File> resultDirs = null;
+ Map<SuiteResultHolder, File> holders = new LinkedHashMap<>();
try {
- results = ResultHandler.getLightResults(getBuildHelper().getResultsDir());
+ resultDirs = getResults(getBuildHelper().getResultsDir());
} catch (FileNotFoundException e) {
throw new RuntimeException("Error while parsing results directory", e);
}
- if (results.size() > 0) {
- for (int i = 0; i < results.size(); i++) {
- IInvocationResult result = results.get(i);
- Map<String, String> invocationInfo = result.getInvocationInfo();
-
- // invocation attributes are not always present (e.g. in the case of halted runs)
- // replace null entries with the string "Unknown"
- for (Map.Entry<String, String> entry : invocationInfo.entrySet()) {
- if (entry.getValue() == null) {
- invocationInfo.put(entry.getKey(), "Unknown");
- }
- }
-
- String moduleProgress = String.format("%d of %d",
- result.getModuleCompleteCount(), result.getModules().size());
-
- table.add(Arrays.asList(
- Integer.toString(i),
- Integer.toString(result.countResults(TestStatus.PASS)),
- Integer.toString(result.countResults(TestStatus.FAIL)),
- moduleProgress,
- CompatibilityBuildHelper.getDirSuffix(result.getStartTime()),
- result.getTestPlan(),
- ArrayUtil.join(", ", result.getDeviceSerials()),
- invocationInfo.get("build_id"),
- invocationInfo.get("build_product")
- ));
+ CertificationResultXml xmlParser = new CertificationResultXml();
+ for (File resultDir : resultDirs) {
+ if (LATEST_RESULT_DIR.equals(resultDir.getName())) {
+ continue;
}
-
- // add the table header to the beginning of the list
- table.add(0, Arrays.asList("Session", "Pass", "Fail", "Modules Complete",
- "Result Directory", "Test Plan", "Device serial(s)", "Build ID", "Product"));
- tableFormatter.displayTable(table, new PrintWriter(System.out, true));
- } else {
- printLine(String.format("No results found"));
+ try {
+ holders.put(xmlParser.parseResults(resultDir, true), resultDir);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
+
+ if (holders.isEmpty()) {
+ printLine(String.format("No results found"));
+ return;
+ }
+ int i = 0;
+ for (SuiteResultHolder holder : holders.keySet()) {
+ String moduleProgress = String.format("%d of %d",
+ holder.completeModules, holder.totalModules);
+
+ table.add(
+ Arrays.asList(
+ Integer.toString(i),
+ Long.toString(holder.passedTests),
+ Long.toString(holder.failedTests),
+ moduleProgress,
+ holders.get(holder).getName(),
+ holder.context
+ .getAttributes()
+ .get(CertificationResultXml.SUITE_PLAN_ATTR)
+ .get(0),
+ Joiner.on(", ").join(holder.context.getShardsSerials().values()),
+ printAttributes(holder.context.getAttributes(), "build_id"),
+ printAttributes(holder.context.getAttributes(), "build_product")));
+ i++;
+ }
+
+ // add the table header to the beginning of the list
+ table.add(0, Arrays.asList("Session", "Pass", "Fail", "Modules Complete",
+ "Result Directory", "Test Plan", "Device serial(s)", "Build ID", "Product"));
+ tableFormatter.displayTable(table, new PrintWriter(System.out, true));
+ }
+
+ private String printAttributes(MultiMap<String, String> map, String key) {
+ if (map.get(key) == null) {
+ return "unknown";
+ }
+ return map.get(key).get(0);
+ }
+
+ /**
+ * Returns the list of all results directories.
+ */
+ private List<File> getResults(File resultsDir) {
+ return ResultHandler.getResultDirectories(resultsDir);
}
private void listSubPlans() {
@@ -427,14 +473,25 @@
private CompatibilityBuildHelper getBuildHelper() {
if (mBuildHelper == null) {
+ IBuildInfo build = getBuild();
+ if (build == null) {
+ return null;
+ }
+ mBuildHelper = new CompatibilityBuildHelper(build);
+ }
+ return mBuildHelper;
+ }
+
+ private IBuildInfo getBuild() {
+ if (mBuildInfo == null) {
try {
CompatibilityBuildProvider buildProvider = new CompatibilityBuildProvider();
- mBuildHelper = new CompatibilityBuildHelper(buildProvider.getBuild());
+ mBuildInfo = buildProvider.getBuild();
} catch (BuildRetrievalError e) {
e.printStackTrace();
}
}
- return mBuildHelper;
+ return mBuildInfo;
}
public static void main(String[] args) throws InterruptedException, ConfigurationException {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index 3b79465..44939f3 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -34,6 +34,8 @@
import com.android.compatibility.common.util.TestStatus;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.IConfigurationReceiver;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.config.OptionClass;
@@ -61,6 +63,7 @@
import com.android.tradefed.util.proto.TfMetricProtoUtil;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.xml.XmlEscapers;
import org.xmlpull.v1.XmlPullParserException;
@@ -86,7 +89,7 @@
*/
@OptionClass(alias="result-reporter")
public class ResultReporter implements ILogSaverListener, ITestInvocationListener,
- ITestSummaryListener, IShardableListener {
+ ITestSummaryListener, IShardableListener, IConfigurationReceiver {
public static final String INCLUDE_HTML_IN_ZIP = "html-in-zip";
private static final String UNKNOWN_DEVICE = "unknown_device";
@@ -185,6 +188,9 @@
// Elapsed time from invocation started to ended.
private long mElapsedTime;
+ /** Invocation level configuration */
+ private IConfiguration mConfiguration = null;
+
/**
* Default constructor.
*/
@@ -201,6 +207,12 @@
mMasterResultReporter = masterResultReporter;
}
+ /** {@inheritDoc} */
+ @Override
+ public void setConfiguration(IConfiguration configuration) {
+ mConfiguration = configuration;
+ }
+
/**
* {@inheritDoc}
*/
@@ -384,7 +396,7 @@
*/
@Override
public void testFailed(TestDescription test, String trace) {
- mCurrentResult.failed(trace);
+ mCurrentResult.failed(sanitizeXmlContent(trace));
}
/**
@@ -521,15 +533,6 @@
}
}
- /**
- * Returns whether a report creation should be skipped.
- */
- protected boolean shouldSkipReportCreation() {
- // This value is always false here for backwards compatibility.
- // Extended classes have the option to override this.
- return false;
- }
-
private void finalizeResults() {
if (mFingerprintFailure) {
CLog.w("Failed the fingerprint check. Skip result reporting.");
@@ -563,10 +566,6 @@
mResult.getModuleCompleteCount(), mResult.getModules().size());
- if (shouldSkipReportCreation()) {
- return;
- }
-
try {
// Zip the full test results directory.
copyDynamicConfigFiles();
@@ -751,6 +750,7 @@
fis = new FileInputStream(resultFile);
logFile = mLogSaver.saveLogData("log-result", LogDataType.XML, fis);
debug("Result XML URL: %s", logFile.getUrl());
+ logReportFiles(mConfiguration, resultFile, resultFile.getName(), LogDataType.XML);
} catch (IOException ioe) {
CLog.e("[%s] error saving XML with log saver", mDeviceSerial);
CLog.e(ioe);
@@ -764,6 +764,8 @@
zipResultStream = new FileInputStream(zippedResults);
logFile = mLogSaver.saveLogData("results", LogDataType.ZIP, zipResultStream);
debug("Result zip URL: %s", logFile.getUrl());
+ logReportFiles(
+ mConfiguration, zippedResults, "results", LogDataType.ZIP);
} finally {
StreamUtil.close(zipResultStream);
}
@@ -1078,4 +1080,26 @@
public boolean waitForFinalized(long timeout, TimeUnit unit) throws InterruptedException {
return mFinalized.await(timeout, unit);
}
+
+ private static String sanitizeXmlContent(String s) {
+ return XmlEscapers.xmlContentEscaper().escape(s);
+ }
+
+ /** Re-log a result file to all reporters so they are aware of it. */
+ private void logReportFiles(
+ IConfiguration configuration, File resultFile, String dataName, LogDataType type) {
+ if (configuration == null) {
+ return;
+ }
+ List<ITestInvocationListener> listeners = configuration.getTestInvocationListeners();
+ try (FileInputStreamSource source = new FileInputStreamSource(resultFile)) {
+ for (ITestInvocationListener listener : listeners) {
+ if (listener.equals(this)) {
+ // Avoid logging agaisnt itself
+ continue;
+ }
+ listener.testLog(dataName, type, source);
+ }
+ }
+ }
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationResultXml.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationResultXml.java
index 4911d92..2e31722 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationResultXml.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationResultXml.java
@@ -31,12 +31,12 @@
*/
public class CertificationResultXml extends XmlSuiteResultFormatter {
+ public static final String SUITE_PLAN_ATTR = "suite_plan";
private static final String LOG_URL_ATTR = "log_url";
private static final String REPORT_VERSION_ATTR = "report_version";
private static final String REFERENCE_URL_ATTR = "reference_url";
private static final String RESULT_FILE_VERSION = "5.0";
private static final String SUITE_NAME_ATTR = "suite_name";
- private static final String SUITE_PLAN_ATTR = "suite_plan";
private static final String SUITE_VERSION_ATTR = "suite_version";
private static final String SUITE_BUILD_ATTR = "suite_build_number";
@@ -48,6 +48,11 @@
private String mLogUrl;
/**
+ * Empty version of the constructor when loading results.
+ */
+ public CertificationResultXml() {}
+
+ /**
* Create an XML report specialized for the Compatibility Test cases.
*/
public CertificationResultXml(String suiteName,
@@ -89,12 +94,25 @@
public void parseSuiteAttributes(XmlPullParser parser, IInvocationContext context)
throws XmlPullParserException {
mSuiteName = parser.getAttributeValue(NS, SUITE_NAME_ATTR);
+ context.addInvocationAttribute(SUITE_NAME_ATTR, mSuiteName);
+
mSuiteVersion = parser.getAttributeValue(NS, SUITE_VERSION_ATTR);
+ context.addInvocationAttribute(SUITE_VERSION_ATTR, mSuiteVersion);
+
mSuitePlan = parser.getAttributeValue(NS, SUITE_PLAN_ATTR);
+ context.addInvocationAttribute(SUITE_PLAN_ATTR, mSuitePlan);
+
mSuiteBuild = parser.getAttributeValue(NS, SUITE_BUILD_ATTR);
+ context.addInvocationAttribute(SUITE_BUILD_ATTR, mSuiteBuild);
mReferenceUrl = parser.getAttributeValue(NS, REFERENCE_URL_ATTR);
+ if (mReferenceUrl != null) {
+ context.addInvocationAttribute(REFERENCE_URL_ATTR, mReferenceUrl);
+ }
mLogUrl = parser.getAttributeValue(NS, LOG_URL_ATTR);
+ if (mLogUrl != null) {
+ context.addInvocationAttribute(LOG_URL_ATTR, mLogUrl);
+ }
}
/**
@@ -114,6 +132,19 @@
}
/**
+ * Parse the information in 'Build' tag.
+ */
+ @Override
+ public void parseBuildInfoAttributes(XmlPullParser parser, IInvocationContext context)
+ throws XmlPullParserException {
+ for (int index = 0; index < parser.getAttributeCount(); index++) {
+ String key = parser.getAttributeName(index);
+ String value = parser.getAttributeValue(NS, key);
+ context.addInvocationAttribute(key, value);
+ }
+ }
+
+ /**
* Returns the compatibility prefix for attributes.
*/
public String getAttributesPrefix() {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationSuiteResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationSuiteResultReporter.java
index 8399d9d..8c497a3 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationSuiteResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CertificationSuiteResultReporter.java
@@ -20,11 +20,15 @@
import com.android.compatibility.common.util.ResultHandler;
import com.android.compatibility.common.util.ResultUploader;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.IConfigurationReceiver;
import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.FileInputStreamSource;
import com.android.tradefed.result.ILogSaver;
-import com.android.tradefed.result.ILogSaverListener;
+import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.ITestSummaryListener;
import com.android.tradefed.result.InputStreamSource;
import com.android.tradefed.result.LogDataType;
@@ -65,8 +69,9 @@
* Extension of {@link XmlFormattedGeneratorReporter} and {@link SuiteResultReporter} to handle
* Compatibility specific format and operations.
*/
+@OptionClass(alias = "result-reporter")
public class CertificationSuiteResultReporter extends XmlFormattedGeneratorReporter
- implements ILogSaverListener, ITestSummaryListener {
+ implements IConfigurationReceiver, ITestSummaryListener {
public static final String LATEST_LINK_NAME = "latest";
public static final String SUMMARY_FILE = "invocation_summary.txt";
@@ -78,7 +83,10 @@
@Option(name = "result-server", description = "Server to publish test results.")
private String mResultServer;
- @Option(name = "disable-result-posting", description = "Disable result posting into report server.")
+ @Option(
+ name = "disable-result-posting",
+ description ="Disable result posting into report server."
+ )
private boolean mDisableResultPosting = false;
@Option(name = "include-test-log-tags", description = "Include test log tags in report.")
@@ -105,8 +113,10 @@
private ResultUploader mUploader;
private LogFileSaver mTestLogSaver;
- /** Log saver to receive when files are logged */
+ /** Invocation level Log saver to receive when files are logged */
private ILogSaver mLogSaver;
+ /** Invocation level configuration */
+ private IConfiguration mConfiguration = null;
private String mReferenceUrl;
@@ -223,12 +233,20 @@
mLogSaver = saver;
}
+ /** {@inheritDoc} */
+ @Override
+ public void setConfiguration(IConfiguration configuration) {
+ mConfiguration = configuration;
+ }
+
/**
* Create directory structure where results and logs will be written.
*/
private void initializeResultDirectories() {
CLog.d("Initializing result directory");
-
+ // TODO: Clean up start time handling to avoid relying on buildinfo
+ getPrimaryBuildInfo().addBuildAttribute(CompatibilityBuildHelper.START_TIME_MS,
+ Long.toString(getStartTime()));
try {
mResultDir = mBuildHelper.getResultDir();
if (mResultDir != null) {
@@ -251,7 +269,7 @@
mUploader = new ResultUploader(mResultServer, mBuildHelper.getSuiteName());
try {
mLogDir = new File(mBuildHelper.getLogsDir(),
- CompatibilityBuildHelper.getDirSuffix(mBuildHelper.getStartTime()));
+ CompatibilityBuildHelper.getDirSuffix(getStartTime()));
} catch (FileNotFoundException e) {
CLog.e(e);
}
@@ -456,6 +474,7 @@
fis = new FileInputStream(resultFile);
logFile = mLogSaver.saveLogData("log-result", LogDataType.XML, fis);
CLog.d("Result XML URL: %s", logFile.getUrl());
+ logReportFiles(mConfiguration, resultFile, resultFile.getName(), LogDataType.XML);
} catch (IOException ioe) {
CLog.e("error saving XML with log saver");
CLog.e(ioe);
@@ -469,6 +488,7 @@
zipResultStream = new FileInputStream(zippedResults);
logFile = mLogSaver.saveLogData("results", LogDataType.ZIP, zipResultStream);
CLog.d("Result zip URL: %s", logFile.getUrl());
+ logReportFiles(mConfiguration, zippedResults, "results", LogDataType.ZIP);
} finally {
StreamUtil.close(zipResultStream);
}
@@ -519,7 +539,9 @@
Transformer transformer = TransformerFactory.newInstance().newTransformer(
new StreamSource(xslStream));
transformer.transform(new StreamSource(inputXml), new StreamResult(outputStream));
- } catch (IOException | TransformerException ignored) { }
+ } catch (IOException | TransformerException ignored) {
+ CLog.e(ignored);
+ }
return failureReport;
}
@@ -530,4 +552,22 @@
String buildFingerprint) {
CertificationChecksumHelper.tryCreateChecksum(resultDir, results, buildFingerprint);
}
+
+ /** Re-log a result file to all reporters so they are aware of it. */
+ private void logReportFiles(
+ IConfiguration configuration, File resultFile, String dataName, LogDataType type) {
+ if (configuration == null) {
+ return;
+ }
+ List<ITestInvocationListener> listeners = configuration.getTestInvocationListeners();
+ try (FileInputStreamSource source = new FileInputStreamSource(resultFile)) {
+ for (ITestInvocationListener listener : listeners) {
+ if (listener.equals(this)) {
+ // Avoid logging agaisnt itself
+ continue;
+ }
+ listener.testLog(dataName, type, source);
+ }
+ }
+ }
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CompatibilityProtoResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CompatibilityProtoResultReporter.java
new file mode 100644
index 0000000..823dc2b
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/CompatibilityProtoResultReporter.java
@@ -0,0 +1,82 @@
+/*
+ * 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.result.suite;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.proto.ProtoResultReporter;
+import com.android.tradefed.result.proto.TestRecordProto.TestRecord;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Proto reporter that will drop a {@link TestRecord} protobuf in the result directory.
+ */
+public class CompatibilityProtoResultReporter extends ProtoResultReporter {
+
+ public static final String PROTO_FILE_NAME = "test-record.pb";
+
+ private CompatibilityBuildHelper mBuildHelper;
+
+ /** The directory containing the results */
+ private File mResultDir = null;
+
+ @Override
+ public void processStartInvocation(
+ TestRecord invocationStartRecord, IInvocationContext invocationContext) {
+ if (mBuildHelper == null) {
+ mBuildHelper = new CompatibilityBuildHelper(invocationContext.getBuildInfos().get(0));
+ }
+ }
+
+ @Override
+ public void processFinalProto(TestRecord finalRecord) {
+ super.processFinalProto(finalRecord);
+
+ mResultDir = getResultDirectory();
+ File protoFile = new File(mResultDir, PROTO_FILE_NAME);
+ try {
+ finalRecord.writeDelimitedTo(new FileOutputStream(protoFile));
+ } catch (IOException e) {
+ CLog.e(e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ private File getResultDirectory() {
+ try {
+ mResultDir = mBuildHelper.getResultDir();
+ if (mResultDir != null) {
+ mResultDir.mkdirs();
+ }
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ if (mResultDir == null) {
+ throw new RuntimeException("Result Directory was not created");
+ }
+ if (!mResultDir.exists()) {
+ throw new RuntimeException("Result Directory was not created: " +
+ mResultDir.getAbsolutePath());
+ }
+ CLog.d("Results Directory: %s", mResultDir.getAbsolutePath());
+ return mResultDir;
+ }
+}
\ No newline at end of file
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousResultLoader.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousResultLoader.java
new file mode 100644
index 0000000..a605fd0
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousResultLoader.java
@@ -0,0 +1,242 @@
+/*
+ * 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.result.suite;
+
+import com.android.annotations.VisibleForTesting;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
+import com.android.compatibility.common.tradefed.targetprep.BuildFingerPrintPreparer;
+import com.android.compatibility.common.tradefed.testtype.retry.RetryFactoryTest;
+import com.android.compatibility.common.util.ResultHandler;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.build.BuildRetrievalError;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.build.IBuildProvider;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.invoker.InvocationContext;
+import com.android.tradefed.invoker.TestInvocation;
+import com.android.tradefed.invoker.proto.InvocationContext.Context;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.proto.TestRecordProto.TestRecord;
+import com.android.tradefed.result.suite.SuiteResultHolder;
+import com.android.tradefed.result.suite.XmlSuiteResultFormatter.RunHistory;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.testtype.suite.retry.ITestSuiteResultLoader;
+import com.android.tradefed.util.proto.TestRecordProtoUtil;
+
+import com.google.api.client.util.Strings;
+import com.google.gson.Gson;
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Implementation of {@link ITestSuiteResultLoader} to reload CTS previous results.
+ */
+public final class PreviousResultLoader implements ITestSuiteResultLoader {
+
+ /** Usually associated with ro.build.fingerprint. */
+ public static final String BUILD_FINGERPRINT = "build_fingerprint";
+ /** Usally associated with ro.vendor.build.fingerprint. */
+ public static final String BUILD_VENDOR_FINGERPRINT = "build_vendor_fingerprint";
+ /**
+ * Some suites have a business need to alter the original real device fingerprint value, in this
+ * case we expect an "unaltered" version to be available to still do the original check.
+ */
+ public static final String BUILD_FINGERPRINT_UNALTERED = "build_fingerprint_unaltered";
+ /** Used to get run history from the invocation context of last run. */
+ public static final String RUN_HISTORY_KEY = "run_history";
+
+ @Option(name = RetryFactoryTest.RETRY_OPTION,
+ shortName = 'r',
+ description = "retry a previous session's failed and not executed tests.",
+ mandatory = true)
+ private Integer mRetrySessionId = null;
+
+ @Option(
+ name = "fingerprint-property",
+ description = "The property name to check for the fingerprint."
+ )
+ private String mFingerprintProperty = "ro.build.fingerprint";
+
+ private TestRecord mTestRecord;
+ private IInvocationContext mPreviousContext;
+ private String mExpectedFingerprint;
+ private String mExpectedVendorFingerprint;
+ private String mUnalteredFingerprint;
+
+ private File mResultDir;
+
+ private IBuildProvider mProvider;
+
+ /**
+ * The run history of last run (last run excluded) will be first parsed out and stored here, the
+ * information of last run is added second. Then this object is serialized and added to the
+ * configuration of the current test run.
+ */
+ private Collection<RunHistory> mRunHistories;
+
+ @Override
+ public void init() {
+ IBuildInfo info = null;
+ try {
+ info = getProvider().getBuild();
+ } catch (BuildRetrievalError e) {
+ throw new RuntimeException(e);
+ }
+ CompatibilityBuildHelper helperBuild = new CompatibilityBuildHelper(info);
+ mResultDir = null;
+ try {
+ CLog.logAndDisplay(LogLevel.DEBUG, "Start loading the record protobuf.");
+ mResultDir =
+ ResultHandler.getResultDirectory(helperBuild.getResultsDir(), mRetrySessionId);
+ mTestRecord =
+ TestRecordProtoUtil.readFromFile(
+ new File(mResultDir, CompatibilityProtoResultReporter.PROTO_FILE_NAME));
+ CLog.logAndDisplay(LogLevel.DEBUG, "Done loading the record protobuf.");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ Context contextProto = null;
+ try {
+ contextProto = mTestRecord.getDescription().unpack(Context.class);
+ } catch (InvalidProtocolBufferException e) {
+ throw new RuntimeException(e);
+ }
+ mPreviousContext = InvocationContext.fromProto(contextProto);
+
+ mRunHistories = new ArrayList<>();
+ String runHistoryJSON =
+ mPreviousContext.getAttributes().getUniqueMap().get(RUN_HISTORY_KEY);
+ if (runHistoryJSON != null) {
+ Gson gson = new Gson();
+ RunHistory[] runHistories = gson.fromJson(runHistoryJSON, RunHistory[].class);
+ Collections.addAll(mRunHistories, runHistories);
+ }
+
+ // Validate the fingerprint
+ // TODO: Use fingerprint argument from TestRecord but we have to deal with suite namespace
+ // for example: cts:build_fingerprint instead of just build_fingerprint.
+ // And update run history.
+ try {
+ CLog.logAndDisplay(LogLevel.DEBUG, "Start parsing previous test_results.xml");
+ CertificationResultXml xmlParser = new CertificationResultXml();
+ SuiteResultHolder holder = xmlParser.parseResults(mResultDir, true);
+ CLog.logAndDisplay(LogLevel.DEBUG, "Done parsing previous test_results.xml");
+ mExpectedFingerprint = holder.context.getAttributes()
+ .getUniqueMap().get(BUILD_FINGERPRINT);
+ if (mExpectedFingerprint == null) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Could not find the %s field in the loaded result.",
+ BUILD_FINGERPRINT));
+ }
+ /** If available in the report, collect the vendor fingerprint too. */
+ mExpectedVendorFingerprint =
+ holder.context.getAttributes().getUniqueMap().get(BUILD_VENDOR_FINGERPRINT);
+ if (mExpectedVendorFingerprint == null) {
+ throw new IllegalArgumentException(
+ String.format(
+ "Could not find the %s field in the loaded result.",
+ BUILD_VENDOR_FINGERPRINT));
+ }
+ // Some cases will have an unaltered fingerprint
+ mUnalteredFingerprint =
+ holder.context.getAttributes().getUniqueMap().get(BUILD_FINGERPRINT_UNALTERED);
+
+ // Add the information of last test run to a run history list.
+ RunHistory newRun = new RunHistory();
+ newRun.startTime = holder.startTime;
+ newRun.endTime = holder.endTime;
+ mRunHistories.add(newRun);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String getCommandLine() {
+ List<String> command = mPreviousContext.getAttributes().get(
+ TestInvocation.COMMAND_ARGS_KEY);
+ if (command == null) {
+ throw new RuntimeException("Couldn't find the command line arg.");
+ }
+ return command.get(0);
+ }
+
+ @Override
+ public TestRecord loadPreviousRecord() {
+ return mTestRecord;
+ }
+
+ @Override
+ public final void cleanUp() {
+ if (mTestRecord != null) {
+ mTestRecord = null;
+ }
+ }
+
+ @Override
+ public final void customizeConfiguration(IConfiguration config) {
+ // This is specific to Compatibility checking and does not work for multi-device.
+ List<ITargetPreparer> preparers = config.getTargetPreparers();
+ List<ITargetPreparer> newList = new ArrayList<>();
+ // Add the fingerprint checker first to ensure we check it before rerunning the config.
+ BuildFingerPrintPreparer fingerprintChecker = new BuildFingerPrintPreparer();
+ fingerprintChecker.setExpectedFingerprint(mExpectedFingerprint);
+ fingerprintChecker.setExpectedVendorFingerprint(mExpectedVendorFingerprint);
+ fingerprintChecker.setFingerprintProperty(mFingerprintProperty);
+ if (!Strings.isNullOrEmpty(mUnalteredFingerprint)) {
+ fingerprintChecker.setUnalteredFingerprint(mUnalteredFingerprint);
+ }
+ newList.add(fingerprintChecker);
+ newList.addAll(preparers);
+ config.setTargetPreparers(newList);
+
+ // Add the file copier last to copy from previous sesssion
+ List<ITestInvocationListener> listeners = config.getTestInvocationListeners();
+ PreviousSessionFileCopier copier = new PreviousSessionFileCopier();
+ copier.setPreviousSessionDir(mResultDir);
+ listeners.add(copier);
+
+ // Add run history to the configuration so it will be augmented in the next test run.
+ Gson gson = new Gson();
+ config.getCommandOptions()
+ .getInvocationData()
+ .put(RUN_HISTORY_KEY, gson.toJson(mRunHistories));
+ }
+
+ @VisibleForTesting
+ protected void setProvider(IBuildProvider provider) {
+ mProvider = provider;
+ }
+
+ private IBuildProvider getProvider() {
+ if (mProvider == null) {
+ mProvider = new CompatibilityBuildProvider();
+ }
+ return mProvider;
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopier.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopier.java
new file mode 100644
index 0000000..87a667b
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopier.java
@@ -0,0 +1,133 @@
+/*
+ * 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.result.suite;
+
+import com.android.annotations.VisibleForTesting;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.util.ChecksumReporter;
+import com.android.compatibility.common.util.ResultHandler;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.util.FileUtil;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Recursively copy all the files from a previous session into the current one if they don't exists
+ * already.
+ */
+public class PreviousSessionFileCopier implements ITestInvocationListener {
+
+ private static final List<String> NOT_RETRY_FILES =
+ Arrays.asList(
+ ChecksumReporter.NAME,
+ ChecksumReporter.PREV_NAME,
+ ResultHandler.FAILURE_REPORT_NAME,
+ "diffs");
+
+ private CompatibilityBuildHelper mBuildHelper;
+ private File mPreviousSessionDir = null;
+
+ /** Sets the previous session directory to copy from. */
+ public void setPreviousSessionDir(File previousSessionDir) {
+ mPreviousSessionDir = previousSessionDir;
+ }
+
+ @Override
+ public void invocationStarted(IInvocationContext context) {
+ if (mBuildHelper == null) {
+ mBuildHelper = createCompatibilityHelper(context.getBuildInfos().get(0));
+ }
+ }
+
+ @Override
+ public void invocationEnded(long elapsedTime) {
+ if (mPreviousSessionDir == null) {
+ CLog.e("Could not copy previous sesson files.");
+ return;
+ }
+ File resultDir = getResultDirectory();
+ copyRetryFiles(mPreviousSessionDir, resultDir);
+ }
+
+ @VisibleForTesting
+ protected CompatibilityBuildHelper createCompatibilityHelper(IBuildInfo info) {
+ return new CompatibilityBuildHelper(info);
+ }
+
+ /**
+ * Recursively copy any other files found in the previous session's result directory to the new
+ * result directory, so long as they don't already exist. For example, a "screenshots" directory
+ * generated in a previous session by a passing test will not be generated on retry unless
+ * copied from the old result directory.
+ *
+ * @param oldDir
+ * @param newDir
+ */
+ private void copyRetryFiles(File oldDir, File newDir) {
+ File[] oldChildren = oldDir.listFiles();
+ for (File oldChild : oldChildren) {
+ if (NOT_RETRY_FILES.contains(oldChild.getName())) {
+ continue; // do not copy this file/directory or its children
+ }
+ File newChild = new File(newDir, oldChild.getName());
+ if (!newChild.exists()) {
+ // If this old file or directory doesn't exist in new dir, simply copy it
+ try {
+ CLog.d("Copying %s to new session.", oldChild.getName());
+ if (oldChild.isDirectory()) {
+ FileUtil.recursiveCopy(oldChild, newChild);
+ } else {
+ FileUtil.copyFile(oldChild, newChild);
+ }
+ } catch (IOException e) {
+ CLog.w("Failed to copy file \"%s\" from previous session", oldChild.getName());
+ }
+ } else if (oldChild.isDirectory() && newChild.isDirectory()) {
+ // If both children exist as directories, make sure the children of the old child
+ // directory exist in the new child directory.
+ copyRetryFiles(oldChild, newChild);
+ }
+ }
+ }
+
+ private File getResultDirectory() {
+ File resultDir = null;
+ try {
+ resultDir = mBuildHelper.getResultDir();
+ if (resultDir != null) {
+ resultDir.mkdirs();
+ }
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ if (resultDir == null) {
+ throw new RuntimeException("Result Directory was not created");
+ }
+ if (!resultDir.exists()) {
+ throw new RuntimeException(
+ "Result Directory was not created: " + resultDir.getAbsolutePath());
+ }
+ CLog.d("Results Directory: %s", resultDir.getAbsolutePath());
+ return resultDir;
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
index 81a5f11..80493f7 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
@@ -17,26 +17,25 @@
package com.android.compatibility.common.tradefed.targetprep;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
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.metrics.proto.MetricMeasurement.Metric;
-import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.result.TestResult;
+import com.android.tradefed.result.TestRunResult;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.ITargetCleaner;
import com.android.tradefed.targetprep.TargetSetupError;
import com.android.tradefed.testtype.AndroidJUnitTest;
-import com.android.tradefed.util.proto.TfMetricProtoUtil;
import java.io.File;
import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map.Entry;
/**
* Target preparer that instruments an APK.
@@ -60,10 +59,6 @@
@Option(name = "throw-error", description = "Whether to throw error for device test failure")
protected boolean mThrowError = true;
- protected ConcurrentHashMap<TestDescription, Map<String, String>> testMetrics =
- new ConcurrentHashMap<>();
- private ConcurrentHashMap<TestDescription, String> testFailures = new ConcurrentHashMap<>();
-
/**
* {@inheritDoc}
*/
@@ -101,14 +96,13 @@
try {
instrument(device, buildInfo);
} catch (FileNotFoundException e1) {
- logError("Couldn't find apk to instrument");
- logError(e1);
+ CLog.e("Couldn't find apk to instrument");
+ CLog.e(e1);
}
}
private boolean instrument(ITestDevice device, IBuildInfo buildInfo)
throws DeviceNotAvailableException, FileNotFoundException {
- ITestInvocationListener listener = new TargetPreparerListener();
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
File apkFile = buildHelper.getTestFile(mApkFileName);
@@ -117,44 +111,37 @@
}
if (device.getAppPackageInfo(mPackageName) != null) {
- logInfo("Package %s already present on the device, uninstalling ...", mPackageName);
+ CLog.i("Package %s already present on the device, uninstalling ...", mPackageName);
device.uninstallPackage(mPackageName);
}
- logInfo("Instrumenting package: %s", mPackageName);
+ CLog.i("Instrumenting package: %s", mPackageName);
+ CollectingTestListener listener = new CollectingTestListener();
AndroidJUnitTest instrTest = new AndroidJUnitTest();
instrTest.setDevice(device);
instrTest.setInstallFile(apkFile);
instrTest.setPackageName(mPackageName);
+ instrTest.setRerunMode(false);
+ instrTest.setReRunUsingTestFile(false);
+ // TODO: Make this configurable.
+ instrTest.setIsolatedStorage(false);
instrTest.run(listener);
- boolean success = true;
- if (!testFailures.isEmpty()) {
- for (TestDescription test : testFailures.keySet()) {
- success = false;
- String trace = testFailures.get(test);
+ TestRunResult result = listener.getCurrentRunResults();
+
+ for (Entry<TestDescription, TestResult> results : result.getTestResults().entrySet()) {
+ if (TestStatus.FAILURE.equals(results.getValue().getStatus())) {
if (mThrowError) {
- logError("Target preparation step %s failed.\n%s", test.getTestName(), trace);
+ CLog.e(
+ "Target preparation step %s failed.\n%s",
+ results.getKey(), results.getValue().getStackTrace());
} else {
- logWarning("Target preparation step %s failed.\n%s", test.getTestName(),
- trace);
+ CLog.w(
+ "Target preparation step %s failed.\n%s",
+ results.getKey(), results.getValue().getStackTrace());
}
}
}
- return success;
+ // If any failure return false
+ return !(result.isRunFailure() || result.hasFailedTests());
}
-
- private class TargetPreparerListener implements ITestInvocationListener {
-
- @Override
- public void testEnded(TestDescription test, HashMap<String, Metric> metrics) {
- testMetrics.put(test, TfMetricProtoUtil.compatibleConvert(metrics));
- }
-
- @Override
- public void testFailed(TestDescription test, String trace) {
- testFailures.put(test, trace);
- }
-
- }
-
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BuildFingerPrintPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BuildFingerPrintPreparer.java
new file mode 100644
index 0000000..a96b76a
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BuildFingerPrintPreparer.java
@@ -0,0 +1,108 @@
+/*
+ * 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.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BaseTargetPreparer;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+/**
+ * Special preparer used to check the build fingerprint of a device against an expected one.
+ *
+ * <p>An "unaltered" fingerprint might be available. Which reflects that the official fingerprint
+ * has been modified for business reason, but we still want to validate the original device is the
+ * same.
+ */
+public final class BuildFingerPrintPreparer extends BaseTargetPreparer {
+
+ private String mExpectedFingerprint = null;
+ private String mExpectedVendorFingerprint = null;
+ private String mUnalteredFingerprint = null;
+
+ private String mFingerprintProperty = "ro.build.fingerprint";
+ private String mVendorFingerprintProperty = "ro.vendor.build.fingerprint";
+
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo)
+ throws TargetSetupError, BuildError, DeviceNotAvailableException {
+ if (mExpectedFingerprint == null) {
+ throw new TargetSetupError("build fingerprint shouldn't be null",
+ device.getDeviceDescriptor());
+ }
+ try {
+ String compare = mExpectedFingerprint;
+ if (mUnalteredFingerprint != null) {
+ compare = mUnalteredFingerprint;
+ }
+ String currentBuildFingerprint = device.getProperty(mFingerprintProperty);
+ if (!compare.equals(currentBuildFingerprint)) {
+ throw new TargetSetupError(
+ String.format(
+ "Device build fingerprint must match %s. Found '%s' instead.",
+ compare, currentBuildFingerprint),
+ device.getDeviceDescriptor());
+ }
+ if (mExpectedVendorFingerprint != null) {
+ String currentBuildVendorFingerprint =
+ device.getProperty(mVendorFingerprintProperty);
+ if (!mExpectedVendorFingerprint.equals(currentBuildVendorFingerprint)) {
+ throw new TargetSetupError(
+ String.format(
+ "Device vendor build fingerprint must match %s - found %s instead.",
+ mExpectedVendorFingerprint, currentBuildVendorFingerprint),
+ device.getDeviceDescriptor());
+ }
+ }
+ } catch (DeviceNotAvailableException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Sets the expected fingerprint we are checking against.
+ */
+ public void setExpectedFingerprint(String expectedFingerprint) {
+ mExpectedFingerprint = expectedFingerprint;
+ }
+
+ /**
+ * Returns the expected fingerprint.
+ */
+ public String getExpectedFingerprint() {
+ return mExpectedFingerprint;
+ }
+
+ /**
+ * Allow to override the base fingerprint property. In some cases, we want to check the
+ * "ro.vendor.build.fingerpint" for example.
+ */
+ public void setFingerprintProperty(String property) {
+ mFingerprintProperty = property;
+ }
+
+ /** Sets the unchanged original fingerprint. */
+ public void setUnalteredFingerprint(String unalteredFingerprint) {
+ mUnalteredFingerprint = unalteredFingerprint;
+ }
+
+ /** Set the property value associated with ro.vendor.build.fingerprint */
+ public void setExpectedVendorFingerprint(String expectedVendorFingerprint) {
+ mExpectedVendorFingerprint = expectedVendorFingerprint;
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java
index c24b439..48709fc 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparer.java
@@ -22,14 +22,19 @@
import com.android.compatibility.common.util.FeatureUtil;
import com.android.compatibility.common.util.PropertyUtil;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.GlobalConfiguration;
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.BuildError;
import com.android.tradefed.targetprep.ITargetCleaner;
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.suite.TestSuiteInfo;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.MultiMap;
@@ -64,12 +69,16 @@
/**
* Pushes business Logic to the host and the test device, for use by test cases in the test suite.
*/
-@OptionClass(alias="business-logic-preparer")
-public class BusinessLogicPreparer implements ITargetCleaner {
+@OptionClass(alias = "business-logic-preparer")
+public class BusinessLogicPreparer implements IAbiReceiver, IInvocationContextReceiver,
+ ITargetCleaner {
/* Placeholder in the service URL for the suite to be configured */
private static final String SUITE_PLACEHOLDER = "{suite-name}";
+ /* String for the key to get file from GlobalConfiguration */
+ private static final String GLOBAL_APE_API_KEY = "ape-api-key";
+
/* String for creating files to store the business logic configuration on the host */
private static final String FILE_LOCATION = "business-logic";
/* String for creating cached business logic configuration files */
@@ -122,8 +131,37 @@
"connection to the business logic service, in seconds.")
private int mMaxConnectionTime = DEFAULT_CONNECTION_TIME;
+ @Option(name = "config-filename", description = "The module name for module-level " +
+ "configurations, or the suite name for suite-level configurations. Will lookup " +
+ "suite name if not provided.")
+ private String mModuleName = null;
+
+ @Option(name = "version", description = "The module configuration version to retrieve.")
+ private String mModuleVersion = null;
+
private String mDeviceFilePushed;
private String mHostFilePushed;
+ private IAbi mAbi = null;
+ private IInvocationContext mModuleContext = null;
+
+ /** {@inheritDoc} */
+ @Override
+ public void setAbi(IAbi abi) {
+ mAbi = abi;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public IAbi getAbi() {
+ return mAbi;
+ }
+
+
+ /** {@inheritDoc} */
+ @Override
+ public void setInvocationContext(IInvocationContext invocationContext) {
+ mModuleContext = invocationContext;
+ }
/**
* {@inheritDoc}
@@ -131,6 +169,20 @@
@Override
public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, BuildError,
DeviceNotAvailableException {
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
+ if (buildHelper.hasBusinessLogicHostFile()) {
+ CLog.i("Business logic file already collected, skipping BusinessLogicPreparer.");
+ return;
+ }
+ // Ensure mModuleName is set.
+ if (mModuleName == null) {
+ mModuleName = "";
+ CLog.w("Option config-filename isn't set. Using empty string instead.");
+ }
+ if (mModuleVersion == null) {
+ CLog.w("Option version isn't set. Using 'null' instead.");
+ mModuleVersion = "null";
+ }
String requestParams = buildRequestParams(device, buildInfo);
String baseUrl = mUrl.replace(SUITE_PLACEHOLDER, getSuiteName());
String businessLogicString = null;
@@ -158,10 +210,10 @@
return;
} else {
throw new TargetSetupError(String.format("Cannot connect to business logic "
- + "service for suite %s.\nIf this problem persists, re-invoking with "
+ + "service for config %s.\nIf this problem persists, re-invoking with "
+ "option '--ignore-business-logic-failure' will cause tests to execute "
+ "anyways (though tests depending on the remote configuration will fail).",
- TestSuiteInfo.getInstance().getName()), device.getDeviceDescriptor());
+ mModuleName), device.getDeviceDescriptor());
}
}
@@ -173,12 +225,13 @@
File hostFile = FileUtil.createTempFile(FILE_LOCATION, FILE_EXT);
FileUtil.writeToFile(businessLogicString, hostFile);
mHostFilePushed = hostFile.getAbsolutePath();
- CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
- buildHelper.setBusinessLogicHostFile(hostFile);
+ // Ensure bitness is set.
+ String bitness = (mAbi != null) ? mAbi.getBitness() : "";
+ buildHelper.setBusinessLogicHostFile(hostFile, bitness + mModuleName);
} catch (IOException e) {
throw new TargetSetupError(String.format(
- "Retrieved business logic for suite %s could not be written to host",
- TestSuiteInfo.getInstance().getName()), device.getDeviceDescriptor());
+ "Retrieved business logic for config %s could not be written to host",
+ mModuleName), device.getDeviceDescriptor());
}
// Push business logic string to device file
removeDeviceFile(device); // remove any existing business logic file from device
@@ -186,9 +239,8 @@
mDeviceFilePushed = BusinessLogic.DEVICE_FILE;
} else {
throw new TargetSetupError(String.format(
- "Retrieved business logic for suite %s could not be written to device %s",
- TestSuiteInfo.getInstance().getName(), device.getSerialNumber()),
- device.getDeviceDescriptor());
+ "Retrieved business logic for config %s could not be written to device %s",
+ mModuleName, device.getSerialNumber()), device.getDeviceDescriptor());
}
}
@@ -198,7 +250,12 @@
throws DeviceNotAvailableException {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
MultiMap<String, String> paramMap = new MultiMap<>();
- paramMap.put("suite_version", buildHelper.getSuiteVersion());
+ String suiteVersion = buildHelper.getSuiteVersion();
+ if (suiteVersion == null) {
+ suiteVersion = "null";
+ }
+ paramMap.put("suite_version", suiteVersion);
+ paramMap.put("module_version", mModuleVersion);
paramMap.put("oem", String.valueOf(PropertyUtil.getManufacturer(device)));
for (String feature : getBusinessLogicFeatures(device, buildInfo)) {
paramMap.put("features", feature);
@@ -218,9 +275,31 @@
return paramString;
}
+ /**
+ * Return the the first element of test-suite-tag from configuration if it's not empty,
+ * otherwise, return the name from test-suite-info.properties.
+ */
@VisibleForTesting
String getSuiteName() {
- return TestSuiteInfo.getInstance().getName().toLowerCase();
+ String suiteName = null;
+ if (mModuleContext == null) {
+ suiteName = TestSuiteInfo.getInstance().getName().toLowerCase();
+ } else {
+ List<String> testSuiteTags = mModuleContext.getConfigurationDescriptor().
+ getSuiteTags();
+ if (!testSuiteTags.isEmpty()) {
+ if (testSuiteTags.size() >= 2) {
+ CLog.i("More than 2 test-suite-tag are defined. test-suite-tag: " +
+ testSuiteTags);
+ }
+ suiteName = testSuiteTags.get(0).toLowerCase();
+ CLog.i("Using %s from test suite tags to get value from dynamic config", suiteName);
+ } else {
+ suiteName = TestSuiteInfo.getInstance().getName().toLowerCase();
+ CLog.i("Using %s from TestSuiteInfo to get value from dynamic config", suiteName);
+ }
+ }
+ return suiteName;
}
/* Get device properties list, with element format "<property_name>:<property_value>" */
@@ -428,20 +507,27 @@
/** Remove business logic file from the device */
private static void removeDeviceFile(ITestDevice device) throws DeviceNotAvailableException {
- device.executeShellCommand(String.format("rm -rf %s", BusinessLogic.DEVICE_FILE));
+ device.deleteFile(BusinessLogic.DEVICE_FILE);
}
- /*
- * Returns an OAuth2 token string obtained using a service account json key file.
- *
- * Uses the service account key file location stored in environment variable 'APE_API_KEY'
- * to request an OAuth2 token.
- */
+ /**
+ * Returns an OAuth2 token string obtained using a service account json key file.
+ *
+ * Uses the service account key file location stored in environment variable 'APE_API_KEY'
+ * to request an OAuth2 token. If APE_API_KEY wasn't set, try to get if file is dynamically
+ * downloaded from GlobalConfiguration.
+ */
private String getToken() {
String keyFilePath = System.getenv("APE_API_KEY");
if (Strings.isNullOrEmpty(keyFilePath)) {
- CLog.d("Environment variable APE_API_KEY not set.");
- return null;
+ File globalKeyFile = GlobalConfiguration.getInstance().getHostOptions().
+ getServiceAccountJsonKeyFiles().get(GLOBAL_APE_API_KEY);
+ if (globalKeyFile == null || !globalKeyFile.exists()) {
+ CLog.d("Unable to fetch the service key because neither environment variable " +
+ "APE_API_KEY is set nor the key file is dynamically downloaded.");
+ return null;
+ }
+ keyFilePath = globalKeyFile.getAbsolutePath();
}
if (Strings.isNullOrEmpty(mApiScope)) {
CLog.d("API scope not set, use flag --business-logic-api-scope.");
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceFileCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceFileCollector.java
index b91ac27..139e204 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceFileCollector.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceFileCollector.java
@@ -17,27 +17,28 @@
package com.android.compatibility.common.tradefed.targetprep;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
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 java.nio.file.Paths;
import java.io.File;
import java.io.FileNotFoundException;
-import java.util.Map;
+import java.nio.file.Paths;
import java.util.HashMap;
+import java.util.Map;
-/**
- * An {@link PreconditionPreparer} that collects one device file.
- */
+/** An {@link PreconditionPreparer} that collects one device file. */
+@OptionClass(alias = "device-file-collector")
public class DeviceFileCollector extends PreconditionPreparer {
- @Option(name = CompatibilityTest.SKIP_DEVICE_INFO_OPTION,
- shortName = 'd',
- description = "Whether device info collection should be skipped")
+ @Option(
+ name = DeviceInfoCollector.SKIP_DEVICE_INFO_OPTION,
+ shortName = 'd',
+ description = "Whether device info collection should be skipped"
+ )
private boolean mSkipDeviceInfo = false;
@Option(name = "src-file", description = "The file path to copy to the results dir")
@@ -101,7 +102,7 @@
return;
}
} catch (FileNotFoundException fnfe) {
- fnfe.printStackTrace();
+ CLog.e(fnfe);
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
index 4aa9000..fdff02c 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
@@ -20,6 +20,7 @@
import com.android.compatibility.common.util.DevicePropertyInfo;
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.ITestLogger;
@@ -35,9 +36,8 @@
import java.io.IOException;
import java.util.Map.Entry;
-/**
- * An {@link ApkInstrumentationPreparer} that collects device info.
- */
+/** An {@link ApkInstrumentationPreparer} that collects device info. */
+@OptionClass(alias = "device-info-collector")
public class DeviceInfoCollector extends ApkInstrumentationPreparer implements ITestLoggerReceiver {
public static final String DEVICE_INFO_DIR = "device_info_dir";
@@ -52,6 +52,7 @@
private static final String BRAND = "ro.product.brand";
private static final String DEVICE = "ro.product.device";
private static final String FINGERPRINT = "ro.build.fingerprint";
+ private static final String VENDOR_FINGERPRINT = "ro.vendor.build.fingerprint";
private static final String ID = "ro.build.id";
private static final String MANUFACTURER = "ro.product.manufacturer";
private static final String MODEL = "ro.product.model";
@@ -93,16 +94,41 @@
@Override
public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
BuildError, DeviceNotAvailableException {
- DevicePropertyInfo devicePropertyInfo = new DevicePropertyInfo(ABI, ABI2, ABIS, ABIS_32,
- ABIS_64, BOARD, BRAND, DEVICE, FINGERPRINT, ID, MANUFACTURER, MODEL, PRODUCT,
- REFERENCE_FINGERPRINT, SERIAL, TAGS, TYPE, VERSION_BASE_OS, VERSION_RELEASE,
- VERSION_SDK, VERSION_SECURITY_PATCH, VERSION_INCREMENTAL);
+ if (buildInfo.getFile(DEVICE_INFO_DIR) != null) {
+ CLog.i("Device info already collected, skipping DeviceInfoCollector.");
+ return;
+ }
+ DevicePropertyInfo devicePropertyInfo =
+ new DevicePropertyInfo(
+ ABI,
+ ABI2,
+ ABIS,
+ ABIS_32,
+ ABIS_64,
+ BOARD,
+ BRAND,
+ DEVICE,
+ FINGERPRINT,
+ VENDOR_FINGERPRINT,
+ ID,
+ MANUFACTURER,
+ MODEL,
+ PRODUCT,
+ REFERENCE_FINGERPRINT,
+ SERIAL,
+ TAGS,
+ TYPE,
+ VERSION_BASE_OS,
+ VERSION_RELEASE,
+ VERSION_SDK,
+ VERSION_SECURITY_PATCH,
+ VERSION_INCREMENTAL);
// add device properties to the result with a prefix tag for each key
for (Entry<String, String> entry :
devicePropertyInfo.getPropertytMapWithPrefix(PREFIX_TAG).entrySet()) {
- buildInfo.addBuildAttribute(
- entry.getKey(), nullToEmpty(device.getProperty(entry.getValue())));
+ String property = nullToEmpty(device.getProperty(entry.getValue()));
+ buildInfo.addBuildAttribute(entry.getKey(), property);
}
if (mSkipDeviceInfo) {
return;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
index 1df6840..d004fb4 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
@@ -19,17 +19,19 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.util.DynamicConfig;
import com.android.compatibility.common.util.DynamicConfigHandler;
-import com.android.ddmlib.Log;
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;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.targetprep.BaseTargetPreparer;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.ITargetCleaner;
import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.testtype.IInvocationContextReceiver;
+import com.android.tradefed.testtype.suite.TestSuiteInfo;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.StreamUtil;
@@ -41,18 +43,22 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.util.List;
-/**
- * Pushes dynamic config files from config repository
- */
-@OptionClass(alias="dynamic-config-pusher")
-public class DynamicConfigPusher extends BaseTargetPreparer implements ITargetCleaner {
+/** Pushes dynamic config files from config repository */
+@OptionClass(alias = "dynamic-config-pusher")
+public class DynamicConfigPusher extends BaseTargetPreparer
+ implements ITargetCleaner, IInvocationContextReceiver {
public enum TestTarget {
DEVICE,
HOST
}
- private static final String LOG_TAG = DynamicConfigPusher.class.getSimpleName();
+ /* API Key for compatibility test project, used for dynamic configuration. */
+ private static final String API_KEY = "AIzaSyAbwX5JRlmsLeygY2WWihpIJPXFLueOQ3U";
+
+ @Option(name = "api-key", description = "API key for for dynamic configuration.")
+ private String mApiKey = API_KEY;
@Option(name = "cleanup", description = "Whether to remove config files from the test " +
"target after test completion.")
@@ -60,11 +66,12 @@
@Option(name = "config-url", description = "The url path of the dynamic config. If set, " +
"will override the default config location defined in CompatibilityBuildProvider.")
- private String mConfigUrl;
+ private String mConfigUrl = "https://androidpartner.googleapis.com/v1/dynamicconfig/" +
+ "suites/{suite-name}/modules/{module}/version/{version}?key={api-key}";
@Option(name="config-filename", description = "The module name for module-level " +
- "configurations, or the suite name for suite-level configurations", mandatory = true)
- private String mModuleName;
+ "configurations, or the suite name for suite-level configurations")
+ private String mModuleName = null;
@Option(name = "target", description = "The test target, \"device\" or \"host\"",
mandatory = true)
@@ -86,12 +93,25 @@
+ "logged under the module name.")
private String mResourceFileName = null;
+ @Option(name = "dynamic-config-name",
+ description = "The dynamic config name for module-level configurations, or the "
+ + "suite name for suite-level configurations.")
+ private String mDynamicConfigName = null;
+
private String mDeviceFilePushed;
+ private IInvocationContext mModuleContext = null;
+
void setModuleName(String moduleName) {
mModuleName = moduleName;
}
+ /** {@inheritDoc} */
+ @Override
+ public void setInvocationContext(IInvocationContext invocationContext) {
+ mModuleContext = invocationContext;
+ }
+
/**
* {@inheritDoc}
*/
@@ -103,27 +123,32 @@
File localConfigFile = getLocalConfigFile(buildHelper, device);
+ String suiteName =
+ (mModuleContext != null) ? getSuiteName() : TestSuiteInfo.getInstance().getName();
+ // Ensure mModuleName is set.
+ if (mModuleName == null) {
+ mModuleName = suiteName.toLowerCase();
+ CLog.w("Option config-filename isn't set. Using suite-name '%s'", mModuleName);
+ if (buildHelper.getDynamicConfigFiles().get(mModuleName) != null) {
+ CLog.i("Dynamic config file already collected, skipping DynamicConfigPusher.");
+ return;
+ }
+ }
if (mVersion == null) {
mVersion = buildHelper.getSuiteVersion();
}
String apfeConfigInJson = null;
- String originUrl = (mConfigUrl != null) ? mConfigUrl : buildHelper.getDynamicConfigUrl();
-
- if (originUrl != null) {
- String requestUrl = originUrl;
- try {
- requestUrl = originUrl
- .replace("{module}", mModuleName).replace("{version}", mVersion);
- java.net.URL request = new URL(requestUrl);
- apfeConfigInJson = StreamUtil.getStringFromStream(request.openStream());
- } catch (IOException e) {
- LogUtil.printLog(Log.LogLevel.WARN, LOG_TAG,
- "Cannot download and parse json config from URL " + requestUrl);
- }
- } else {
- LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG,
- "Dynamic config override URL is not set, using local configuration values");
+ String requestUrl = null;
+ try {
+ requestUrl = mConfigUrl.replace("{suite-name}", suiteName)
+ .replace("{module}", mModuleName)
+ .replace("{version}", mVersion)
+ .replace("{api-key}", mApiKey);
+ java.net.URL request = new URL(requestUrl);
+ apfeConfigInJson = StreamUtil.getStringFromStream(request.openStream());
+ } catch (IOException e) {
+ CLog.w(e);
}
// Use DynamicConfigHandler to merge local and service configuration into one file
@@ -152,10 +177,37 @@
// Remove any file we have pushed to the device, host file will be moved to the result
// directory by ResultReporter upon invocation completion.
if (mDeviceFilePushed != null && !(e instanceof DeviceNotAvailableException) && mCleanup) {
- device.executeShellCommand("rm -r " + mDeviceFilePushed);
+ device.deleteFile(mDeviceFilePushed);
}
}
+ /**
+ * Return the the first element of test-suite-tag from configuration if it's not empty,
+ * otherwise, return the name from test-suite-info.properties.
+ */
+ @VisibleForTesting
+ String getSuiteName() {
+ List<String> testSuiteTags = mModuleContext.getConfigurationDescriptor().getSuiteTags();
+ String suiteName = null;
+ if (!testSuiteTags.isEmpty()) {
+ if (testSuiteTags.size() >= 2) {
+ CLog.i("More than 2 test-suite-tag are defined. test-suite-tag: " + testSuiteTags);
+ }
+ suiteName = testSuiteTags.get(0).toUpperCase();
+ CLog.i(
+ "Replacing {suite-name} placeholder with %s from test suite tags in dynamic "
+ + "config url.",
+ suiteName);
+ } else {
+ suiteName = TestSuiteInfo.getInstance().getName();
+ CLog.i(
+ "Replacing {suite-name} placeholder with %s from TestSuiteInfo in dynamic "
+ + "config url.",
+ suiteName);
+ }
+ return suiteName;
+ }
+
@VisibleForTesting
final File getLocalConfigFile(CompatibilityBuildHelper buildHelper, ITestDevice device)
throws TargetSetupError {
@@ -178,7 +230,8 @@
// If not from resources look at local path.
try {
- localConfigFile = buildHelper.getTestFile(String.format("%s.dynamic", mModuleName));
+ String lookupName = (mDynamicConfigName != null) ? mDynamicConfigName : mModuleName;
+ localConfigFile = buildHelper.getTestFile(String.format("%s.dynamic", lookupName));
} catch (FileNotFoundException e) {
throw new TargetSetupError("Cannot get local dynamic config file from test directory",
e, device.getDeviceDescriptor());
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
index 9970c4f..87beb75 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
@@ -15,78 +15,28 @@
*/
package com.android.compatibility.common.tradefed.targetprep;
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.targetprep.PushFilePreparer;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
import java.io.File;
-import java.io.FileNotFoundException;
-/**
- * Pushes specified testing artifacts from Compatibility repository.
- */
-@OptionClass(alias="file-pusher")
-public class FilePusher extends PushFilePreparer implements IAbiReceiver {
+/** Pushes specified testing artifacts from Compatibility repository. */
+@OptionClass(alias = "file-pusher")
+public final class FilePusher extends PushFilePreparer {
@Option(name = "append-bitness",
description = "Append the ABI's bitness to the filename.")
private boolean mAppendBitness = false;
- private CompatibilityBuildHelper mBuildHelper = null;
-
- private IAbi mAbi;
-
- private void setBuildHelper(IBuildInfo buildInfo) {
- if (mBuildHelper == null) {
- mBuildHelper = new CompatibilityBuildHelper(buildInfo);
- }
- }
-
- protected File getTestsDir(IBuildInfo buildInfo) throws FileNotFoundException {
- setBuildHelper(buildInfo);
- return mBuildHelper.getTestsDir();
- }
-
- protected File getTestFile(IBuildInfo buildInfo, String filename) throws FileNotFoundException {
- setBuildHelper(buildInfo);
- return mBuildHelper.getTestFile(filename);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setAbi(IAbi abi) {
- mAbi = abi;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public IAbi getAbi() {
- return mAbi;
- }
-
/**
* {@inheritDoc}
*/
@Override
public File resolveRelativeFilePath(IBuildInfo buildInfo, String fileName) {
- try {
- File f = getTestFile(buildInfo,
- String.format("%s%s", fileName, mAppendBitness ? mAbi.getBitness() : ""));
- CLog.logAndDisplay(LogLevel.INFO, "Copying from %s", f.getAbsolutePath());
- return f;
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- return null;
+ return super.resolveRelativeFilePath(
+ buildInfo,
+ String.format("%s%s", fileName, mAppendBitness ? getAbi().getBitness() : ""));
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
index 548dd6f..25351a1 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
@@ -19,6 +19,7 @@
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.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
@@ -50,7 +51,7 @@
return; // skip this precondition if required location feature is not present
}
- logInfo("Verifying location setting");
+ CLog.i("Verifying location setting");
mSettingName = LOCATION_SETTING;
mSettingType = SettingsPreparer.SettingType.SECURE;
mExpectedSettingValues.add(NETWORK);
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparer.java
index 67dd528..427a4bc 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparer.java
@@ -15,6 +15,7 @@
*/
package com.android.compatibility.common.tradefed.targetprep;
+import com.android.annotations.VisibleForTesting;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.util.DynamicConfigFileReader;
import com.android.ddmlib.IDevice;
@@ -25,9 +26,11 @@
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.targetprep.BaseTargetPreparer;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
import com.android.tradefed.testtype.AndroidJUnitTest;
@@ -47,33 +50,43 @@
import java.util.regex.Pattern;
import java.util.zip.ZipFile;
-/**
- * Ensures that the appropriate media files exist on the device
- */
-@OptionClass(alias="media-preparer")
-public class MediaPreparer extends PreconditionPreparer {
+/** Ensures that the appropriate media files exist on the device */
+@OptionClass(alias = "media-preparer")
+public class MediaPreparer extends BaseTargetPreparer {
- @Option(name = "local-media-path",
- description = "Absolute path of the media files directory, containing" +
- "'bbb_short' and 'bbb_full' directories")
- protected String mLocalMediaPath = null;
+ @Option(
+ name = "local-media-path",
+ description =
+ "Absolute path of the media files directory, containing"
+ + "'bbb_short' and 'bbb_full' directories"
+ )
+ private String mLocalMediaPath = null;
- @Option(name = "skip-media-download",
- description = "Whether to skip the media files precondition")
- protected boolean mSkipMediaDownload = false;
+ @Option(
+ name = "skip-media-download",
+ description = "Whether to skip the media files precondition"
+ )
+ private boolean mSkipMediaDownload = false;
- @Option(name = "media-download-only",
- description = "Only download media files; do not run instrumentation or copy files")
- protected boolean mMediaDownloadOnly = false;
+ /** @deprecated do not use it. */
+ @Deprecated
+ @Option(
+ name = "media-download-only",
+ description =
+ "Deprecated: Only download media files; do not run instrumentation or copy files"
+ )
+ private boolean mMediaDownloadOnly = false;
- @Option(name = "images-only",
- description = "Only push images files to the device")
- protected boolean mImagesOnly = false;
+ @Option(name = "images-only", description = "Only push images files to the device")
+ private boolean mImagesOnly = false;
- @Option(name = "push-all",
- description = "Push everything downloaded to the device,"
- + " use 'media-folder-name' to specify the destination dir name.")
- protected boolean mPushAll = false;
+ @Option(
+ name = "push-all",
+ description =
+ "Push everything downloaded to the device,"
+ + " use 'media-folder-name' to specify the destination dir name."
+ )
+ private boolean mPushAll = false;
@Option(name = "dynamic-config-module",
description = "For a target preparer, the 'module' of the configuration" +
@@ -174,6 +187,11 @@
public String toString() {
return String.format("%dx%d", width, height);
}
+
+ /** Returns the width of the resolution. */
+ public int getWidth() {
+ return width;
+ }
}
public static File getDefaultMediaDir() {
@@ -189,6 +207,7 @@
*
* This method is exposed for unit testing.
*/
+ @VisibleForTesting
protected boolean mediaFilesExistOnDevice(ITestDevice device)
throws DeviceNotAvailableException {
if (mPushAll) {
@@ -236,45 +255,56 @@
* this file to the same location on the host. Only an issue in Android O and above,
* where MediaPreparer is used for multiple, shardable modules.
*/
- private synchronized File downloadMediaToHost(ITestDevice device, IBuildInfo buildInfo)
+ private File downloadMediaToHost(ITestDevice device, IBuildInfo buildInfo)
throws TargetSetupError {
- // Retrieve default directory for storing media files
- File mediaFolder = getMediaDir();
- if (mediaFolder.exists() && mediaFolder.list().length > 0) {
- // Folder has already been created and populated by previous MediaPreparer runs,
- // assume all necessary media files exist inside.
+ // Make sure the synchronization is on the class and not the object
+ synchronized (MediaPreparer.class) {
+ // Retrieve default directory for storing media files
+ File mediaFolder = getMediaDir();
+ if (mediaFolder.exists() && mediaFolder.list().length > 0) {
+ // Folder has already been created and populated by previous MediaPreparer runs,
+ // assume all necessary media files exist inside.
+ return mediaFolder;
+ }
+ mediaFolder.mkdirs();
+ URL url;
+ try {
+ // Get download URL from dynamic configuration service
+ String mediaUrlString =
+ DynamicConfigFileReader.getValueFromConfig(
+ buildInfo, mDynamicConfigModule, MEDIA_FILES_URL_KEY);
+ url = new URL(mediaUrlString);
+ } catch (IOException | XmlPullParserException e) {
+ throw new TargetSetupError(
+ "Trouble finding media file download location with "
+ + "dynamic configuration",
+ e,
+ device.getDeviceDescriptor());
+ }
+ File mediaFolderZip = new File(mediaFolder.getAbsolutePath() + ".zip");
+ try {
+ LogUtil.printLog(
+ Log.LogLevel.INFO,
+ LOG_TAG,
+ String.format("Downloading media files from %s", url.toString()));
+ URLConnection conn = url.openConnection();
+ InputStream in = conn.getInputStream();
+ mediaFolderZip.createNewFile();
+ FileUtil.writeToFile(in, mediaFolderZip);
+ LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG, "Unzipping media files");
+ ZipUtil.extractZip(new ZipFile(mediaFolderZip), mediaFolder);
+ } catch (IOException e) {
+ FileUtil.recursiveDelete(mediaFolder);
+ throw new TargetSetupError(
+ "Failed to download and open media files on host, the"
+ + " device requires these media files for compatibility tests",
+ e,
+ device.getDeviceDescriptor());
+ } finally {
+ FileUtil.deleteFile(mediaFolderZip);
+ }
return mediaFolder;
}
- mediaFolder.mkdirs();
- URL url;
- try {
- // Get download URL from dynamic configuration service
- String mediaUrlString = DynamicConfigFileReader.getValueFromConfig(
- buildInfo, mDynamicConfigModule, MEDIA_FILES_URL_KEY);
- url = new URL(mediaUrlString);
- } catch (IOException | XmlPullParserException e) {
- throw new TargetSetupError("Trouble finding media file download location with " +
- "dynamic configuration", e, device.getDeviceDescriptor());
- }
- File mediaFolderZip = new File(mediaFolder.getAbsolutePath() + ".zip");
- try {
- LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG,
- String.format("Downloading media files from %s", url.toString()));
- URLConnection conn = url.openConnection();
- InputStream in = conn.getInputStream();
- mediaFolderZip.createNewFile();
- FileUtil.writeToFile(in, mediaFolderZip);
- LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG, "Unzipping media files");
- ZipUtil.extractZip(new ZipFile(mediaFolderZip), mediaFolder);
- } catch (IOException e) {
- FileUtil.recursiveDelete(mediaFolder);
- throw new TargetSetupError("Failed to download and open media files on host, the"
- + " device requires these media files for compatibility tests", e,
- device.getDeviceDescriptor());
- } finally {
- FileUtil.deleteFile(mediaFolderZip);
- }
- return mediaFolder;
}
/*
@@ -301,14 +331,14 @@
protected void copyVideoFiles(ITestDevice device) throws DeviceNotAvailableException {
for (Resolution resolution : RESOLUTIONS) {
if (resolution.width > mMaxRes.width) {
- logInfo("Media file copying complete");
+ CLog.i("Media file copying complete");
return;
}
String deviceShortFilePath = mBaseDeviceShortDir + resolution.toString();
String deviceFullFilePath = mBaseDeviceFullDir + resolution.toString();
if (!device.doesFileExist(deviceShortFilePath) ||
!device.doesFileExist(deviceFullFilePath)) {
- logInfo("Copying files of resolution %s to device", resolution.toString());
+ CLog.i("Copying files of resolution %s to device", resolution.toString());
String localShortDirName = "bbb_short/" + resolution.toString();
String localFullDirName = "bbb_full/" + resolution.toString();
File localShortDir = new File(mLocalMediaPath, localShortDirName);
@@ -328,7 +358,7 @@
// copy image files to the device
protected void copyImagesFiles(ITestDevice device) throws DeviceNotAvailableException {
if (!device.doesFileExist(mBaseDeviceImagesDir)) {
- logInfo("Copying images files to device");
+ CLog.i("Copying images files to device");
device.pushDir(new File(mLocalMediaPath, "images"), mBaseDeviceImagesDir);
}
}
@@ -336,7 +366,7 @@
// copy everything from the host directory to the device
protected void copyAll(ITestDevice device) throws DeviceNotAvailableException {
if (!device.doesFileExist(mBaseDeviceModuleDir)) {
- logInfo("Copying files to device");
+ CLog.i("Copying files to device");
device.pushDir(new File(mLocalMediaPath), mBaseDeviceModuleDir);
}
}
@@ -351,27 +381,28 @@
}
@Override
- public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
- BuildError, DeviceNotAvailableException {
+ public void setUp(ITestDevice device, IBuildInfo buildInfo)
+ throws TargetSetupError, BuildError, DeviceNotAvailableException {
if (mImagesOnly && mPushAll) {
throw new TargetSetupError(
- "'images-only' and 'push-all' cannot be set to true together.");
+ "'images-only' and 'push-all' cannot be set to true together.",
+ device.getDeviceDescriptor());
}
if (mSkipMediaDownload) {
- logInfo("Skipping media preparation");
+ CLog.i("Skipping media preparation");
return; // skip this precondition
}
- if (!mMediaDownloadOnly) {
- setMountPoint(device);
- if (!mImagesOnly && !mPushAll) {
- setMaxRes(device, buildInfo); // max resolution only applies to video files
- }
- if (mediaFilesExistOnDevice(device)) {
- // if files already on device, do nothing
- logInfo("Media files found on the device");
- return;
- }
+
+ setMountPoint(device);
+ if (!mImagesOnly && !mPushAll) {
+ setMaxRes(device, buildInfo); // max resolution only applies to video files
}
+ if (mediaFilesExistOnDevice(device)) {
+ // if files already on device, do nothing
+ CLog.i("Media files found on the device");
+ return;
+ }
+
if (mLocalMediaPath == null) {
// Option 'local-media-path' has not been defined
// Get directory to store media files on this host
@@ -379,10 +410,8 @@
// set mLocalMediaPath to extraction location of media files
updateLocalMediaPath(device, mediaFolder);
}
- logInfo("Media files located on host at: %s", mLocalMediaPath);
- if (!mMediaDownloadOnly) {
- copyMediaFiles(device);
- }
+ CLog.i("Media files located on host at: %s", mLocalMediaPath);
+ copyMediaFiles(device);
}
// Initialize maximum resolution of media files to copy
@@ -399,14 +428,15 @@
}
} catch (FileNotFoundException e) {
mMaxRes = DEFAULT_MAX_RESOLUTION;
- logWarning("Cound not find %s to determine maximum resolution, copying up to %s",
+ CLog.w(
+ "Cound not find %s to determine maximum resolution, copying up to %s",
APP_APK, DEFAULT_MAX_RESOLUTION.toString());
return;
}
if (device.getAppPackageInfo(APP_PKG_NAME) != null) {
device.uninstallPackage(APP_PKG_NAME);
}
- logInfo("Instrumenting package %s:", APP_PKG_NAME);
+ CLog.i("Instrumenting package %s:", APP_PKG_NAME);
AndroidJUnitTest instrTest = new AndroidJUnitTest();
instrTest.setDevice(device);
instrTest.setInstallFile(apkFile);
@@ -414,11 +444,12 @@
instrTest.run(listener);
if (mFailureStackTrace != null) {
mMaxRes = DEFAULT_MAX_RESOLUTION;
- logWarning("Retrieving maximum resolution failed with trace:\n%s", mFailureStackTrace);
- logWarning("Copying up to %s", DEFAULT_MAX_RESOLUTION.toString());
+ CLog.w("Retrieving maximum resolution failed with trace:\n%s", mFailureStackTrace);
+ CLog.w("Copying up to %s", DEFAULT_MAX_RESOLUTION.toString());
} else if (mMaxRes == null) {
mMaxRes = DEFAULT_MAX_RESOLUTION;
- logWarning("Failed to pull resolution capabilities from device, copying up to %s",
+ CLog.w(
+ "Failed to pull resolution capabilities from device, copying up to %s",
DEFAULT_MAX_RESOLUTION.toString());
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PackageDisabler.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PackageDisabler.java
index da7ce22..40fbf30 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PackageDisabler.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PackageDisabler.java
@@ -21,6 +21,7 @@
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.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
@@ -38,7 +39,7 @@
throws TargetSetupError, BuildError, DeviceNotAvailableException {
if (device.getAppPackageInfo(mPackageName) != null) {
- logInfo("Package %s installed, disabling ...", mPackageName);
+ CLog.i("Package %s installed, disabling ...", mPackageName);
device.executeShellCommand("pm disable-user " + mPackageName);
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java
index d47b56c..26c119a 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PreconditionPreparer.java
@@ -16,7 +16,6 @@
package com.android.compatibility.common.tradefed.targetprep;
-import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.ConfigurationException;
@@ -26,6 +25,7 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.BaseTargetPreparer;
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.targetprep.TargetSetupError;
@@ -34,19 +34,27 @@
import java.util.List;
/**
- * An {@link ITargetPreparer} that performs checks and/or tasks to ensure the
- * the device is ready to run the test suite.
+ * An {@link ITargetPreparer} that performs checks and/or tasks to ensure the the device is ready to
+ * run the test suite.
*/
-public abstract class PreconditionPreparer implements ITargetPreparer {
+public abstract class PreconditionPreparer extends BaseTargetPreparer {
- @Option(name = CompatibilityTest.SKIP_PRECONDITIONS_OPTION,
- shortName = 'o',
- description = "Whether preconditions should be skipped")
+ public static final String SKIP_PRECONDITIONS_OPTION = "skip-preconditions";
+ public static final String PRECONDITION_ARG_OPTION = "precondition-arg";
+
+ @Option(
+ name = SKIP_PRECONDITIONS_OPTION,
+ shortName = 'o',
+ description = "Whether preconditions should be skipped"
+ )
private boolean mSkipPreconditions = false;
- @Option(name = CompatibilityTest.PRECONDITION_ARG_OPTION,
- description = "the arguments to pass to a precondition. The expected format is"
- + "\"<arg-name>:<arg-value>\"")
+ @Option(
+ name = PRECONDITION_ARG_OPTION,
+ description =
+ "the arguments to pass to a precondition. The expected format is"
+ + "\"<arg-name>:<arg-value>\""
+ )
private List<String> mPreconditionArgs = new ArrayList<>();
protected final String mLogTag = getClass().getSimpleName();
@@ -54,16 +62,17 @@
@Override
public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
BuildError, DeviceNotAvailableException {
- if (!mSkipPreconditions) {
- for (String preconditionArg : mPreconditionArgs) {
- String[] parts = preconditionArg.split(":");
- String argName = parts[0];
- // If arg-value is not supplied, set to "true"
- String argValue = (parts.length > 1) ? parts[1] : Boolean.toString(true);
- setOption(argName, argValue);
- }
- run(device, buildInfo);
+ if (mSkipPreconditions) {
+ return;
}
+ for (String preconditionArg : mPreconditionArgs) {
+ String[] parts = preconditionArg.split(":");
+ String argName = parts[0];
+ // If arg-value is not supplied, set to "true"
+ String argValue = (parts.length > 1) ? parts[1] : Boolean.toString(true);
+ setOption(argName, argValue);
+ }
+ run(device, buildInfo);
}
private void setOption(String option, String value) {
@@ -76,37 +85,54 @@
}
}
+ /**
+ * All PreconditionPreparer implementations share a base setup and can implement their own
+ * specific run logic.
+ */
public abstract void run(ITestDevice device, IBuildInfo buildInfo)
throws TargetSetupError, BuildError, DeviceNotAvailableException;
+ /** @deprecated Use {@link CLog} instead. */
+ @Deprecated
protected void logInfo(String info) {
LogUtil.printLog(Log.LogLevel.INFO, mLogTag, info);
}
+ /** @deprecated Use {@link CLog} instead. */
+ @Deprecated
protected void logInfo(String infoFormat, Object... args) {
LogUtil.printLog(Log.LogLevel.INFO, mLogTag, String.format(infoFormat, args));
}
+ /** @deprecated Use {@link CLog} instead. */
+ @Deprecated
protected void logWarning(String warning) {
LogUtil.printLog(Log.LogLevel.WARN, mLogTag, warning);
}
+ /** @deprecated Use {@link CLog} instead. */
+ @Deprecated
protected void logWarning(String warningFormat, Object... args) {
LogUtil.printLog(Log.LogLevel.WARN, mLogTag, String.format(warningFormat, args));
}
+ /** @deprecated Use {@link CLog} instead. */
+ @Deprecated
protected void logError(String error) {
LogUtil.printLog(Log.LogLevel.ERROR, mLogTag, error);
}
+ /** @deprecated Use {@link CLog} instead. */
+ @Deprecated
protected void logError(String errorFormat, Object... args) {
LogUtil.printLog(Log.LogLevel.ERROR, mLogTag, String.format(errorFormat, args));
}
+ /** @deprecated Use {@link CLog} instead. */
+ @Deprecated
protected void logError(Throwable t) {
if (t != null) {
Log.e(mLogTag, t);
}
}
-
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
index 192c095..7030a29 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheck.java
@@ -20,6 +20,7 @@
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.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
@@ -29,17 +30,25 @@
@OptionClass(alias="property-check")
public class PropertyCheck extends PreconditionPreparer {
- @Option(name = "property-name", description = "The name of the property to check",
- mandatory = true)
- protected String mPropertyName = null;
+ @Option(
+ name = "property-name",
+ description = "The name of the property to check",
+ mandatory = true
+ )
+ private String mPropertyName = null;
- @Option(name = "expected-value", description = "The expected value of the property",
- mandatory = true)
- protected String mExpectedPropertyValue = null;
+ @Option(
+ name = "expected-value",
+ description = "The expected value of the property",
+ mandatory = true
+ )
+ private String mExpectedPropertyValue = null;
- @Option(name = "throw-error",
- description = "Whether to throw an error for an unexpected property value")
- protected boolean mThrowError = false;
+ @Option(
+ name = "throw-error",
+ description = "Whether to throw an error for an unexpected property value"
+ )
+ private boolean mThrowError = false;
@Override
public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
@@ -47,7 +56,8 @@
String propertyValue = device.getProperty(mPropertyName);
if (propertyValue == null) {
- logWarning("Property \"%s\" not found on device, cannot verify value \"%s\" ",
+ CLog.w(
+ "Property \"%s\" not found on device, cannot verify value \"%s\" ",
mPropertyName, mExpectedPropertyValue);
return;
}
@@ -59,7 +69,7 @@
if(mThrowError) {
throw new TargetSetupError(msg, device.getDeviceDescriptor());
} else {
- logWarning(msg);
+ CLog.w(msg);
}
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java
deleted file mode 100644
index 432f223..0000000
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2015 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.targetprep;
-
-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.BuildError;
-import com.android.tradefed.targetprep.ITargetCleaner;
-import com.android.tradefed.targetprep.TargetSetupError;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Pulls files from the device after a test run and puts them into the result folder.
- */
-@OptionClass(alias="result-file-puller")
-public class ResultFilePuller implements ITargetCleaner {
-
- @Option(name="clear", description = "Whether to clear the src files and dirs before running the test")
- private boolean mClearSrc = true;
-
- @Option(name="src-file", description = "The file to copy to the results dir")
- private List<String> mSrcFiles = new ArrayList<>();
-
- @Option(name="src-dir", description = "The directory to copy to the results dir")
- private List<String> mSrcDirs = new ArrayList<>();
-
- @Option(name = "dest-dir", description = "The directory under the result to store the files")
- private String mDestDir;
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, BuildError,
- DeviceNotAvailableException {
- if (mClearSrc) {
- for (String file : mSrcFiles) {
- delete(device, file);
- }
- for (String dir : mSrcDirs) {
- delete(device, dir);
- }
- }
- }
-
- private void delete(ITestDevice device, String file) throws DeviceNotAvailableException {
- device.executeShellCommand(String.format("rm -rf %s", file));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
- throws DeviceNotAvailableException {
- CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
- try {
- File resultDir = buildHelper.getResultDir();
- if (mDestDir != null) {
- resultDir = new File(resultDir, mDestDir);
- }
- resultDir.mkdirs();
- if (!resultDir.isDirectory()) {
- CLog.e("%s is not a directory", resultDir.getAbsolutePath());
- return;
- }
- String resultPath = resultDir.getAbsolutePath();
- for (String file : mSrcFiles) {
- pull(device, file, resultPath);
- }
- for (String dir : mSrcDirs) {
- pull(device, dir, resultPath);
- }
- } catch (FileNotFoundException fnfe) {
- fnfe.printStackTrace();
- }
- }
-
- private void pull(ITestDevice device, String src, String dest) {
- String command = String.format("adb -s %s pull %s %s", device.getSerialNumber(), src, dest);
- try {
- Process p = Runtime.getRuntime().exec(new String[] {"/bin/bash", "-c", command});
- if (p.waitFor() != 0) {
- CLog.e("Failed to run %s", command);
- }
- } catch (Exception e) {
- CLog.e("Caught exception during pull.");
- CLog.e(e);
- }
- }
-}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
index 7bcf880..b065475 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
@@ -20,19 +20,20 @@
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.BuildError;
import com.android.tradefed.targetprep.TargetSetupError;
/**
- * This preparer ensures that the device is connected to a network.
- * The options "wifi-ssid" and "wifi-psk" allow users of the preparer to attempt connection
- * to a network. If the options are provided, the preparer disconnects any existing network
- * connection, and attempts to connect with the options provided.
+ * This preparer ensures that the device is connected to a network. The options "wifi-ssid" and
+ * "wifi-psk" allow users of the preparer to attempt connection to a network. If the options are
+ * provided, the preparer disconnects any existing network connection, and attempts to connect with
+ * the options provided.
*
- * @throws TargetSetupError if device is not connected to a network and no options are given, or
- * if the device fails to connect to the network specified in the options
+ * @throw TargetSetupError if device is not connected to a network and no options are given, or if
+ * the device fails to connect to the network specified in the options
*/
-@OptionClass(alias="wifi-check")
+@OptionClass(alias = "wifi-check")
public class WifiCheck extends PreconditionPreparer {
private static final String WIFI_FEATURE = "android.hardware.wifi";
@@ -62,18 +63,21 @@
if (mWifiSsid == null) { // no connection to create, check for existing connectivity
if (!device.checkConnectivity()) {
- logError("Device has no network connection, no ssid provided, some modules " +
- "of CTS require an active network connection");
+ CLog.e(
+ "Device has no network connection, no ssid provided, some modules "
+ + "of CTS require an active network connection");
return;
}
} else { // network provided in options, attempt to create new connection
- logInfo("Attempting connection to \"%s\"", mWifiSsid);
+ CLog.i("Attempting connection to \"%s\"", mWifiSsid);
if (!device.connectToWifiNetwork(mWifiSsid, mWifiPsk)) { // attempt connection
- logError("Unable to connect to network \"%s\", some modules of CTS" +
- "require an active network connection", mWifiSsid);
+ CLog.e(
+ "Unable to connect to network \"%s\", some modules of CTS"
+ + "require an active network connection",
+ mWifiSsid);
return;
}
}
- logInfo("Wifi is connected");
+ CLog.i("Wifi is connected");
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/BusinessLogicHostTestBase.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/BusinessLogicHostTestBase.java
index ed6e7bc..33fe835 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/BusinessLogicHostTestBase.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/BusinessLogicHostTestBase.java
@@ -19,10 +19,6 @@
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.TestName;
-
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.util.BusinessLogic;
import com.android.compatibility.common.util.BusinessLogicExecutor;
@@ -30,7 +26,10 @@
import com.android.compatibility.common.util.BusinessLogicHostExecutor;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import com.android.tradefed.testtype.suite.TestSuiteInfo;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
import java.io.File;
@@ -72,8 +71,19 @@
}
protected void loadBusinessLogic() {
+ File businessLogicFile = null;
CompatibilityBuildHelper helper = new CompatibilityBuildHelper(getBuild());
- File businessLogicFile = helper.getBusinessLogicHostFile();
+ // Check if business logic file has been already collected by suite level business logic
+ // preparer.
+ if (helper.hasBusinessLogicHostFile()) {
+ businessLogicFile = helper.getBusinessLogicHostFile();
+ }
+ else {
+ String bitness = (getAbi() != null) ? getAbi().getBitness() : "";
+ String moduleName = getInvocationContext().getConfigurationDescriptor().
+ getModuleName();
+ businessLogicFile = helper.getBusinessLogicHostFile(bitness + moduleName);
+ }
if (businessLogicFile != null && businessLogicFile.canRead()) {
mBusinessLogic = BusinessLogicFactory.createFromFile(businessLogicFile);
} else {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index 60208b1..d99a5ae 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -55,7 +55,6 @@
import com.android.tradefed.testtype.IInvocationContextReceiver;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IShardableTest;
-import com.android.tradefed.testtype.IStrictShardableTest;
import com.android.tradefed.testtype.ITestCollector;
import com.android.tradefed.testtype.suite.TestSuiteInfo;
import com.android.tradefed.util.AbiFormatter;
@@ -88,7 +87,7 @@
@Deprecated
@OptionClass(alias = "compatibility")
public class CompatibilityTest implements IDeviceTest, IShardableTest, IBuildReceiver,
- IStrictShardableTest, ISystemStatusCheckerReceiver, ITestCollector,
+ ISystemStatusCheckerReceiver, ITestCollector,
IInvocationContextReceiver {
public static final String INCLUDE_FILTER_OPTION = "include-filter";
@@ -477,6 +476,10 @@
moduleContext.addInvocationAttribute(IModuleDef.MODULE_NAME, module.getName());
moduleContext.addInvocationAttribute(IModuleDef.MODULE_ABI,
module.getAbi().getName());
+ // This format is not always true but for the deprecated runner this is best effort.
+ moduleContext.addInvocationAttribute(
+ IModuleDef.MODULE_ID,
+ String.format("%s %s", module.getAbi().getName(), module.getName()));
mInvocationContext.setModuleInvocationContext(moduleContext);
// Populate the module context with devices and builds
for (String deviceName : mInvocationContext.getDeviceConfigNames()) {
@@ -620,7 +623,7 @@
* Exposed for testing.
*/
protected Set<String> getAbisForBuildTargetArch() {
- return AbiUtils.getAbisForArch(TestSuiteInfo.getInstance().getTargetArch());
+ return AbiUtils.getAbisForArch(TestSuiteInfo.getInstance().getTargetArchs().get(0));
}
/**
@@ -836,11 +839,7 @@
return shardQueue;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public IRemoteTest getTestShard(int shardCount, int shardIndex) {
+ private IRemoteTest getTestShard(int shardCount, int shardIndex) {
CompatibilityTest test = new CompatibilityTest(shardCount, mModuleRepo, shardIndex);
OptionCopier.copyOptionsNoThrow(this, test);
// Set the shard count because the copy option on the previous line
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
index 51b33a1..6d13902 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
@@ -41,6 +41,7 @@
// literals and making it easier to converge IModuleDef and ModuleDefinition later
public static String MODULE_NAME = ModuleDefinition.MODULE_NAME;
public static String MODULE_ABI = ModuleDefinition.MODULE_ABI;
+ public static String MODULE_ID = ModuleDefinition.MODULE_ID;
/**
* @return The name of this module.
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ISubPlan.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ISubPlan.java
index eda40b2..29876a0 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ISubPlan.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ISubPlan.java
@@ -21,7 +21,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.Set;
/**
@@ -36,18 +35,6 @@
public void parse(InputStream xmlInputStream) throws ParseException;
/**
- * Retrieve the set of include filters previously added or parsed from XML.
- * @return a set of include filter strings
- */
- public Set<String> getIncludeFilters();
-
- /**
- * Retrieve the set of exclude filters previously added or parsed from XML.
- * @return a set of exclude filter strings
- */
- public Set<String> getExcludeFilters();
-
- /**
* Serialize the existing filters into a stream of XML, and write to an output stream.
* @param xmlOutputStream the {@link OutputStream} to receive subplan XML
*/
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index eb67cc8..d0aef67 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -28,9 +28,7 @@
import com.android.tradefed.config.IConfigurationFactory;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IRemoteTest;
-import com.android.tradefed.testtype.IStrictShardableTest;
import com.android.tradefed.testtype.ITestFileFilterReceiver;
import com.android.tradefed.testtype.ITestFilterReceiver;
import com.android.tradefed.util.AbiUtils;
@@ -253,9 +251,6 @@
prepareTestClass(name, abi, config, test);
}
List<IRemoteTest> shardedTests = tests;
- if (mTotalShards > 1) {
- shardedTests = splitShardableTests(tests, buildInfo);
- }
if (shardedTests.size() > 1) {
shardedTestCounts.put(id, shardedTests.size());
}
@@ -314,23 +309,6 @@
}
}
- private List<IRemoteTest> splitShardableTests(List<IRemoteTest> tests, IBuildInfo buildInfo) {
- ArrayList<IRemoteTest> shardedList = new ArrayList<>(tests.size());
- for (IRemoteTest test : tests) {
- if (test instanceof IBuildReceiver) {
- ((IBuildReceiver)test).setBuild(buildInfo);
- }
- if (mShardIndex != null && test instanceof IStrictShardableTest) {
- for (int i = 0; i < mTotalShards; i++) {
- shardedList.add(((IStrictShardableTest)test).getTestShard(mTotalShards, i));
- }
- } else {
- shardedList.add(test);
- }
- }
- return shardedList;
- }
-
private void addFilters(Set<String> stringFilters,
Map<String, List<TestFilter>> filters, Set<IAbi> abis) {
for (String filterString : stringFilters) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/SubPlan.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/SubPlan.java
index c2c7155..46e6326 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/SubPlan.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/SubPlan.java
@@ -107,6 +107,22 @@
* {@inheritDoc}
*/
@Override
+ public void clearExcludeFilters() {
+ mExcludes.clear();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clearIncludeFilters() {
+ mIncludes.clear();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public void serialize(OutputStream stream) throws IOException {
KXmlSerializer serializer = new KXmlSerializer();
serializer.setOutput(stream, ENCODING);
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTest.java
index 7d6db59..d8f310c 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTest.java
@@ -39,6 +39,8 @@
import com.android.tradefed.testtype.IInvocationContextReceiver;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.testtype.suite.BaseTestSuite;
+import com.android.tradefed.util.MultiMap;
import com.google.common.annotations.VisibleForTesting;
@@ -131,6 +133,38 @@
importance = Importance.IF_UNSET)
protected RetryType mRetryType = null;
+ @Option(
+ name = BaseTestSuite.CONFIG_PATTERNS_OPTION,
+ description =
+ "The pattern(s) of the configurations that should be loaded from a directory."
+ + " If none is explicitly specified, .*.xml and .*.config will be used."
+ + " Can be repeated."
+ )
+ private List<String> mConfigPatterns = new ArrayList<>();
+
+ @Option(
+ name = "module-metadata-include-filter",
+ description =
+ "Include modules for execution based on matching of metadata fields: for any of "
+ + "the specified filter name and value, if a module has a metadata field "
+ + "with the same name and value, it will be included. When both module "
+ + "inclusion and exclusion rules are applied, inclusion rules will be "
+ + "evaluated first. Using this together with test filter inclusion rules "
+ + "may result in no tests to execute if the rules don't overlap."
+ )
+ private MultiMap<String, String> mModuleMetadataIncludeFilter = new MultiMap<>();
+
+ @Option(
+ name = "module-metadata-exclude-filter",
+ description =
+ "Exclude modules for execution based on matching of metadata fields: for any of "
+ + "the specified filter name and value, if a module has a metadata field "
+ + "with the same name and value, it will be excluded. When both module "
+ + "inclusion and exclusion rules are applied, inclusion rules will be "
+ + "evaluated first."
+ )
+ private MultiMap<String, String> mModuleMetadataExcludeFilter = new MultiMap<>();
+
private List<ISystemStatusChecker> mStatusCheckers;
private IBuildInfo mBuildInfo;
private ITestDevice mDevice;
@@ -229,9 +263,11 @@
test.setSystemStatusChecker(mStatusCheckers);
test.setInvocationContext(mContext);
test.setConfiguration(mMainConfiguration);
+ test.addConfigPatterns(mConfigPatterns);
+ test.addModuleMetadataIncludeFilters(mModuleMetadataIncludeFilter);
+ test.addModuleMetadataExcludeFilters(mModuleMetadataExcludeFilter);
// reset the retry id - Ensure that retry of retry does not throw
test.resetRetryId();
- test.isRetry();
// clean the helper
helper.tearDown();
return test;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
index 1f8b024..802980a 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/suite/CompatibilityTestSuite.java
@@ -64,8 +64,6 @@
private String mSubPlan;
private CompatibilityBuildHelper mBuildHelper;
- /** Tag if the current instance is running as a retry from RetryFactory */
- private boolean mIsRetry = false;
/**
* Ctor that sets some default for Compatibility runs.
@@ -73,7 +71,6 @@
public CompatibilityTestSuite() {
try {
OptionSetter setter = new OptionSetter(this);
- setter.setOptionValue("config-patterns", ".*\\.config");
setter.setOptionValue("skip-loading-config-jar", "true");
} catch (ConfigurationException e) {
// Should not happen
@@ -148,31 +145,18 @@
}
/**
- * Mark the instance of CompatibilityTestSuite as a retry.
- */
- public final void isRetry() {
- mIsRetry = true;
- }
-
- /**
* {@inheritDoc}
*/
@Override
public LinkedHashMap<String, IConfiguration> loadingStrategy(
- Set<IAbi> abis, File testsDir, String suitePrefix, String suiteTag) {
+ Set<IAbi> abis, List<File> testsDirs, String suitePrefix, String suiteTag) {
LinkedHashMap<String, IConfiguration> loadedConfigs =
- super.loadingStrategy(abis, testsDir, suitePrefix, suiteTag);
+ super.loadingStrategy(abis, testsDirs, suitePrefix, suiteTag);
// Add an extra check in CTS since we never expect the config folder to be empty.
if (loadedConfigs.size() == 0) {
- if (mIsRetry) {
- // Only log if it's a retry
- CLog.logAndDisplay(LogLevel.DEBUG,
- "No module that needed to run in retry were found. nothing to do.");
- } else {
- throw new IllegalArgumentException(
- String.format("No config files found in %s or in resources.",
- testsDir.getAbsolutePath()));
- }
+ // Only log if nothing to run.
+ CLog.logAndDisplay(LogLevel.DEBUG,
+ "No module that needed to run were found. nothing to do.");
}
return loadedConfigs;
}
diff --git a/common/host-side/tradefed/tests/Android.bp b/common/host-side/tradefed/tests/Android.bp
new file mode 100644
index 0000000..57a8fb9
--- /dev/null
+++ b/common/host-side/tradefed/tests/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2015 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.
+
+java_test_host {
+ name: "compatibility-tradefed-tests",
+ defaults: ["tradefed_errorprone_defaults"],
+
+ srcs: ["src/**/*.java"],
+ java_resource_dirs: ["res"],
+
+ libs: [
+ "tradefed",
+ "compatibility-mock-tradefed",
+ "junit-host",
+ "compatibility-host-util",
+ "easymock",
+ "objenesis-host",
+ "mockito-host",
+ ],
+}
+
+
+tradefed_binary_host {
+ name: "compatibility-mock-tradefed",
+ short_name: "TESTS",
+ full_name: "Compatibility Tests",
+ version: "1",
+ static_libs: ["cts-tradefed-harness"],
+}
diff --git a/common/host-side/tradefed/tests/Android.mk b/common/host-side/tradefed/tests/Android.mk
deleted file mode 100644
index c952159..0000000
--- a/common/host-side/tradefed/tests/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2015 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.
-
-# Make a mock compatibility suite to test
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-include cts/error_prone_rules.mk
-
-LOCAL_SUITE_BUILD_NUMBER := 2
-LOCAL_SUITE_TARGET_ARCH := $(TARGET_ARCH)
-LOCAL_SUITE_NAME := TESTS
-LOCAL_SUITE_FULLNAME := "Compatibility Tests"
-LOCAL_SUITE_VERSION := 1
-
-LOCAL_MODULE := compatibility-mock-tradefed
-LOCAL_STATIC_JAVA_LIBRARIES := cts-tradefed-harness
-include cts/error_prone_rules.mk
-include $(BUILD_COMPATIBILITY_SUITE)
-
-# Make the tests
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_RESOURCE_DIRS := res
-
-include cts/error_prone_rules.mk
-LOCAL_MODULE := compatibility-tradefed-tests
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := easymock objenesis-host mockito-host
-
-LOCAL_JAVA_LIBRARIES := tradefed compatibility-mock-tradefed junit-host compatibility-host-util
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/tradefed/tests/res/testtype/testJar2.jar b/common/host-side/tradefed/tests/res/testtype/testJar2.jar
deleted file mode 100644
index a4c3179..0000000
--- a/common/host-side/tradefed/tests/res/testtype/testJar2.jar
+++ /dev/null
Binary files differ
diff --git a/common/host-side/tradefed/tests/run_tests.sh b/common/host-side/tradefed/tests/run_tests.sh
deleted file mode 100755
index 3cec79c..0000000
--- a/common/host-side/tradefed/tests/run_tests.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2015 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.
-
-HARNESS_DIR=$(dirname ${0})/../../../..
-source ${HARNESS_DIR}/test_defs.sh
-
-JARS="
- compatibility-common-util-hostsidelib\
- compatibility-common-util-tests\
- compatibility-host-util\
- compatibility-host-util-tests\
- compatibility-mock-tradefed\
- compatibility-tradefed-tests"
-
-run_tests "com.android.compatibility.common.tradefed.UnitTests" "${JARS}" "${@}"
-
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
index 10b57b9..2a0e462 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
@@ -21,6 +21,7 @@
import com.android.compatibility.common.tradefed.config.ConfigurationFactoryTest;
import com.android.compatibility.common.tradefed.presubmit.ApkPackageNameCheck;
import com.android.compatibility.common.tradefed.presubmit.CtsConfigLoadingTest;
+import com.android.compatibility.common.tradefed.presubmit.DupFileTest;
import com.android.compatibility.common.tradefed.presubmit.IntegrationTest;
import com.android.compatibility.common.tradefed.presubmit.PresubmitSetupValidation;
import com.android.compatibility.common.tradefed.presubmit.ValidateTestsAbi;
@@ -31,6 +32,8 @@
import com.android.compatibility.common.tradefed.result.ResultReporterTest;
import com.android.compatibility.common.tradefed.result.SubPlanHelperTest;
import com.android.compatibility.common.tradefed.result.suite.CertificationChecksumHelperTest;
+import com.android.compatibility.common.tradefed.result.suite.PreviousResultLoaderTest;
+import com.android.compatibility.common.tradefed.result.suite.PreviousSessionFileCopierTest;
import com.android.compatibility.common.tradefed.targetprep.BusinessLogicPreparerTest;
import com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusherTest;
import com.android.compatibility.common.tradefed.targetprep.MediaPreparerTest;
@@ -54,8 +57,8 @@
/**
* A test suite for all compatibility tradefed unit tests.
- * <p/>
- * All tests listed here should be self-contained, and do not require any external dependencies.
+ *
+ * <p>All tests listed here should be self-contained, and do not require any external dependencies.
*/
@RunWith(Suite.class)
@SuiteClasses({
@@ -72,6 +75,7 @@
// presubmit
ApkPackageNameCheck.class,
CtsConfigLoadingTest.class,
+ DupFileTest.class,
IntegrationTest.class,
PresubmitSetupValidation.class,
ValidateTestsAbi.class,
@@ -86,6 +90,8 @@
// result.suite
CertificationChecksumHelperTest.class,
+ PreviousResultLoaderTest.class,
+ PreviousSessionFileCopierTest.class,
// targetprep
BusinessLogicPreparerTest.class,
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
index 832bbe4..43284e3 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
@@ -38,6 +38,7 @@
private static final String BASE_DIR_NAME = "android-tests";
private static final String TESTCASES = "testcases";
private static final String COMMAND_LINE_ARGS = "cts -m CtsModuleTestCases";
+ private static final String BUSINESS_LOGIC_HOST_FILE = "BUSINESS_LOGIC_HOST_FILE";
private File mRoot = null;
private File mBase = null;
@@ -216,6 +217,159 @@
}
/**
+ * Test setting business logic host file. When sharding, the contents are the same.
+ */
+ public void testSetBusinessLogicHostFile() throws Exception {
+ File tmpBLFile = FileUtil.createTempFile("businesslogic-test-file", ".bl");
+ FileUtil.writeToFile("test string", tmpBLFile);
+ try {
+ mHelper.setBusinessLogicHostFile(tmpBLFile);
+ File currentBLFile = mHelper.getBusinessLogicHostFile();
+ assertNotNull(currentBLFile);
+ assertEquals(tmpBLFile, currentBLFile);
+ // In case of sharding the underlying build info will be cloned, and old build cleaned.
+ IBuildInfo clone = mBuild.clone();
+ try {
+ CompatibilityBuildHelper helperShard = new CompatibilityBuildHelper(clone);
+ File newBLFile = helperShard.getBusinessLogicHostFile();
+ assertNotNull(newBLFile);
+ // content has also followed.
+ assertEquals("test string", FileUtil.readStringFromFile(newBLFile));
+ } finally {
+ clone.cleanUp();
+ }
+ } finally {
+ FileUtil.deleteFile(tmpBLFile);
+ }
+ }
+
+ /**
+ * Test setting business logic host file with name. When sharding, the contents are the same.
+ */
+ public void testSetBusinessLogicHostFileWithModuleId() throws Exception {
+ File tmpBLFile = FileUtil.createTempFile("businesslogic-test-file", ".bl");
+ FileUtil.writeToFile("test string", tmpBLFile);
+ try {
+ String moduleId = "64MODULE1";
+ mHelper.setBusinessLogicHostFile(tmpBLFile, moduleId);
+ File currentBLFile = mHelper.getBusinessLogicHostFile(moduleId);
+ assertNotNull(currentBLFile);
+ assertEquals(tmpBLFile, currentBLFile);
+ // In case of sharding the underlying build info will be cloned, and old build cleaned.
+ IBuildInfo clone = mBuild.clone();
+ try {
+ CompatibilityBuildHelper helperShard = new CompatibilityBuildHelper(clone);
+ File newBLFile = helperShard.getBusinessLogicHostFile(moduleId);
+ assertNotNull(newBLFile);
+ // content has also followed.
+ assertEquals("test string", FileUtil.readStringFromFile(newBLFile));
+ } finally {
+ clone.cleanUp();
+ }
+ } finally {
+ FileUtil.deleteFile(tmpBLFile);
+ }
+ }
+
+ /**
+ * Test checking business logic host file. When sharding, files still exist.
+ */
+ public void testHasBusinessLogicHostFile() throws Exception {
+ File tmpBLFile = FileUtil.createTempFile("businesslogic-test-file", ".bl");
+ try {
+ mBuild.setFile(BUSINESS_LOGIC_HOST_FILE, tmpBLFile, tmpBLFile.getName());
+ assertTrue(mHelper.hasBusinessLogicHostFile());
+ // In case of sharding the underlying build info will be cloned, and old build cleaned.
+ IBuildInfo clone = mBuild.clone();
+ try {
+ CompatibilityBuildHelper helperShard = new CompatibilityBuildHelper(clone);
+ assertTrue(helperShard.hasBusinessLogicHostFile());
+ } finally {
+ clone.cleanUp();
+ }
+ } finally {
+ FileUtil.deleteFile(tmpBLFile);
+ }
+ }
+
+ /**
+ * Test checking business logic host file with name. When sharding, files still exist.
+ */
+ public void testHasBusinessLogicHostFileModuleId() throws Exception {
+ File tmpBLFile = FileUtil.createTempFile("businesslogic-test-file", ".bl");
+ try {
+ String moduleId = "64MODULE1";
+ mBuild.setFile(BUSINESS_LOGIC_HOST_FILE + moduleId, tmpBLFile, tmpBLFile.getName());
+ assertTrue(mHelper.hasBusinessLogicHostFile(moduleId));
+ // In case of sharding the underlying build info will be cloned, and old build cleaned.
+ IBuildInfo clone = mBuild.clone();
+ try {
+ CompatibilityBuildHelper helperShard = new CompatibilityBuildHelper(clone);
+ assertTrue(helperShard.hasBusinessLogicHostFile(moduleId));
+ } finally {
+ clone.cleanUp();
+ }
+ } finally {
+ FileUtil.deleteFile(tmpBLFile);
+ }
+ }
+
+ /**
+ * Test getting business logic host file. When sharding, the contents are the same.
+ */
+ public void testGetBusinessLogicHostFile() throws Exception {
+ File tmpBLFile = FileUtil.createTempFile("businesslogic-test-file", ".bl");
+ FileUtil.writeToFile("test string", tmpBLFile);
+ try {
+ mBuild.setFile(BUSINESS_LOGIC_HOST_FILE, tmpBLFile, tmpBLFile.getName());
+ File currentBLFile = mHelper.getBusinessLogicHostFile();
+ assertNotNull(currentBLFile);
+ assertEquals(tmpBLFile, currentBLFile);
+ // In case of sharding the underlying build info will be cloned, and old build cleaned.
+ IBuildInfo clone = mBuild.clone();
+ try {
+ CompatibilityBuildHelper helperShard = new CompatibilityBuildHelper(clone);
+ File newBLFile = helperShard.getBusinessLogicHostFile();
+ assertNotNull(newBLFile);
+ // content has also followed.
+ assertEquals("test string", FileUtil.readStringFromFile(newBLFile));
+ } finally {
+ clone.cleanUp();
+ }
+ } finally {
+ FileUtil.deleteFile(tmpBLFile);
+ }
+ }
+
+ /**
+ * Test getting business logic host file with name. When sharding, the contents are the same.
+ */
+ public void testGetBusinessLogicHostFileWithModuleId() throws Exception {
+ File tmpBLFile = FileUtil.createTempFile("businesslogic-test-file", ".bl");
+ FileUtil.writeToFile("test string", tmpBLFile);
+ try {
+ String moduleId = "64MODULE1";
+ mBuild.setFile(BUSINESS_LOGIC_HOST_FILE + moduleId, tmpBLFile, tmpBLFile.getName());
+ File currentBLFile = mHelper.getBusinessLogicHostFile(moduleId);
+ assertNotNull(currentBLFile);
+ assertEquals(tmpBLFile, currentBLFile);
+ // In case of sharding the underlying build info will be cloned, and old build cleaned.
+ IBuildInfo clone = mBuild.clone();
+ try {
+ CompatibilityBuildHelper helperShard = new CompatibilityBuildHelper(clone);
+ File newBLFile = helperShard.getBusinessLogicHostFile(moduleId);
+ assertNotNull(newBLFile);
+ // content has also followed.
+ assertEquals("test string", FileUtil.readStringFromFile(newBLFile));
+ } finally {
+ clone.cleanUp();
+ }
+ } finally {
+ FileUtil.deleteFile(tmpBLFile);
+ }
+ }
+
+ /**
* Sets the *_ROOT property of the build's installation location.
*
* @param value the value to set, or null to clear the property.
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java
index e2eefa4..b65d631 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProviderTest.java
@@ -15,6 +15,7 @@
*/
package com.android.compatibility.common.tradefed.build;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -101,6 +102,59 @@
assertNotNull(((IDeviceBuildInfo)info).getTestsDir());
// ensure that tests dir is never clean up.
mProvider.cleanUp(info);
+ assertNotNull(((IDeviceBuildInfo) info).getTestsDir());
+ }
+
+ /** Tests building build infos using the device information. */
+ @Test
+ public void testBaseGetBuild_withDeviceAndBuildFlavorPrefix() throws Exception {
+ // Create real testcases dir
+ new File(mRootDir, "android-cts/testcases").mkdirs();
+ OptionSetter setter = new OptionSetter(mProvider);
+ setter.setOptionValue("use-device-build-info", "true");
+ setter.setOptionValue("branch", "build_branch");
+ setter.setOptionValue("build-flavor-prefix", "prefix-");
+ EasyMock.expect(mMockDevice.getBuildId()).andReturn("8888");
+ EasyMock.expect(mMockDevice.getBuildFlavor()).andReturn("flavor");
+ EasyMock.expect(mMockDevice.getBuildAlias()).andReturn("alias");
+ EasyMock.expect(mMockDevice.getProperty("ro.product.name")).andReturn("product");
+ EasyMock.expect(mMockDevice.getProperty("ro.build.type")).andReturn("userdebug");
+ EasyMock.replay(mMockDevice);
+ IBuildInfo info = mProvider.getBuild(mMockDevice);
+ EasyMock.verify(mMockDevice);
+ assertTrue(info instanceof IDeviceBuildInfo);
+ assertEquals("prefix-flavor", ((IDeviceBuildInfo) info).getBuildFlavor());
+ // tests dir should be populated
+ assertNotNull(((IDeviceBuildInfo) info).getTestsDir());
+ // ensure that tests dir is never clean up.
+ mProvider.cleanUp(info);
+ assertNotNull(((IDeviceBuildInfo) info).getTestsDir());
+ }
+
+ /** Tests building build infos using the device information. */
+ @Test
+ public void testBaseGetBuild_withBuildFlavorAndPrefixOverride() throws Exception {
+ // Create real testcases dir
+ new File(mRootDir, "android-cts/testcases").mkdirs();
+ OptionSetter setter = new OptionSetter(mProvider);
+ setter.setOptionValue("use-device-build-info", "true");
+ setter.setOptionValue("branch", "build_branch");
+ setter.setOptionValue("build-flavor", "artificial-flavor");
+ setter.setOptionValue("build-flavor-prefix", "prefix-");
+ EasyMock.expect(mMockDevice.getBuildId()).andReturn("8888");
+ EasyMock.expect(mMockDevice.getBuildFlavor()).andReturn("flavor").anyTimes();
+ EasyMock.expect(mMockDevice.getBuildAlias()).andReturn("alias");
+ EasyMock.expect(mMockDevice.getProperty("ro.product.name")).andReturn("product");
+ EasyMock.expect(mMockDevice.getProperty("ro.build.type")).andReturn("userdebug");
+ EasyMock.replay(mMockDevice);
+ IBuildInfo info = mProvider.getBuild(mMockDevice);
+ EasyMock.verify(mMockDevice);
+ assertTrue(info instanceof IDeviceBuildInfo);
+ assertEquals("prefix-artificial-flavor", ((IDeviceBuildInfo) info).getBuildFlavor());
+ // tests dir should be populated
+ assertNotNull(((IDeviceBuildInfo) info).getTestsDir());
+ // ensure that tests dir is never clean up.
+ mProvider.cleanUp(info);
assertNotNull(((IDeviceBuildInfo)info).getTestsDir());
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
index 92f3f05..e870577 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ApkPackageNameCheck.java
@@ -19,10 +19,13 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.ConfigurationFactory;
import com.android.tradefed.config.IConfiguration;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.targetprep.TestAppInstallSetup;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.InstrumentationTest;
import com.android.tradefed.util.AaptParser;
import org.junit.Test;
@@ -81,6 +84,7 @@
.createConfigurationFromArgs(new String[] {config.getAbsolutePath()});
// For each config, we check all the apk it's going to install
List<String> apkNames = new ArrayList<>();
+ List<String> packageListNames = new ArrayList<>();
for (ITargetPreparer prep : c.getTargetPreparers()) {
if (prep instanceof TestAppInstallSetup) {
apkNames.addAll(((TestAppInstallSetup) prep).getTestsFileName());
@@ -97,6 +101,7 @@
assertNotNull(res);
String packageName = res.getPackageName();
String put = packageNames.put(packageName, apkName);
+ packageListNames.add(packageName);
// The package already exists and it's a different apk
if (put != null && !apkName.equals(put) && !EXCEPTION_LIST.contains(packageName)) {
fail(String.format("Module %s: Package name '%s' from apk '%s' was already "
@@ -104,6 +109,22 @@
config.getName(), packageName, apkName, put));
}
}
+
+ // Catch a test trying to run something it doesn't install.
+ List<IRemoteTest> tests = c.getTests();
+ for (IRemoteTest test : tests) {
+ if (test instanceof InstrumentationTest) {
+ InstrumentationTest instrumentationTest = (InstrumentationTest) test;
+ if (instrumentationTest.getPackageName() != null) {
+ if (!packageListNames.contains(instrumentationTest.getPackageName())) {
+ throw new ConfigurationException(
+ String.format("Module %s requests to run '%s' but it's not "
+ + "part of any apks.",
+ config.getName(), instrumentationTest.getPackageName()));
+ }
+ }
+ }
+ }
}
}
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
index 46c4022..856a41b 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/CtsConfigLoadingTest.java
@@ -20,17 +20,21 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.targetprep.ApkInstaller;
+import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
import com.android.compatibility.common.tradefed.testtype.JarHostTest;
import com.android.tradefed.build.FolderBuildInfo;
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.invoker.shard.token.TokenProperty;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.testtype.AndroidJUnitTest;
import com.android.tradefed.testtype.HostTest;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.ITestFilterReceiver;
+import com.android.tradefed.testtype.suite.ITestSuite;
+import com.android.tradefed.testtype.suite.params.ModuleParameters;
import org.junit.Assert;
import org.junit.Test;
@@ -39,9 +43,12 @@
import java.io.File;
import java.io.FilenameFilter;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -62,6 +69,8 @@
"bionic",
"bluetooth",
"camera",
+ "contentcapture",
+ "deviceinfo",
"deqp",
"devtools",
"framework",
@@ -87,6 +96,24 @@
"vr",
"webview"
));
+ private static final Set<String> KNOWN_MISC_MODULES =
+ new HashSet<>(
+ Arrays.asList(
+ // Modifications to the list below must be approved by someone in
+ // test/suite_harness/OWNERS.
+ "CtsSliceTestCases.config",
+ "CtsSampleDeviceTestCases.config",
+ "CtsUsbTests.config",
+ "CtsGpuToolsHostTestCases.config",
+ "CtsEdiHostTestCases.config",
+ "CtsClassLoaderFactoryPathClassLoaderTestCases.config",
+ "CtsSampleHostTestCases.config",
+ "CtsHardwareTestCases.config",
+ "CtsMonkeyTestCases.config",
+ "CtsAndroidAppTestCases.config",
+ "CtsClassLoaderFactoryInMemoryDexClassLoaderTestCases.config",
+ "CtsAppComponentFactoryTestCases.config",
+ "CtsSeccompHostTestCases.config"));
/**
* List of the officially supported runners in CTS, they meet all the interfaces criteria as
@@ -123,6 +150,35 @@
}
/**
+ * Families of module parameterization that MUST be specified explicitly in the module
+ * AndroidTest.xml.
+ */
+ private static final Set<String> MANDATORY_PARAMETERS_FAMILY = new HashSet<>();
+
+ static {
+ MANDATORY_PARAMETERS_FAMILY.add(ModuleParameters.INSTANT_APP_FAMILY);
+ MANDATORY_PARAMETERS_FAMILY.add(ModuleParameters.MULTI_ABI_FAMILY);
+ }
+
+ /**
+ * Whitelist to start enforcing metadata on modules. No additional entry will be allowed! This
+ * is meant to burn down the remaining modules definition.
+ */
+ private static final Set<String> WHITELIST_MODULE_PARAMETERS = new HashSet<>();
+
+ static {
+ WHITELIST_MODULE_PARAMETERS.add("CtsWidgetTestCases.config");
+ WHITELIST_MODULE_PARAMETERS.add("CtsSimpleCpuTestCases.config");
+ WHITELIST_MODULE_PARAMETERS.add("CtsAppSecurityHostTestCases.config");
+ WHITELIST_MODULE_PARAMETERS.add("CtsMediaStressTestCases.config");
+ WHITELIST_MODULE_PARAMETERS.add("CtsTelephonySdk28TestCases.config");
+ WHITELIST_MODULE_PARAMETERS.add("CtsHardwareTestCases.config");
+ WHITELIST_MODULE_PARAMETERS.add("CtsGestureTestCases.config");
+ WHITELIST_MODULE_PARAMETERS.add("CtsNetTestCases.config");
+ WHITELIST_MODULE_PARAMETERS.add("CtsPermissionTestCasesSdk28.config");
+ }
+
+ /**
* Test that configuration shipped in Tradefed can be parsed.
* -> Exclude deprecated ApkInstaller.
* -> Check if host-side tests are non empty.
@@ -150,6 +206,7 @@
stubFolder.setRootDir(new File(ctsRoot));
stubFolder.addBuildAttribute(CompatibilityBuildHelper.SUITE_NAME, "CTS");
stubFolder.addBuildAttribute("ROOT_DIR", ctsRoot);
+ List<String> missingMandatoryParameters = new ArrayList<>();
// We expect to be able to load every single config in testcases/
for (File config : listConfig) {
IConfiguration c = ConfigurationFactory.getInstance()
@@ -163,6 +220,13 @@
+ "common.tradefed.targetprep.ApkInstaller, options will be "
+ "the same.", config));
}
+ if (prep.getClass().isAssignableFrom(PreconditionPreparer.class)) {
+ throw new ConfigurationException(
+ String.format(
+ "%s: includes a PreconditionPreparer (%s) which is not allowed"
+ + " in modules.",
+ config.getName(), prep.getClass()));
+ }
}
// We can ensure that Host side tests are not empty.
for (IRemoteTest test : c.getTests()) {
@@ -189,11 +253,11 @@
"Test in module %s must implement ITestFilterReceiver.",
config.getName()));
}
- // Ensure that the device runner is the AJUR one if explicitly specified
+ // Ensure that the device runner is the AJUR one if explicitly specified.
if (test instanceof AndroidJUnitTest) {
AndroidJUnitTest instru = (AndroidJUnitTest) test;
if (instru.getRunnerName() != null &&
- !ALLOWED_INSTRUMENTATION_RUNNER_NAME.contains(instru.getRunnerName())) {
+ !ALLOWED_INSTRUMENTATION_RUNNER_NAME.contains(instru.getRunnerName())) {
// Some runner are exempt
if (!RUNNER_EXCEPTION.contains(instru.getRunnerName())) {
throw new ConfigurationException(
@@ -221,6 +285,26 @@
+ "field \"%s\", supported ones are: %s\nconfig: %s",
cmp, KNOWN_COMPONENTS, config), KNOWN_COMPONENTS.contains(cmp));
+ if ("misc".equals(cmp)) {
+ String configFileName = config.getName();
+ Assert.assertTrue(
+ String.format(
+ "Adding new module %s to \"misc\" component is restricted, "
+ + "please pick a component that your module fits in",
+ configFileName),
+ KNOWN_MISC_MODULES.contains(configFileName));
+ }
+
+ // Check that specified parameters are expected
+ boolean res =
+ checkModuleParameters(
+ config.getName(), cd.getMetaData(ITestSuite.PARAMETER_KEY));
+ if (!res) {
+ missingMandatoryParameters.add(config.getName());
+ }
+ // Check that specified tokens are expected
+ checkTokens(config.getName(), cd.getMetaData(ITestSuite.TOKEN_KEY));
+
// Ensure each CTS module is tagged with <option name="test-suite-tag" value="cts" />
Assert.assertTrue(String.format(
"Module config %s does not contains "
@@ -238,6 +322,70 @@
}
}
}
+ // Ensure options have been set
+ c.validateOptions();
}
+
+ // Exempt the whitelist
+ missingMandatoryParameters.removeAll(WHITELIST_MODULE_PARAMETERS);
+ // Ensure the mandatory fields are filled
+ if (!missingMandatoryParameters.isEmpty()) {
+ String msg =
+ String.format(
+ "The following %s modules are missing some of the mandatory "
+ + "parameters [instant_app, not_instant_app, "
+ + "multi_abi, not_multi_abi]: '%s'",
+ missingMandatoryParameters.size(), missingMandatoryParameters);
+ throw new ConfigurationException(msg);
+ }
+ }
+
+ /** Test that all parameter metadata can be resolved. */
+ private boolean checkModuleParameters(String configName, List<String> parameters)
+ throws ConfigurationException {
+ if (parameters == null) {
+ return false;
+ }
+ Map<String, Boolean> families = createFamilyCheckMap();
+ for (String param : parameters) {
+ try {
+ ModuleParameters p = ModuleParameters.valueOf(param.toUpperCase());
+ if (families.containsKey(p.getFamily())) {
+ families.put(p.getFamily(), true);
+ }
+ } catch (IllegalArgumentException e) {
+ throw new ConfigurationException(
+ String.format("Config: %s includes an unknown parameter '%s'.",
+ configName, param));
+ }
+ }
+ if (families.containsValue(false)) {
+ return false;
+ }
+ return true;
+ }
+
+ /** Test that all tokens can be resolved. */
+ private void checkTokens(String configName, List<String> tokens) throws ConfigurationException {
+ if (tokens == null) {
+ return;
+ }
+ for (String token : tokens) {
+ try {
+ TokenProperty.valueOf(token.toUpperCase());
+ } catch (IllegalArgumentException e) {
+ throw new ConfigurationException(
+ String.format(
+ "Config: %s includes an unknown token '%s'.", configName, token));
+ }
+ }
+ }
+
+ private Map<String, Boolean> createFamilyCheckMap() {
+ Map<String, Boolean> families = new HashMap<>();
+ for (String family : MANDATORY_PARAMETERS_FAMILY) {
+ families.put(family, false);
+ }
+ return families;
}
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
new file mode 100644
index 0000000..aef768b
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/DupFileTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.presubmit;
+
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.config.ConfigurationException;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Test to check for duplicate files in different jars and prevent the same dependencies of being
+ * included several time (which might result in version conflicts).
+ */
+@RunWith(JUnit4.class)
+public class DupFileTest {
+
+ // We ignore directories part of the common java and google packages.
+ private static final String[] IGNORE_DIRS = new String[] {"android/", "javax/annotation/"};
+
+ /** test if there are duplicate files in different jars. */
+ @Test
+ public void testDupFilesExist() throws Exception {
+ // Get list of jars.
+ List<File> jars = getListOfBuiltJars();
+
+ // Create map of files to jars.
+ Map<String, List<String>> filesToJars = getMapOfFilesAndJars(jars);
+
+ // Check if there are any files with the same name in diff jars.
+ int dupedFiles = 0;
+ StringBuilder dupedFilesSummary = new StringBuilder();
+ for (Map.Entry<String, List<String>> entry : filesToJars.entrySet()) {
+ String file = entry.getKey();
+ List<String> jarFiles = entry.getValue();
+
+ if (jarFiles.size() != 1) {
+ dupedFiles++;
+ dupedFilesSummary.append(file + ": " + jarFiles.toString() + "\n");
+ }
+ }
+
+ if (dupedFiles != 0) {
+ fail(
+ String.format(
+ "%d files are duplicated in different jars:\n%s",
+ dupedFiles, dupedFilesSummary.toString()));
+ }
+ }
+
+ /** Create map of file to jars */
+ private Map<String, List<String>> getMapOfFilesAndJars(List<File> jars) throws IOException {
+ Map<String, List<String>> map = new LinkedHashMap<String, List<String>>();
+ JarFile jarFile;
+ List<String> jarFileList;
+ // Map all the files from all the jars.
+ for (File jar : jars) {
+ jarFile = new JarFile(jar);
+ jarFileList = getListOfFiles(jarFile);
+ jarFile.close();
+
+ // Add in the jar file to the map.
+ for (String file : jarFileList) {
+ if (!map.containsKey(file)) {
+ map.put(file, new LinkedList<String>());
+ }
+
+ map.get(file).add(jar.getName());
+ }
+ }
+ return map;
+ }
+
+ /** Get the list of jars specified in the path. */
+ private List<File> getListOfBuiltJars() throws ConfigurationException {
+ String classpathStr = System.getProperty("java.class.path");
+ if (classpathStr == null) {
+ throw new ConfigurationException(
+ "Could not find the classpath property: java.class.path");
+ }
+ List<File> listOfJars = new ArrayList<File>();
+ for (String jar : classpathStr.split(":")) {
+ File jarFile = new File(jar);
+ if (jarFile.exists()) {
+ listOfJars.add(jarFile);
+ }
+ }
+ return listOfJars;
+ }
+
+ /** Return the list of files in the jar. */
+ private List<String> getListOfFiles(JarFile jar) {
+ List<String> files = new ArrayList<String>();
+ Enumeration<JarEntry> e = jar.entries();
+ while (e.hasMoreElements()) {
+ JarEntry entry = e.nextElement();
+ String filename = entry.getName();
+ if (checkThisFile(filename)) {
+ files.add(filename);
+ }
+ }
+ return files;
+ }
+
+ /** Check if we should add this file to list of files. We only want to check for classes. */
+ private Boolean checkThisFile(String filename) {
+ if (!filename.endsWith(".class")) {
+ return false;
+ }
+
+ for (String skipDir : IGNORE_DIRS) {
+ if (filename.startsWith(skipDir)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
index 594ace1..63e6fab 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
@@ -16,7 +16,6 @@
package com.android.compatibility.common.tradefed.presubmit;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.result.ResultReporter;
@@ -40,7 +39,6 @@
import com.android.tradefed.testtype.IDeviceTest;
import com.android.tradefed.testtype.IInvocationContextReceiver;
import com.android.tradefed.testtype.IRemoteTest;
-import com.android.tradefed.testtype.suite.TestSuiteInfo;
import com.android.tradefed.util.AbiUtils;
import com.android.tradefed.util.FileUtil;
@@ -57,11 +55,9 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.TimeUnit;
/**
* Integration tests between {@link CompatibilityTest} and {@link ResultReporter} to ensure proper
@@ -546,160 +542,4 @@
}
}
}
-
- /**
- * Simple tests running in one module that should be marked complete when each shard run a test
- * from the module. Each Module is going to run 1 pass 1 fail. 2 modules and 2 shards.
- * Using the {@link CompatibilityTest#split()}.
- */
- @Test
- public void testSingleModuleRun_sharded() throws Exception {
- final String moduleName = "module_sharded";
- Set<String> abis = AbiUtils.getAbisForArch(TestSuiteInfo.getInstance().getTargetArch());
- Iterator<String> ite = abis.iterator();
- final String abi1 = ite.next();
- final String abi2 = ite.next();
- createConfig(mTestDir, moduleName, TEST_STUB_SHARDABLE, true, true, true, false);
- EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(
- String.format("%s,%s", abi1, abi2));
- mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS),
- EasyMock.anyObject());
- EasyMock.expectLastCall();
-
- EasyMock.replay(mMockDevice, mMockBuildInfo);
-
- OptionSetter setter = new OptionSetter(mTest);
- setter.setOptionValue("shards", "2");
- List<IRemoteTest> tests = (List<IRemoteTest>) mTest.split();
- // We expect 2 shards
- assertEquals(2, tests.size());
-
- List<ShardThread> threads = new ArrayList<>();
- // Run all shards
- for (IRemoteTest test : tests) {
- ShardThread st = new ShardThread(test, mReporter, mMockBuildInfo, mMockDevice,
- mContext);
- threads.add(st);
- st.start();
- }
- for (ShardThread thread : threads) {
- thread.join(5000);
- }
- // Allow some time for ResultReport to finalize the results coming from the threads.
- boolean finalized = mReporter.waitForFinalized(2, TimeUnit.MINUTES);
- assertTrue(finalized);
- EasyMock.verify(mMockDevice, mMockBuildInfo);
- // Check aggregated results to make sure it's consistent.
- IInvocationResult result = mReporter.getResult();
- assertEquals(4, result.countResults(TestStatus.PASS));
- assertEquals(4, result.countResults(TestStatus.FAIL));
- assertEquals(2, result.getModules().size());
- //assertEquals(2, result.getModuleCompleteCount());
- }
-
- /**
- * Simple tests running in one module that should be marked incomplete when shards do not
- * complete. Each shard is going to run 1 pass 1 fail 1 not_executed.
- * Using the {@link CompatibilityTest#split()}.
- */
- @Test
- public void testSingleModuleRun_sharded_incomplete() throws Exception {
- final String moduleName = "module_sharded_incomplete";
- Set<String> abis = AbiUtils.getAbisForArch(TestSuiteInfo.getInstance().getTargetArch());
- Iterator<String> ite = abis.iterator();
- final String abi1 = ite.next();
- final String abi2 = ite.next();
- createConfig(mTestDir, moduleName, TEST_STUB_SHARDABLE, true, false, true, false);
- EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(
- String.format("%s,%s", abi1, abi2));
- mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS),
- EasyMock.anyObject());
- EasyMock.expectLastCall();
-
- EasyMock.replay(mMockDevice, mMockBuildInfo);
- OptionSetter setter = new OptionSetter(mTest);
- setter.setOptionValue("shards", "2");
- List<IRemoteTest> tests = (List<IRemoteTest>) mTest.split();
- // We expect 2 shards
- assertEquals(2, tests.size());
-
- List<ShardThread> threads = new ArrayList<>();
- // Run all shards
- for (IRemoteTest test : tests) {
- ShardThread st = new ShardThread(test, mReporter, mMockBuildInfo, mMockDevice,
- mContext);
- threads.add(st);
- st.start();
- }
- for (ShardThread thread : threads) {
- thread.join(5000);
- }
- // Allow some time for ResultReport to finalize the results coming from the threads.
- boolean finalized = mReporter.waitForFinalized(2, TimeUnit.MINUTES);
- assertTrue(finalized);
- EasyMock.verify(mMockDevice, mMockBuildInfo);
- // Check aggregated results to make sure it's consistent.
- IInvocationResult result = mReporter.getResult();
- assertEquals(4, result.countResults(TestStatus.PASS));
- assertEquals(4, result.countResults(TestStatus.FAIL));
- assertEquals(2, result.getModules().size());
- assertEquals(0, result.getModuleCompleteCount());
- }
-
- /**
- * Simple tests running in one module that should be marked complete when each shard run a test
- * from the module.
- * We are going to run only one of the shard since IStrictShardable allows it.
- * Using the {@link CompatibilityTest#getTestShard(int, int)}.
- * FIXME: Fix expectation of this test.
- */
- @Test
- public void testSingleModuleRun_sharded_getTestShard() throws Exception {
- final String moduleName = "module_sharded_getTestShard";
- Set<String> abis = AbiUtils.getAbisForArch(TestSuiteInfo.getInstance().getTargetArch());
- Iterator<String> ite = abis.iterator();
- final String abi1 = ite.next();
- final String abi2 = ite.next();
- createConfig(mTestDir, moduleName, TEST_STUB_SHARDABLE, true, true, true, false);
- EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(
- String.format("%s,%s", abi1, abi2));
-
- String expectedAdd = AbiUtils.createId(abi1, moduleName) + ","
- + AbiUtils.createId(abi2, moduleName);
- mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS),
- EasyMock.anyObject());
- EasyMock.expectLastCall();
- mAttributes.put(CompatibilityBuildHelper.MODULE_IDS, expectedAdd);
-
- EasyMock.replay(mMockDevice, mMockBuildInfo);
-
- List<IRemoteTest> tests = new ArrayList<>();
- tests.add(mTest.getTestShard(3, 0));
- // We are only running one of the shards since they should be independent.
- assertEquals(1, tests.size());
-
- ((IBuildReceiver)tests.get(0)).setBuild(mMockBuildInfo);
- ((IDeviceTest)tests.get(0)).setDevice(mMockDevice);
- ((IInvocationContextReceiver)tests.get(0)).setInvocationContext(mContext);
- mReporter.invocationStarted(mContext);
- try {
- tests.get(0).run(mReporter);
- } catch (DeviceNotAvailableException e) {
- throw new RuntimeException(e);
- } finally {
- mReporter.invocationEnded(500);
- }
- EasyMock.verify(mMockDevice, mMockBuildInfo);
-
- IInvocationResult result = mReporter.getResult();
- assertEquals(2, result.countResults(TestStatus.PASS));
- assertEquals(2, result.countResults(TestStatus.FAIL));
- // FIXME: Only one module should be expected since within the one shard requested to run
- // only one module existed.
- assertEquals(2, result.getModules().size());
- // FIXME: The module for the shard should be completed since all tests run.
- // TestRunHandler in this case create an expectation of 3 testRunStarted just because of
- // the number of shards.
- assertEquals(0, result.getModuleCompleteCount());
- }
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
index 297ccfc..9f2aa1b 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
@@ -115,7 +115,7 @@
if (!result.getNativeCode().isEmpty()) {
List<String> supportedAbiApk = result.getNativeCode();
Set<String> buildTarget = AbiUtils.getAbisForArch(
- TestSuiteInfo.getInstance().getTargetArch());
+ TestSuiteInfo.getInstance().getTargetArchs().get(0));
// first check, all the abis are supported
for (String abi : supportedAbiApk) {
if (!buildTarget.contains(abi)) {
@@ -176,7 +176,7 @@
// characters of their name with be the bitness (32 or 64).
Collections.sort(orderedList);
Set<String> buildTarget = AbiUtils.getAbisForArch(
- TestSuiteInfo.getInstance().getTargetArch());
+ TestSuiteInfo.getInstance().getTargetArchs().get(0));
// We expect one binary per abi of CTS, they should be appended with 32 or 64
for (int i = 0; i < orderedList.size(); i=i + buildTarget.size()) {
List<String> subSet = orderedList.subList(i, i + buildTarget.size());
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java
index 8912411..005e180 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java
@@ -89,7 +89,7 @@
mResultsDir = FileUtil.createTempDir("results");
mResultDir = FileUtil.createTempDir("12345", mResultsDir);
mSubPlansDir = FileUtil.createTempDir("subplans");
- mBuildHelper = new SpctMockCompatibilityBuildHelper(new BuildInfo("0", "", ""));
+ mBuildHelper = new SpctMockCompatibilityBuildHelper(new BuildInfo("0", ""));
populateResults();
mSubPlanHelper = new SubPlanHelper();
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/PreviousResultLoaderTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/PreviousResultLoaderTest.java
new file mode 100644
index 0000000..0669a22
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/PreviousResultLoaderTest.java
@@ -0,0 +1,252 @@
+/*
+ * 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.result.suite;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.targetprep.BuildFingerPrintPreparer;
+import com.android.tradefed.build.DeviceBuildInfo;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.build.IBuildProvider;
+import com.android.tradefed.config.Configuration;
+import com.android.tradefed.config.ConfigurationDef;
+import com.android.tradefed.config.ConfigurationDescriptor;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.invoker.InvocationContext;
+import com.android.tradefed.invoker.TestInvocation;
+import com.android.tradefed.result.proto.TestRecordProto.TestRecord;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.util.FileUtil;
+
+import com.google.protobuf.Any;
+
+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.FileOutputStream;
+
+/**
+ * Unit tests for {@link PreviousResultLoader}.
+ */
+@RunWith(JUnit4.class)
+public class PreviousResultLoaderTest {
+
+ public static final String RUN_HISTORY_KEY = "run_history";
+
+ private PreviousResultLoader mLoader;
+ private IInvocationContext mContext;
+ private File mRootDir;
+ private File mProtoFile;
+
+ private ITestDevice mMockDevice;
+ private IBuildProvider mMockProvider;
+
+ @Before
+ public void setUp() throws Exception {
+ mMockProvider = EasyMock.createMock(IBuildProvider.class);
+ mLoader = new PreviousResultLoader();
+ mLoader.setProvider(mMockProvider);
+ OptionSetter setter = new OptionSetter(mLoader);
+ setter.setOptionValue("retry", "0");
+ mContext = new InvocationContext();
+ mContext.setConfigurationDescriptor(new ConfigurationDescriptor());
+ mContext.addInvocationAttribute(TestInvocation.COMMAND_ARGS_KEY,
+ "cts -m CtsGesture --skip-all-system-status-check");
+ mMockDevice = EasyMock.createMock(ITestDevice.class);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtil.recursiveDelete(mRootDir);
+ }
+
+ /**
+ * Test the loader properly fails when the results are not loaded.
+ */
+ @Test
+ public void testReloadTests_failed() throws Exception {
+ EasyMock.expect(mMockProvider.getBuild()).andReturn(createFakeBuild(""));
+ // Delete the proto file
+ mProtoFile.delete();
+ try {
+ EasyMock.replay(mMockProvider);
+ mLoader.init();
+ fail("Should have thrown an exception.");
+ } catch (RuntimeException expected) {
+ // expected
+ assertEquals(
+ String.format("java.io.FileNotFoundException: %s (No such file or directory)",
+ mProtoFile.getAbsolutePath()), expected.getMessage());
+ }
+ EasyMock.verify(mMockProvider);
+ }
+
+ /**
+ * Test that the loader can provide the results information back.
+ */
+ @Test
+ public void testReloadTests() throws Exception {
+ final String EXPECTED_RUN_HISTORY =
+ "[{\"startTime\":1530218251501," + "\"endTime\":1530218261061}]";
+ EasyMock.expect(mMockProvider.getBuild()).andReturn(createFakeBuild(createBasicResults()));
+ mContext.addAllocatedDevice(ConfigurationDef.DEFAULT_DEVICE_NAME, mMockDevice);
+
+ EasyMock.replay(mMockDevice, mMockProvider);
+ mLoader.init();
+ assertEquals("cts -m CtsGesture --skip-all-system-status-check", mLoader.getCommandLine());
+ mLoader.loadPreviousRecord();
+ IConfiguration config = new Configuration("name", "desc");
+ assertEquals(0, config.getTargetPreparers().size());
+ mLoader.customizeConfiguration(config);
+ // A special preparer was added for fingerprint
+ assertEquals(1, config.getTargetPreparers().size());
+ ITargetPreparer preparer = config.getTargetPreparers().get(0);
+ assertTrue(preparer instanceof BuildFingerPrintPreparer);
+ assertEquals("testfingerprint",
+ ((BuildFingerPrintPreparer) preparer).getExpectedFingerprint());
+ String runHistory =
+ config.getCommandOptions().getInvocationData().getUniqueMap().get(RUN_HISTORY_KEY);
+ assertEquals(EXPECTED_RUN_HISTORY, runHistory);
+ EasyMock.verify(mMockDevice, mMockProvider);
+ }
+
+ /** Test that the loader can correctly provide the run history back. */
+ @Test
+ public void testReloadTests_withRunHistory() throws Exception {
+ final String EXPECTED_RUN_HISTORY =
+ "[{\"startTime\":10000000000000,"
+ + "\"endTime\":10000000100000},{\"startTime\":1530218251501,"
+ + "\"endTime\":1530218261061}]";
+ final String OLD_RUN_HISTORY =
+ "[{\"startTime\":10000000000000,\"endTime\":10000000100000}]";
+ mContext.addInvocationAttribute(RUN_HISTORY_KEY, OLD_RUN_HISTORY);
+ EasyMock.expect(mMockProvider.getBuild())
+ .andReturn(createFakeBuild(createResultsWithRunHistory()));
+ mContext.addAllocatedDevice(ConfigurationDef.DEFAULT_DEVICE_NAME, mMockDevice);
+ EasyMock.replay(mMockDevice, mMockProvider);
+
+ mLoader.init();
+ IConfiguration config = new Configuration("name", "desc");
+ mLoader.customizeConfiguration(config);
+ String runHistory =
+ config.getCommandOptions().getInvocationData().getUniqueMap().get(RUN_HISTORY_KEY);
+
+ assertEquals(EXPECTED_RUN_HISTORY, runHistory);
+ EasyMock.verify(mMockDevice, mMockProvider);
+ }
+
+ private IBuildInfo createFakeBuild(String resultContent) throws Exception {
+ DeviceBuildInfo build = new DeviceBuildInfo();
+ build.addBuildAttribute(CompatibilityBuildHelper.SUITE_NAME, "CTS");
+ mRootDir = FileUtil.createTempDir("cts-root-dir");
+ new File(mRootDir, "android-cts/results").mkdirs();
+ build.addBuildAttribute(CompatibilityBuildHelper.ROOT_DIR, mRootDir.getAbsolutePath());
+ // Create fake result dir
+ long time = System.currentTimeMillis();
+ build.addBuildAttribute(CompatibilityBuildHelper.START_TIME_MS, Long.toString(time));
+ new CompatibilityBuildHelper(build).getResultDir().mkdirs();
+ // Populate a test_results.xml
+ File testResult = new File(new CompatibilityBuildHelper(build).getResultDir(),
+ "test_result.xml");
+ testResult.createNewFile();
+ // Populate a proto result
+ mProtoFile = new File(new CompatibilityBuildHelper(build).getResultDir(),
+ CompatibilityProtoResultReporter.PROTO_FILE_NAME);
+ TestRecord.Builder builder = TestRecord.newBuilder();
+ builder.setDescription(Any.pack(mContext.toProto()));
+ builder.build().writeDelimitedTo(new FileOutputStream(mProtoFile));
+ FileUtil.writeToFile(resultContent, testResult);
+ return build;
+ }
+
+ private String createBasicResults() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<?xml version='1.0' encoding='UTF-8' standalone='no' ?>\n");
+ sb.append("<?xml-stylesheet type=\"text/xsl\" href=\"compatibility_result.xsl\"?>\n");
+ sb.append("<Result start=\"1530218251501\" end=\"1530218261061\" "
+ + "start_display=\"Thu Jun 28 13:37:31 PDT 2018\" "
+ + "end_display=\"Thu Jun 28 13:37:41 PDT 2018\" "
+ + "command_line_args=\"cts -m CtsGesture --skip-all-system-status-check\" "
+ + "suite_name=\"CTS\" suite_version=\"9.0_r1\" "
+ + "suite_plan=\"cts\" suite_build_number=\"8888\" report_version=\"5.0\" "
+ + "devices=\"HT6570300047\" >\n");
+ sb.append(
+ " <Build command_line_args=\"cts -m CtsGesture --skip-all-system-status-check\""
+ + " build_vendor_fingerprint=\"vendorFingerprint\" "
+ + " build_reference_fingerprint=\"\" "
+ + " build_fingerprint=\"testfingerprint\"/>\n");
+ // Summary
+ sb.append(" <Summary pass=\"0\" failed=\"0\" modules_done=\"2\" modules_total=\"2\" />\n");
+ // Each module results
+ sb.append(" <Module name=\"CtsGestureTestCases\" abi=\"arm64-v8a\" runtime=\"2776\" "
+ + "done=\"true\" pass=\"0\" total_tests=\"0\" />\n");
+ sb.append(" <Module name=\"CtsGestureTestCases\" abi=\"armeabi-v7a\" runtime=\"2776\" "
+ + "done=\"true\" pass=\"0\" total_tests=\"0\" />\n");
+ // End
+ sb.append("</Result>");
+ return sb.toString();
+ }
+
+ private String createResultsWithRunHistory() {
+ // This method is the same as createBasicResults() except that it contains run history.
+ StringBuilder sb = new StringBuilder();
+ sb.append("<?xml version='1.0' encoding='UTF-8' standalone='no' ?>\n");
+ sb.append("<?xml-stylesheet type=\"text/xsl\" href=\"compatibility_result.xsl\"?>\n");
+ sb.append(
+ "<Result start=\"1530218251501\" end=\"1530218261061\" "
+ + "start_display=\"Thu Jun 28 13:37:31 PDT 2018\" "
+ + "end_display=\"Thu Jun 28 13:37:41 PDT 2018\" "
+ + "command_line_args=\"cts -m CtsGesture --skip-all-system-status-check\" "
+ + "suite_name=\"CTS\" suite_version=\"9.0_r1\" "
+ + "suite_plan=\"cts\" suite_build_number=\"8888\" report_version=\"5.0\" "
+ + "devices=\"HT6570300047\" >\n");
+ sb.append(
+ " <Build command_line_args=\"cts -m CtsGesture --skip-all-system-status-check\""
+ + " build_vendor_fingerprint=\"vendorFingerprint\" "
+ + " build_reference_fingerprint=\"\" "
+ + " build_fingerprint=\"testfingerprint\""
+ + " run_history=\"[{'startTime':10000000000000,"
+ + "'endTime':10000000100000}]\"/>\n");
+ // Run history
+ sb.append(
+ " <RunHistory>\n"
+ + " <Run start=\"10000000000000\" end=\"10000000100000\"/>\n"
+ + " </RunHistory>\n");
+ // Summary
+ sb.append(" <Summary pass=\"0\" failed=\"0\" modules_done=\"2\" modules_total=\"2\" />\n");
+ // Each module results
+ sb.append(
+ " <Module name=\"CtsGestureTestCases\" abi=\"arm64-v8a\" runtime=\"2776\" "
+ + "done=\"true\" pass=\"0\" total_tests=\"0\" />\n");
+ sb.append(
+ " <Module name=\"CtsGestureTestCases\" abi=\"armeabi-v7a\" runtime=\"2776\" "
+ + "done=\"true\" pass=\"0\" total_tests=\"0\" />\n");
+ // End
+ sb.append("</Result>");
+ return sb.toString();
+ }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopierTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopierTest.java
new file mode 100644
index 0000000..918acd3
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/suite/PreviousSessionFileCopierTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.result.suite;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.BuildInfo;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.ConfigurationDef;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.invoker.InvocationContext;
+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.io.FileNotFoundException;
+
+/** Unit tests for {@link PreviousSessionFileCopier}. */
+@RunWith(JUnit4.class)
+public class PreviousSessionFileCopierTest {
+
+ private PreviousSessionFileCopier mCopier;
+ private File mPreviousDir;
+ private File mCurrentDir;
+ private IInvocationContext mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mCurrentDir = FileUtil.createTempDir("current-copier-tests");
+ mCopier =
+ new PreviousSessionFileCopier() {
+ @Override
+ protected CompatibilityBuildHelper createCompatibilityHelper(IBuildInfo info) {
+ return new CompatibilityBuildHelper(info) {
+ @Override
+ public File getResultDir() throws FileNotFoundException {
+ return mCurrentDir;
+ }
+ };
+ }
+ };
+ mPreviousDir = FileUtil.createTempDir("previous-copier-tests");
+ mContext = new InvocationContext();
+ mContext.addDeviceBuildInfo(ConfigurationDef.DEFAULT_DEVICE_NAME, new BuildInfo());
+ mCopier.setPreviousSessionDir(mPreviousDir);
+ }
+
+ @After
+ public void tearDown() {
+ FileUtil.recursiveDelete(mPreviousDir);
+ }
+
+ @Test
+ public void testCopy() throws Exception {
+ new File(mPreviousDir, "newFile").createNewFile();
+ assertEquals(0, mCurrentDir.listFiles().length);
+ mCopier.invocationStarted(mContext);
+ mCopier.invocationEnded(500L);
+ assertEquals(1, mCurrentDir.listFiles().length);
+ }
+
+ @Test
+ public void testCopy_fileExists() throws Exception {
+ File original = new File(mCurrentDir, "newFile");
+ original.createNewFile();
+ FileUtil.writeToFile("CURRENT", original);
+
+ File previous = new File(mPreviousDir, "newFile");
+ previous.createNewFile();
+ FileUtil.writeToFile("PREVIOUS", previous);
+
+ assertEquals(1, mCurrentDir.listFiles().length);
+ mCopier.invocationStarted(mContext);
+ mCopier.invocationEnded(500L);
+ assertEquals(1, mCurrentDir.listFiles().length);
+ // File are not overriden
+ assertEquals("CURRENT", FileUtil.readStringFromFile(original));
+ }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparerTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparerTest.java
index 7dca26f..cbffc2f 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparerTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/BusinessLogicPreparerTest.java
@@ -142,6 +142,7 @@
OptionSetter setter = new OptionSetter(mPreparer);
setter.setOptionValue("business-logic-url", serviceUrl);
setter.setOptionValue("business-logic-api-key", "fakeApiKey");
+ setter.setOptionValue("version", "fakeVersion");
}
@After
@@ -157,7 +158,7 @@
mMockBuildInfo.setFile(DeviceInfoCollector.DEVICE_INFO_DIR, jsonPath, "v1");
// Setup BuildInfo attributes.
mMockBuildInfo.addBuildAttribute(CompatibilityBuildHelper.SUITE_VERSION, "v1");
- testBuildRequestString(15, attributes);
+ testBuildRequestString(16, attributes);
}
@Test
@@ -165,7 +166,7 @@
Map<String, String> attributes = new HashMap<>();
// Setup BuildInfo attributes.
attributes.put(CompatibilityBuildHelper.SUITE_VERSION, "v1");
- testBuildRequestString(13, attributes);
+ testBuildRequestString(14, attributes);
}
private void testBuildRequestString(int expectedParams, Map<String, String> attributes) throws Exception {
@@ -181,6 +182,7 @@
mMockBuildInfo.setFile(CONFIG_VERSION + "tests", configFile, CONFIG_VERSION + "tests");
mMockBuildInfo.setFile(CONFIG_VERSION + "gts", configFile, CONFIG_VERSION + "gts");
mMockBuildInfo.setFile(CONFIG_VERSION + "cts", configFile, CONFIG_VERSION + "cts");
+ mMockBuildInfo.setFile(CONFIG_VERSION + "ats", configFile, CONFIG_VERSION + "ats");
when(mMockDevice.executeShellCommand(LIST_FEATURE_QUERY)).thenReturn(FEATURES);
// In getBusinessLogicProperties.
when(mMockDevice.executeShellCommand(GOOGLE_SETTINGS_QUERY)).thenReturn(PARTNER_CONTENT);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusherTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusherTest.java
index 152c695..bed34a5 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusherTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusherTest.java
@@ -23,8 +23,12 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.build.VersionedFile;
+import com.android.tradefed.config.ConfigurationDescriptor;
import com.android.tradefed.config.OptionSetter;
import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.invoker.InvocationContext;
import com.android.tradefed.targetprep.TargetSetupError;
import com.android.tradefed.util.FileUtil;
@@ -37,7 +41,10 @@
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.Map;
/**
@@ -50,9 +57,12 @@
private ITestDevice mMockDevice;
private CompatibilityBuildHelper mMockBuildHelper;
private IBuildInfo mMockBuildInfo;
+ private IInvocationContext mModuleContext;
@Before
public void setUp() {
+ mModuleContext = new InvocationContext();
+ mModuleContext.setConfigurationDescriptor(new ConfigurationDescriptor());
mPreparer = new DynamicConfigPusher();
mMockDevice = EasyMock.createMock(ITestDevice.class);
mMockBuildInfo = EasyMock.createMock(IBuildInfo.class);
@@ -61,6 +71,57 @@
}
/**
+ * Test getSuiteName from /test-suite-info.properties.
+ */
+ @Test
+ public void testGetSuiteName_fromTestSuiteInfo() throws Exception {
+ mPreparer = new DynamicConfigPusher();
+ mPreparer.setInvocationContext(mModuleContext);
+ EasyMock.replay(mMockDevice, mMockBuildInfo);
+ assertNotNull(mPreparer.getSuiteName());
+ EasyMock.verify(mMockDevice, mMockBuildInfo);
+ }
+
+ /**
+ * Test getSuiteName from test-suite-tag.
+ */
+ @Test
+ public void testGetSuiteName_fromTestSuiteTag() throws Exception {
+ mPreparer = new DynamicConfigPusher();
+ mModuleContext
+ .getConfigurationDescriptor()
+ .setSuiteTags(Arrays.asList("cts", "cts-instant", "gts"));
+ mPreparer.setInvocationContext(mModuleContext);
+ EasyMock.replay(mMockDevice, mMockBuildInfo);
+ assertNotNull(mPreparer.getSuiteName());
+ EasyMock.verify(mMockDevice, mMockBuildInfo);
+ }
+
+ /**
+ * Test that when we look up resources locally, we search them from the build helper.
+ */
+ @Test
+ public void testLocalRead_fromDynamicConfigName() throws Exception {
+ OptionSetter setter = new OptionSetter(mPreparer);
+ setter.setOptionValue("config-filename", "config-test-name");
+ setter.setOptionValue("dynamic-config-name", "dynamic-config-test-name");
+ setter.setOptionValue("extract-from-resource", "false");
+
+ File check = new File("anyfilewilldo");
+ mMockBuildHelper = new CompatibilityBuildHelper(mMockBuildInfo) {
+ @Override
+ public File getTestFile(String filename) throws FileNotFoundException {
+ return check;
+ }
+ };
+
+ EasyMock.replay(mMockDevice, mMockBuildInfo);
+ File res = mPreparer.getLocalConfigFile(mMockBuildHelper, mMockDevice);
+ assertEquals(check, res);
+ EasyMock.verify(mMockDevice, mMockBuildInfo);
+ }
+
+ /**
* Test that when we look up resources locally, we search them from the build helper.
*/
@Test
@@ -197,10 +258,13 @@
Map<String, String> attributes = new HashMap<>();
attributes.put(CompatibilityBuildHelper.SUITE_VERSION, "v1");
EasyMock.expect(mMockBuildInfo.getBuildAttributes()).andStubReturn(attributes);
+ Collection<VersionedFile> versionedFiles = new LinkedList<VersionedFile>();
+ EasyMock.expect(mMockBuildInfo.getFiles()).andStubReturn(versionedFiles);
Capture<File> capture = new Capture<>();
mMockBuildInfo.setFile(EasyMock.contains("moduleName"), EasyMock.capture(capture),
EasyMock.eq("DYNAMIC_CONFIG_FILE:moduleName"));
+ mPreparer.setInvocationContext(mModuleContext);
EasyMock.replay(mMockDevice, mMockBuildInfo);
mPreparer.setUp(mMockDevice, mMockBuildInfo);
EasyMock.verify(mMockDevice, mMockBuildInfo);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparerTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparerTest.java
index 005ca43..3bfed47 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparerTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/MediaPreparerTest.java
@@ -16,6 +16,11 @@
package com.android.compatibility.common.tradefed.targetprep;
+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 com.android.ddmlib.IDevice;
import com.android.tradefed.build.BuildInfo;
import com.android.tradefed.build.IBuildInfo;
@@ -23,54 +28,64 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.targetprep.TargetSetupError;
-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;
-public class MediaPreparerTest extends TestCase {
+/** Unit tests for {@link MediaPreparer}. */
+@RunWith(JUnit4.class)
+public class MediaPreparerTest {
private MediaPreparer mMediaPreparer;
private IBuildInfo mMockBuildInfo;
private ITestDevice mMockDevice;
private OptionSetter mOptionSetter;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
mMediaPreparer = new MediaPreparer();
mMockDevice = EasyMock.createMock(ITestDevice.class);
mMockBuildInfo = new BuildInfo("0", "");
mOptionSetter = new OptionSetter(mMediaPreparer);
}
+ @Test
public void testSetMountPoint() throws Exception {
EasyMock.expect(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).andReturn(
"/sdcard").once();
EasyMock.replay(mMockDevice);
mMediaPreparer.setMountPoint(mMockDevice);
+ EasyMock.verify(mMockDevice);
assertEquals(mMediaPreparer.mBaseDeviceShortDir, "/sdcard/test/bbb_short/");
assertEquals(mMediaPreparer.mBaseDeviceFullDir, "/sdcard/test/bbb_full/");
}
+ @Test
public void testDefaultModuleDirMountPoint() throws Exception {
EasyMock.expect(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).andReturn(
"/sdcard").once();
EasyMock.replay(mMockDevice);
mMediaPreparer.setMountPoint(mMockDevice);
+ EasyMock.verify(mMockDevice);
assertEquals(mMediaPreparer.mBaseDeviceModuleDir, "/sdcard/test/android-cts-media/");
assertEquals(mMediaPreparer.getMediaDir().getName(), "android-cts-media");
}
+ @Test
public void testSetModuleDirMountPoint() throws Exception {
mOptionSetter.setOptionValue("media-folder-name", "unittest");
EasyMock.expect(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).andReturn(
"/sdcard").once();
EasyMock.replay(mMockDevice);
mMediaPreparer.setMountPoint(mMockDevice);
+ EasyMock.verify(mMockDevice);
assertEquals(mMediaPreparer.mBaseDeviceModuleDir, "/sdcard/test/unittest/");
assertEquals(mMediaPreparer.getMediaDir().getName(), "unittest");
}
+ @Test
public void testCopyMediaFiles() throws Exception {
mMediaPreparer.mMaxRes = MediaPreparer.DEFAULT_MAX_RESOLUTION;
mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
@@ -78,6 +93,10 @@
mMediaPreparer.mBaseDeviceImagesDir = "/sdcard/test/images";
mMediaPreparer.mBaseDeviceModuleDir = "/sdcard/test/android-cts-media/";
for (MediaPreparer.Resolution resolution : MediaPreparer.RESOLUTIONS) {
+ if (resolution.getWidth() > MediaPreparer.DEFAULT_MAX_RESOLUTION.getWidth()) {
+ // Stop when we reach the default max resolution
+ continue;
+ }
String shortFile = String.format("%s%s", mMediaPreparer.mBaseDeviceShortDir,
resolution.toString());
String fullFile = String.format("%s%s", mMediaPreparer.mBaseDeviceFullDir,
@@ -91,8 +110,10 @@
.andReturn(false).anyTimes();
EasyMock.replay(mMockDevice);
mMediaPreparer.copyMediaFiles(mMockDevice);
+ EasyMock.verify(mMockDevice);
}
+ @Test
public void testMediaFilesExistOnDeviceTrue() throws Exception {
mMediaPreparer.mMaxRes = MediaPreparer.DEFAULT_MAX_RESOLUTION;
mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
@@ -110,8 +131,10 @@
.andReturn(true).anyTimes();
EasyMock.replay(mMockDevice);
assertTrue(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
+ EasyMock.verify(mMockDevice);
}
+ @Test
public void testMediaFilesExistOnDeviceTrueWithPushAll() throws Exception {
mOptionSetter.setOptionValue("push-all", "true");
mMediaPreparer.mBaseDeviceModuleDir = "/sdcard/test/android-cts-media/";
@@ -119,8 +142,10 @@
.andReturn(true).anyTimes();
EasyMock.replay(mMockDevice);
assertTrue(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
+ EasyMock.verify(mMockDevice);
}
+ @Test
public void testMediaFilesExistOnDeviceFalse() throws Exception {
mMediaPreparer.mMaxRes = MediaPreparer.DEFAULT_MAX_RESOLUTION;
mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
@@ -128,14 +153,18 @@
EasyMock.expect(mMockDevice.doesFileExist(firstFileChecked)).andReturn(false).once();
EasyMock.replay(mMockDevice);
assertFalse(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
+ EasyMock.verify(mMockDevice);
}
+ @Test
public void testSkipMediaDownload() throws Exception {
mOptionSetter.setOptionValue("skip-media-download", "true");
- EasyMock.replay();
- mMediaPreparer.run(mMockDevice, mMockBuildInfo);
+ EasyMock.replay(mMockDevice);
+ mMediaPreparer.setUp(mMockDevice, mMockBuildInfo);
+ EasyMock.verify(mMockDevice);
}
+ @Test
public void testPushAll() throws Exception {
mOptionSetter.setOptionValue("push-all", "true");
mOptionSetter.setOptionValue("media-folder-name", "unittest");
@@ -153,18 +182,52 @@
.andReturn(false).anyTimes();
EasyMock.replay(mMockDevice);
mMediaPreparer.copyMediaFiles(mMockDevice);
+ EasyMock.verify(mMockDevice);
}
+ @Test
public void testWithBothPushAllAndImagesOnly() throws Exception {
mOptionSetter.setOptionValue("push-all", "true");
mOptionSetter.setOptionValue("images-only", "true");
+
+ EasyMock.expect(mMockDevice.getDeviceDescriptor()).andReturn(null);
+
EasyMock.replay(mMockDevice);
try {
- mMediaPreparer.run(mMockDevice, mMockBuildInfo);
+ mMediaPreparer.setUp(mMockDevice, mMockBuildInfo);
fail("TargetSetupError expected");
} catch (TargetSetupError e) {
// Expected
}
+ EasyMock.verify(mMockDevice);
}
+ /** Test that if we decide to run and files are on the device, we don't download again. */
+ @Test
+ public void testMediaDownloadOnly_existsOnDevice() throws Exception {
+ mOptionSetter.setOptionValue("local-media-path", "/fake/media/dir");
+ mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
+ mMediaPreparer.mBaseDeviceFullDir = "/sdcard/test/bbb_full/";
+
+ EasyMock.expect(mMockDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE))
+ .andReturn("/sdcard")
+ .once();
+ for (MediaPreparer.Resolution resolution : MediaPreparer.RESOLUTIONS) {
+ if (resolution.getWidth() > MediaPreparer.DEFAULT_MAX_RESOLUTION.getWidth()) {
+ // Stop when we reach the default max resolution
+ continue;
+ }
+ String shortFile =
+ String.format(
+ "%s%s", mMediaPreparer.mBaseDeviceShortDir, resolution.toString());
+ String fullFile =
+ String.format("%s%s", mMediaPreparer.mBaseDeviceFullDir, resolution.toString());
+ EasyMock.expect(mMockDevice.doesFileExist(shortFile)).andReturn(true).once();
+ EasyMock.expect(mMockDevice.doesFileExist(fullFile)).andReturn(true).once();
+ }
+ EasyMock.expect(mMockDevice.doesFileExist("/sdcard/test/images/")).andReturn(true).once();
+ EasyMock.replay(mMockDevice);
+ mMediaPreparer.setUp(mMockDevice, mMockBuildInfo);
+ EasyMock.verify(mMockDevice);
+ }
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java
index 617fde6..9b34646 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/PropertyCheckTest.java
@@ -42,7 +42,7 @@
super.setUp();
mPropertyCheck = new PropertyCheck();
mMockDevice = EasyMock.createMock(ITestDevice.class);
- mMockBuildInfo = new DeviceBuildInfo("0", "", "");
+ mMockBuildInfo = new DeviceBuildInfo("0", "");
mOptionSetter = new OptionSetter(mPropertyCheck);
EasyMock.expect(mMockDevice.getProperty(PROPERTY)).andReturn(ACTUAL_VALUE).anyTimes();
EasyMock.expect(mMockDevice.getDeviceDescriptor()).andReturn(null).anyTimes();
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java
index 7fbb39e..99f2601 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparerTest.java
@@ -46,7 +46,7 @@
mSettingsPreparer = new SettingsPreparer();
mMockDevice = EasyMock.createMock(ITestDevice.class);
EasyMock.expect(mMockDevice.getDeviceDescriptor()).andReturn(null).anyTimes();
- mMockBuildInfo = new BuildInfo("0", "", "");
+ mMockBuildInfo = new BuildInfo("0", "");
mOptionSetter = new OptionSetter(mSettingsPreparer);
mOptionSetter.setOptionValue("device-setting", "stay_on_while_plugged_in");
mOptionSetter.setOptionValue("setting-type", "global");
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/JarHostTestTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/JarHostTestTest.java
index 9c44b65..ec12810 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/JarHostTestTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/JarHostTestTest.java
@@ -19,10 +19,8 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.android.tradefed.build.BuildInfo;
import com.android.tradefed.build.DeviceBuildInfo;
import com.android.tradefed.config.OptionSetter;
-import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
import com.android.tradefed.result.ITestInvocationListener;
@@ -59,7 +57,6 @@
public class JarHostTestTest {
private static final String TEST_JAR1 = "/testtype/testJar1.jar";
- private static final String TEST_JAR2 = "/testtype/testJar2.jar";
private JarHostTest mTest;
private DeviceBuildInfo mStubBuildInfo;
private File mTestDir = null;
@@ -172,69 +169,6 @@
}
/**
- * Test that {@link JarHostTest#getTestShard(int, int)} can split classes coming from a jar.
- */
- @Test
- public void testGetTestShard_withJar() throws Exception {
- File testJar = getJarResource(TEST_JAR2, mTestDir);
- mTest = new JarHostTestLoader(mTestDir, testJar);
- mTest.setBuild(mStubBuildInfo);
- ITestDevice device = EasyMock.createNiceMock(ITestDevice.class);
- mTest.setDevice(device);
- OptionSetter setter = new OptionSetter(mTest);
- setter.setOptionValue("enable-pretty-logs", "false");
- setter.setOptionValue("jar", testJar.getName());
- // full class count without sharding
- assertEquals(238, mTest.countTestCases());
-
- // only one shard
- IRemoteTest oneShard = mTest.getTestShard(1, 0);
- assertTrue(oneShard instanceof JarHostTest);
- ((JarHostTest)oneShard).setBuild(new BuildInfo());
- ((JarHostTest)oneShard).setDevice(device);
- assertEquals(238, ((JarHostTest)oneShard).countTestCases());
-
- // 5 shards total the number of tests.
- int total = 0;
- IRemoteTest shard1 = mTest.getTestShard(5, 0);
- assertTrue(shard1 instanceof JarHostTest);
- ((JarHostTest)shard1).setBuild(new BuildInfo());
- ((JarHostTest)shard1).setDevice(device);
- assertEquals(58, ((JarHostTest)shard1).countTestCases());
- total += ((JarHostTest)shard1).countTestCases();
-
- IRemoteTest shard2 = mTest.getTestShard(5, 1);
- assertTrue(shard2 instanceof JarHostTest);
- ((JarHostTest)shard2).setBuild(new BuildInfo());
- ((JarHostTest)shard2).setDevice(device);
- assertEquals(60, ((JarHostTest)shard2).countTestCases());
- total += ((JarHostTest)shard2).countTestCases();
-
- IRemoteTest shard3 = mTest.getTestShard(5, 2);
- assertTrue(shard3 instanceof JarHostTest);
- ((JarHostTest)shard3).setBuild(new BuildInfo());
- ((JarHostTest)shard3).setDevice(device);
- assertEquals(60, ((JarHostTest)shard3).countTestCases());
- total += ((JarHostTest)shard3).countTestCases();
-
- IRemoteTest shard4 = mTest.getTestShard(5, 3);
- assertTrue(shard4 instanceof JarHostTest);
- ((JarHostTest)shard4).setBuild(new BuildInfo());
- ((JarHostTest)shard4).setDevice(device);
- assertEquals(30, ((JarHostTest)shard4).countTestCases());
- total += ((JarHostTest)shard4).countTestCases();
-
- IRemoteTest shard5 = mTest.getTestShard(5, 4);
- assertTrue(shard5 instanceof JarHostTest);
- ((JarHostTest)shard5).setBuild(new BuildInfo());
- ((JarHostTest)shard5).setDevice(device);
- assertEquals(30, ((JarHostTest)shard5).countTestCases());
- total += ((JarHostTest)shard5).countTestCases();
-
- assertEquals(238, total);
- }
-
- /**
* Testable version of {@link JarHostTest} that allows adding jar to classpath for testing
* purpose.
*/
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
index 4a8e741..d3cbaa2 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
@@ -36,6 +36,7 @@
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -88,6 +89,16 @@
}
@Override
+ public void clearIncludeFilters() {
+ mIncludeFilters.clear();
+ }
+
+ @Override
+ public Set<String> getIncludeFilters() {
+ return new HashSet<>(mIncludeFilters);
+ }
+
+ @Override
public void addExcludeFilter(String filter) {
mExcludeFilters.add(filter);
}
@@ -98,6 +109,16 @@
}
@Override
+ public void clearExcludeFilters() {
+ mExcludeFilters.clear();
+ }
+
+ @Override
+ public Set<String> getExcludeFilters() {
+ return new HashSet<>(mExcludeFilters);
+ }
+
+ @Override
public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
// Do nothing
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
index be246ae..eddda50 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
@@ -31,7 +31,6 @@
import com.android.tradefed.testtype.IAbiReceiver;
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IRuntimeHintProvider;
-import com.android.tradefed.testtype.IStrictShardableTest;
import com.android.tradefed.testtype.ITestCollector;
import com.android.tradefed.testtype.ITestFilterReceiver;
import com.android.tradefed.util.AbiUtils;
@@ -395,31 +394,6 @@
assertEquals("Incorrect module arg", "foobar", stub.mBlah);
}
- public void testSplit() throws Exception {
- createConfig(mTestsDir, "sharded_1", null, SHARDABLE_TEST_STUB);
- createConfig(mTestsDir, "sharded_2", null, SHARDABLE_TEST_STUB);
- createConfig(mTestsDir, "sharded_3", null, SHARDABLE_TEST_STUB);
- Set<IAbi> abis = new HashSet<>();
- abis.add(new Abi(ABI_64, "64"));
- ArrayList<String> emptyList = new ArrayList<>();
-
- mRepo.initialize(3, 0, mTestsDir, abis, DEVICE_TOKENS, emptyList, emptyList, INCLUDES,
- EXCLUDES, METADATA_INCLUDES, METADATA_EXCLUDES, mMockBuildInfo);
-
- List<IModuleDef> modules = new ArrayList<>();
- modules.addAll(mRepo.getNonTokenModules());
- modules.addAll(mRepo.getTokenModules());
-
- int shardableCount = 0;
- for (IModuleDef def : modules) {
- IRemoteTest test = def.getTest();
- if (test instanceof IStrictShardableTest) {
- shardableCount++;
- }
- }
- assertEquals("Shards wrong", 9, shardableCount);
- }
-
public void testGetModuleIds() {
mRepo.initialize(3, null, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
EXCLUDES, METADATA_INCLUDES, METADATA_EXCLUDES, mMockBuildInfo);
@@ -459,6 +433,18 @@
public void setAbi(IAbi arg0) {}
@Override
public IAbi getAbi() {return null;}
+ @Override
+ public Set<String> getIncludeFilters() {
+ return null;
+ }
+ @Override
+ public Set<String> getExcludeFilters() {
+ return null;
+ }
+ @Override
+ public void clearIncludeFilters() {}
+ @Override
+ public void clearExcludeFilters() {}
}
/**
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
index 7b43972..293d0d2 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
@@ -25,7 +25,6 @@
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IRuntimeHintProvider;
import com.android.tradefed.testtype.IShardableTest;
-import com.android.tradefed.testtype.IStrictShardableTest;
import com.android.tradefed.testtype.ITestCollector;
import com.android.tradefed.testtype.ITestFilterReceiver;
@@ -34,8 +33,7 @@
import java.util.Set;
public class ShardableTestStub implements IRemoteTest, IShardableTest, IBuildReceiver,
- IAbiReceiver, IRuntimeHintProvider, ITestCollector, ITestFilterReceiver,
- IStrictShardableTest {
+ IAbiReceiver, IRuntimeHintProvider, ITestCollector, ITestFilterReceiver {
@Option(name = "module")
String mModule;
@@ -76,14 +74,6 @@
return mShards;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public IRemoteTest getTestShard(int shardCount, int shardIndex) {
- return new ShardableTestStub();
- }
-
@Override
public void setAbi(IAbi abi) {
// Do nothing
@@ -123,4 +113,20 @@
public void addAllExcludeFilters(Set<String> filters) {
}
+
+ @Override
+ public Set<String> getIncludeFilters() {
+ return null;
+ }
+
+ @Override
+ public Set<String> getExcludeFilters() {
+ return null;
+ }
+
+ @Override
+ public void clearIncludeFilters() {}
+
+ @Override
+ public void clearExcludeFilters() {}
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SimpleTestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SimpleTestStub.java
index 7a62c8f..effea21 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SimpleTestStub.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SimpleTestStub.java
@@ -93,4 +93,20 @@
public void addAllExcludeFilters(Set<String> filters) {
}
+
+ @Override
+ public Set<String> getIncludeFilters() {
+ return null;
+ }
+
+ @Override
+ public Set<String> getExcludeFilters() {
+ return null;
+ }
+
+ @Override
+ public void clearIncludeFilters() {}
+
+ @Override
+ public void clearExcludeFilters() {}
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
index 0ba3a4c..f04a1be 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
@@ -166,4 +166,20 @@
public void addAllExcludeFilters(Set<String> filters) {
}
+
+ @Override
+ public Set<String> getIncludeFilters() {
+ return null;
+ }
+
+ @Override
+ public Set<String> getExcludeFilters() {
+ return null;
+ }
+
+ @Override
+ public void clearIncludeFilters() {}
+
+ @Override
+ public void clearExcludeFilters() {}
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStubShardable.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStubShardable.java
deleted file mode 100644
index d3d7b41..0000000
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStubShardable.java
+++ /dev/null
@@ -1,45 +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.
- */
-package com.android.compatibility.common.tradefed.testtype;
-
-import com.android.tradefed.config.OptionCopier;
-import com.android.tradefed.result.TestDescription;
-import com.android.tradefed.testtype.IRemoteTest;
-import com.android.tradefed.testtype.IStrictShardableTest;
-
-import java.util.ArrayList;
-
-/**
- * A test Stub that can be used to fake some runs.
- */
-public class TestStubShardable extends TestStub implements IStrictShardableTest {
-
- @Override
- public IRemoteTest getTestShard(int shardCount, int shardIndex) {
- TestStubShardable test = new TestStubShardable();
- OptionCopier.copyOptionsNoThrow(this, test);
- test.mShardedTestToRun = new ArrayList<>();
- TestDescription tid = new TestDescription("TestStub", "test" + shardIndex);
- test.mShardedTestToRun.add(tid);
- if (mIsComplete == false) {
- TestDescription tid2 = new TestDescription("TestStub", "test" + shardIndex + 100);
- test.mShardedTestToRun.add(tid2);
- test.mIsComplete = false;
- }
- test.mShardIndex = shardIndex;
- return test;
- }
-}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTestTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTestTest.java
index 39e24bd..3c3e264 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTestTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/retry/RetryFactoryTestTest.java
@@ -187,9 +187,10 @@
mFactory.setInvocationContext(mMockContext);
mMockListener.testModuleStarted(EasyMock.anyObject());
- mMockListener.testRunStarted("module1", 0);
- mMockListener.testRunEnded(EasyMock.anyLong(),
- (HashMap<String, Metric>) EasyMock.anyObject());
+ mMockListener.testRunStarted(
+ EasyMock.eq("module1"), EasyMock.eq(0), EasyMock.eq(0), EasyMock.anyLong());
+ mMockListener.testRunEnded(
+ EasyMock.anyLong(), EasyMock.<HashMap<String, Metric>>anyObject());
mMockListener.testModuleEnded();
EasyMock.replay(mMockListener, mMockInfo, mMockDevice);
diff --git a/common/host-side/util/.classpath b/common/host-side/util/.classpath
index 28bdded..3cf19b6 100644
--- a/common/host-side/util/.classpath
+++ b/common/host-side/util/.classpath
@@ -10,8 +10,8 @@
<classpathentry combineaccessrules="false" kind="src" path="/tradefederation"/>
<classpathentry kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/json-prebuilt_intermediates/javalib.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/cts-common-util"/>
- <classpathentry kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/jsonlib_intermediates/classes.jar"/>
- <classpathentry kind="var" path="TRADEFED_ROOT/external/mockito/lib/byte-buddy-1.7.9.jar"/>
- <classpathentry kind="var" path="TRADEFED_ROOT/external/mockito/lib/byte-buddy-agent-1.7.9.jar"/>
+ <classpathentry kind="var" path="TRADEFED_ROOT/out/soong/.intermediates/external/mockito/mockito-byte-buddy-agent/linux_glibc_common/combined/mockito-byte-buddy-agent.jar"/>
+ <classpathentry kind="var" path="TRADEFED_ROOT/out/soong/.intermediates/external/mockito/mockito-byte-buddy/linux_glibc_common/combined/mockito-byte-buddy.jar"/>
+ <classpathentry kind="var" path="TRADEFED_ROOT/out/soong/.intermediates/cts/libs/json/json/linux_glibc_common/javac/json.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/common/host-side/util/Android.bp b/common/host-side/util/Android.bp
new file mode 100644
index 0000000..ae7db70
--- /dev/null
+++ b/common/host-side/util/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2015 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.
+
+java_library_host {
+ name: "compatibility-host-util",
+ defaults: ["cts_error_prone_rules"],
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "compatibility-common-util-hostsidelib",
+ "json",
+ ],
+
+ libs: [
+ "json-prebuilt",
+ "tradefed",
+ ],
+}
diff --git a/common/host-side/util/Android.mk b/common/host-side/util/Android.mk
deleted file mode 100644
index 77a5b5d..0000000
--- a/common/host-side/util/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-hostsidelib jsonlib
-
-LOCAL_COMPATIBILITY_SUITE := general-tests
-
-LOCAL_JAVA_LIBRARIES := json-prebuilt tradefed
-
-LOCAL_MODULE := compatibility-host-util
-
-LOCAL_MODULE_TAGS := optional
-include cts/error_prone_rules.mk
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/BackupHostSideUtils.java b/common/host-side/util/src/com/android/compatibility/common/util/BackupHostSideUtils.java
new file mode 100644
index 0000000..37679c4
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/BackupHostSideUtils.java
@@ -0,0 +1,43 @@
+/*
+ * 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.compatibility.common.util;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.INativeDevice;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+/** Host-side specific utilities for backup and restore tests. */
+public class BackupHostSideUtils {
+ /** Create a new {@link BackupUtils} instance. */
+ public static BackupUtils createBackupUtils(INativeDevice device) {
+ return new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ try {
+ String result = device.executeShellCommand(command);
+ return new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8));
+ } catch (DeviceNotAvailableException e) {
+ throw new IOException(e);
+ }
+ }
+ };
+ }
+}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/CpuFeatures.java b/common/host-side/util/src/com/android/compatibility/common/util/CpuFeatures.java
index 123a320..896381a 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/CpuFeatures.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/CpuFeatures.java
@@ -69,6 +69,6 @@
int deviceMajor = Integer.parseInt(kernelVersion[0]);
int deviceMinor = Integer.parseInt(kernelVersion[1]);
- return (major < deviceMajor) || ((major == deviceMajor) && (minor < deviceMinor));
+ return (major > deviceMajor) || ((major == deviceMajor) && (minor > deviceMinor));
}
}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/DeviceInfo.java b/common/host-side/util/src/com/android/compatibility/common/util/DeviceInfo.java
index da040cb..79008ee 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/DeviceInfo.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/DeviceInfo.java
@@ -17,7 +17,6 @@
import static org.junit.Assert.fail;
-import com.android.compatibility.common.util.HostInfoStore;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.FileInputStreamSource;
import com.android.tradefed.result.LogDataType;
@@ -55,9 +54,8 @@
FileInputStreamSource source = null;
try {
jsonFile = FileUtil.createTempFile(getClass().getSimpleName(), FILE_SUFFIX);
- try (HostInfoStore store = new HostInfoStore(jsonFile)) {
- store.open();
- collectDeviceInfo(store);
+ try {
+ collectDeviceInfo(jsonFile);
} finally {
// If file is empty throw exception so it is not copied to the results.
if (jsonFile != null && jsonFile.exists() &&
@@ -81,4 +79,15 @@
* Method to collect device information.
*/
protected abstract void collectDeviceInfo(HostInfoStore store) throws Exception;
+
+ /**
+ * Method to collect device information; this method should write JSON to the specified file
+ * directly.
+ */
+ protected void collectDeviceInfo(File jsonFile) throws Exception {
+ try (HostInfoStore store = new HostInfoStore(jsonFile)) {
+ store.open();
+ collectDeviceInfo(store);
+ }
+ }
}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/HostSideTestUtils.java b/common/host-side/util/src/com/android/compatibility/common/util/HostSideTestUtils.java
new file mode 100644
index 0000000..248768b
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/HostSideTestUtils.java
@@ -0,0 +1,42 @@
+/*
+ * 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.compatibility.common.util;
+
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.util.RunUtil;
+
+/** Utility class for host-side tests. */
+public class HostSideTestUtils {
+ @FunctionalInterface
+ public interface BooleanSupplierWithThrow<E extends Throwable> {
+ boolean getAsBoolean() throws E;
+ }
+
+ /** Wait until {@code predicate} is satisfied, or fail, with a given timeout. */
+ public static <E extends Throwable> void waitUntil(
+ String message, long timeoutSeconds, BooleanSupplierWithThrow<E> predicate) throws E {
+ int sleep = 125;
+ final long timeout = System.currentTimeMillis() + timeoutSeconds * 1000;
+ while (System.currentTimeMillis() < timeout) {
+ if (predicate.getAsBoolean()) {
+ return;
+ }
+ RunUtil.getDefault().sleep(sleep);
+ }
+ fail(message);
+ }
+}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/MonitoringUtils.java b/common/host-side/util/src/com/android/compatibility/common/util/MonitoringUtils.java
index ac16ac0..0c49ee6 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/MonitoringUtils.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/MonitoringUtils.java
@@ -21,8 +21,6 @@
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.result.InputStreamSource;
-import com.android.tradefed.result.LogDataType;
import com.android.tradefed.util.RunUtil;
/**
@@ -38,11 +36,13 @@
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < CONNECTIVITY_CHECK_TIME_MS) {
if (device.checkConnectivity()) {
- CLog.i("Connectivity: passed check.");
+ CLog.i("Wifi Connectivity: passed check.");
return true;
} else {
- CLog.logAndDisplay(LogLevel.INFO,
- "Connectivity check failed on %s, retrying in %dms",
+ CLog.logAndDisplay(
+ LogLevel.INFO,
+ "Wifi Connectivity check failed on %s. (Is your device connected to Wifi?)"
+ + ", retrying in %dms",
device.getSerialNumber(),
CONNECTIVITY_CHECK_INTERVAL_MS);
RunUtil.getDefault().sleep(CONNECTIVITY_CHECK_INTERVAL_MS);
@@ -54,11 +54,8 @@
public static void checkDeviceConnectivity(ITestDevice device, ITestInvocationListener listener,
String tag) throws DeviceNotAvailableException {
if (!checkDeviceConnectivity(device)) {
- CLog.w("Connectivity: check failed.");
- InputStreamSource bugSource = device.getBugreport();
- listener.testLog(String.format("bugreport-connectivity-%s", tag),
- LogDataType.TEXT, bugSource);
- bugSource.cancel();
+ CLog.w("Wifi Connectivity: check failed. (Is your device connected to Wifi?)");
+ device.logBugreport(String.format("bugreport-connectivity-%s", tag), listener);
}
}
}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/PropertyUtil.java b/common/host-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
index ab6dac8..b354f66 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -38,6 +38,10 @@
private static final String BUILD_TYPE_PROPERTY = "ro.build.type";
private static final String MANUFACTURER_PROPERTY = "ro.product.manufacturer";
private static final String TAG_DEV_KEYS = "dev-keys";
+ private static final String VNDK_VERSION = "ro.vndk.version";
+
+ /** Value to be returned by getPropertyInt() if property is not found */
+ public static final int INT_VALUE_IF_UNSET = -1;
public static final String GOOGLE_SETTINGS_QUERY =
"content query --uri content://com.google.settings/partner";
@@ -69,6 +73,20 @@
}
/**
+ * Return whether the SDK version of the vendor partiton is newer than the given API level.
+ * If the property is set to non-integer value, this means the vendor partition is using
+ * current API level and true is returned.
+ */
+ public static boolean isVendorApiLevelNewerThan(ITestDevice device, int apiLevel)
+ throws DeviceNotAvailableException {
+ int vendorApiLevel = getPropertyInt(device, VNDK_VERSION);
+ if (vendorApiLevel == INT_VALUE_IF_UNSET) {
+ return true;
+ }
+ return vendorApiLevel > apiLevel;
+ }
+
+ /**
* Return the manufacturer of this product. If unset, return null.
*/
public static String getManufacturer(ITestDevice device) throws DeviceNotAvailableException {
@@ -123,4 +141,20 @@
String value = device.getProperty(property);
return (value == null) ? false : value.matches(regex);
}
+
+ /**
+ * Retrieves the desired integer property, returning INT_VALUE_IF_UNSET if not found.
+ */
+ public static int getPropertyInt(ITestDevice device, String property)
+ throws DeviceNotAvailableException {
+ String value = device.getProperty(property);
+ if (value == null) {
+ return INT_VALUE_IF_UNSET;
+ }
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return INT_VALUE_IF_UNSET;
+ }
+ }
}
diff --git a/common/host-side/util/tests/Android.bp b/common/host-side/util/tests/Android.bp
new file mode 100644
index 0000000..ad9725b
--- /dev/null
+++ b/common/host-side/util/tests/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2015 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.
+
+java_test_host {
+ name: "compatibility-host-util-tests",
+ defaults: ["cts_error_prone_rules"],
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "objenesis-host",
+ "mockito-host",
+ ],
+
+ libs: [
+ "compatibility-host-util",
+ "easymock",
+ "junit",
+ "json-prebuilt",
+ "tradefed",
+ ],
+}
diff --git a/common/host-side/util/tests/Android.mk b/common/host-side/util/tests/Android.mk
deleted file mode 100644
index 6074164..0000000
--- a/common/host-side/util/tests/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := objenesis-host mockito-host
-LOCAL_JAVA_LIBRARIES := \
- compatibility-host-util \
- easymock \
- junit-host \
- json-prebuilt \
- tradefed
-
-LOCAL_MODULE := compatibility-host-util-tests
-
-LOCAL_MODULE_TAGS := optional
-include cts/error_prone_rules.mk
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/util/tests/run_tests.sh b/common/host-side/util/tests/run_tests.sh
deleted file mode 100755
index 183cd73..0000000
--- a/common/host-side/util/tests/run_tests.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2015 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.
-
-# Helper script for running unit tests for compatibility libraries
-
-HARNESS_DIR=$(dirname ${0})/../../../..
-source ${HARNESS_DIR}/test_defs.sh
-
-JARS="
- compatibility-common-util-hostsidelib\
- compatibility-common-util-tests\
- compatibility-host-util\
- compatibility-host-util-tests\
- compatibility-mock-tradefed\
- compatibility-tradefed-tests"
-
-run_tests "com.android.compatibility.common.util.HostUnitTests" "${JARS}" "${@}"
-
diff --git a/common/util/.classpath b/common/util/.classpath
index 599ee5d..806795a 100644
--- a/common/util/.classpath
+++ b/common/util/.classpath
@@ -5,8 +5,8 @@
<classpathentry kind="src" path="tests/src"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/json-prebuilt_intermediates/javalib.jar"/>
- <classpathentry kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/guavalib_intermediates/classes.jar"/>
- <classpathentry kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/kxml2-2.3.0_intermediates/javalib.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/tradefederation"/>
+ <classpathentry kind="var" path="TRADEFED_ROOT/prebuilts/misc/common/kxml2/kxml2-2.3.0.jar"/>
+ <classpathentry kind="var" path="TRADEFED_ROOT/out/soong/.intermediates/external/guava/guava/linux_glibc_common/combined/guava.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/common/util/Android.bp b/common/util/Android.bp
new file mode 100644
index 0000000..bc46cdb
--- /dev/null
+++ b/common/util/Android.bp
@@ -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.
+
+// Build the common utility library for use device-side
+java_library_static {
+ name: "compatibility-common-util-devicesidelib",
+ sdk_version: "current",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "guava",
+ "junit",
+ ],
+}
+
+// Build the common utility library for use host-side
+java_library_host {
+ name: "compatibility-common-util-hostsidelib",
+ defaults: ["cts_error_prone_rules"],
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "junit",
+ "guava",
+ "json-prebuilt",
+ "platform-test-annotations",
+ "kxml2-2.3.0",
+ ],
+}
diff --git a/common/util/Android.mk b/common/util/Android.mk
deleted file mode 100644
index d5c5f5a..0000000
--- a/common/util/Android.mk
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright (C) 2014 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.
-
-###############################################################################
-# Build the common utility library for use device-side
-###############################################################################
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := compatibility-common-util-devicesidelib
-
-LOCAL_STATIC_JAVA_LIBRARIES := guava junit
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-###############################################################################
-# Build the common utility library for use host-side
-###############################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := compatibility-common-util-hostsidelib
-
-LOCAL_STATIC_JAVA_LIBRARIES := guavalib \
- json-prebuilt \
- junit-host \
- kxml2-2.3.0 \
- platform-test-annotations-host
-include cts/error_prone_rules.mk
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/common/util/src/com/android/compatibility/common/util/BackupUtils.java b/common/util/src/com/android/compatibility/common/util/BackupUtils.java
new file mode 100644
index 0000000..66084da
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/BackupUtils.java
@@ -0,0 +1,422 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Scanner;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Utility class for backup and restore.
+ */
+public abstract class BackupUtils {
+ private static final String LOCAL_TRANSPORT_NAME =
+ "com.android.localtransport/.LocalTransport";
+ private static final String LOCAL_TRANSPORT_NAME_PRE_Q =
+ "android/com.android.internal.backup.LocalTransport";
+ private static final String LOCAL_TRANSPORT_PACKAGE = "com.android.localtransport";
+ public static final String LOCAL_TRANSPORT_TOKEN = "1";
+
+ private static final int BACKUP_PROVISIONING_TIMEOUT_SECONDS = 30;
+ private static final int BACKUP_PROVISIONING_POLL_INTERVAL_SECONDS = 1;
+ private static final int BACKUP_SERVICE_INIT_TIMEOUT_SECS = 30;
+
+ private static final Pattern BACKUP_MANAGER_CURRENTLY_ENABLE_STATUS_PATTERN =
+ Pattern.compile("^Backup Manager currently (enabled|disabled)$");
+ private static final String MATCH_LINE_BACKUP_MANAGER_IS_NOT_PENDING_INIT =
+ "(?s)" + "^Backup Manager is .* not pending init.*"; // DOTALL
+
+ private static final String BACKUP_DUMPSYS_CURRENT_TOKEN_FIELD = "Current:";
+
+ /**
+ * Kicks off adb shell {@param command} and return an {@link InputStream} with the command
+ * output stream.
+ */
+ protected abstract InputStream executeShellCommand(String command) throws IOException;
+
+ public void executeShellCommandSync(String command) throws IOException {
+ StreamUtil.drainAndClose(new InputStreamReader(executeShellCommand(command)));
+ }
+
+ public String getShellCommandOutput(String command) throws IOException {
+ return StreamUtil.readInputStream(executeShellCommand(command));
+ }
+
+ /** Executes shell command "bmgr backupnow <package>" and assert success. */
+ public void backupNowAndAssertSuccess(String packageName) throws IOException {
+ assertBackupIsSuccessful(packageName, backupNow(packageName));
+ }
+
+ /** Executes "bmgr --user <id> backupnow <package>" and assert success. */
+ public void backupNowAndAssertSuccessForUser(String packageName, int userId)
+ throws IOException {
+ assertBackupIsSuccessful(packageName, backupNowForUser(packageName, userId));
+ }
+
+ public void backupNowAndAssertBackupNotAllowed(String packageName) throws IOException {
+ assertBackupNotAllowed(packageName, getBackupNowOutput(packageName));
+ }
+
+ /** Executes shell command "bmgr backupnow <package>" and waits for completion. */
+ public void backupNowSync(String packageName) throws IOException {
+ StreamUtil.drainAndClose(new InputStreamReader(backupNow(packageName)));
+ }
+
+ public String getBackupNowOutput(String packageName) throws IOException {
+ return StreamUtil.readInputStream(backupNow(packageName));
+ }
+
+ /** Executes shell command "bmgr restore <token> <package>" and assert success. */
+ public void restoreAndAssertSuccess(String token, String packageName) throws IOException {
+ assertRestoreIsSuccessful(restore(token, packageName));
+ }
+
+ /** Executes shell command "bmgr --user <id> restore <token> <package>" and assert success. */
+ public void restoreAndAssertSuccessForUser(String token, String packageName, int userId)
+ throws IOException {
+ assertRestoreIsSuccessful(restoreForUser(token, packageName, userId));
+ }
+
+ public void restoreSync(String token, String packageName) throws IOException {
+ StreamUtil.drainAndClose(new InputStreamReader(restore(token, packageName)));
+ }
+
+ public String getRestoreOutput(String token, String packageName) throws IOException {
+ return StreamUtil.readInputStream(restore(token, packageName));
+ }
+
+ public boolean isLocalTransportSelected() throws IOException {
+ return getShellCommandOutput("bmgr list transports")
+ .contains("* " + getLocalTransportName());
+ }
+
+ /**
+ * Executes shell command "bmgr --user <id> list transports" to check the currently selected
+ * transport and returns {@code true} if the local transport is the selected one.
+ */
+ public boolean isLocalTransportSelectedForUser(int userId) throws IOException {
+ return getShellCommandOutput(String.format("bmgr --user %d list transports", userId))
+ .contains("* " + getLocalTransportName());
+ }
+
+ public boolean isBackupEnabled() throws IOException {
+ return getShellCommandOutput("bmgr enabled").contains("currently enabled");
+ }
+
+ /**
+ * Executes shell command "bmgr --user <id> enabled" and returns if backup is enabled for the
+ * user {@code userId}.
+ */
+ public boolean isBackupEnabledForUser(int userId) throws IOException {
+ return getShellCommandOutput(String.format("bmgr --user %d enabled", userId))
+ .contains("currently enabled");
+ }
+
+ public void wakeAndUnlockDevice() throws IOException {
+ executeShellCommandSync("input keyevent KEYCODE_WAKEUP");
+ executeShellCommandSync("wm dismiss-keyguard");
+ }
+
+ /**
+ * Returns {@link #LOCAL_TRANSPORT_NAME} if it's available on the device, or
+ * {@link #LOCAL_TRANSPORT_NAME_PRE_Q} otherwise.
+ */
+ public String getLocalTransportName() throws IOException {
+ return getShellCommandOutput("pm list packages").contains(LOCAL_TRANSPORT_PACKAGE)
+ ? LOCAL_TRANSPORT_NAME : LOCAL_TRANSPORT_NAME_PRE_Q;
+ }
+
+ /** Executes "bmgr backupnow <package>" and returns an {@link InputStream} for its output. */
+ private InputStream backupNow(String packageName) throws IOException {
+ return executeShellCommand("bmgr backupnow " + packageName);
+ }
+
+ /**
+ * Executes "bmgr --user <id> backupnow <package>" and returns an {@link InputStream} for its
+ * output.
+ */
+ private InputStream backupNowForUser(String packageName, int userId) throws IOException {
+ return executeShellCommand(
+ String.format("bmgr --user %d backupnow %s", userId, packageName));
+ }
+
+ /**
+ * Parses the output of "bmgr backupnow" command and checks that {@code packageName} wasn't
+ * allowed to backup.
+ *
+ * Expected format: "Package <packageName> with result: Backup is not allowed"
+ *
+ * TODO: Read input stream instead of string.
+ */
+ private void assertBackupNotAllowed(String packageName, String backupNowOutput) {
+ Scanner in = new Scanner(backupNowOutput);
+ boolean found = false;
+ while (in.hasNextLine()) {
+ String line = in.nextLine();
+
+ if (line.contains(packageName)) {
+ String result = line.split(":")[1].trim();
+ if ("Backup is not allowed".equals(result)) {
+ found = true;
+ }
+ }
+ }
+ in.close();
+ assertTrue("Didn't find \'Backup not allowed\' in the output", found);
+ }
+
+ /**
+ * Parses the output of "bmgr backupnow" command checking that the package {@code packageName}
+ * was backed up successfully. Closes the input stream.
+ *
+ * Expected format: "Package <package> with result: Success"
+ */
+ private void assertBackupIsSuccessful(String packageName, InputStream backupNowOutput)
+ throws IOException {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(backupNowOutput, StandardCharsets.UTF_8));
+ try {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (line.contains(packageName)) {
+ String result = line.split(":")[1].trim().toLowerCase();
+ if ("success".equals(result)) {
+ return;
+ }
+ }
+ }
+ fail("Couldn't find package in output or backup wasn't successful");
+ } finally {
+ StreamUtil.drainAndClose(reader);
+ }
+ }
+
+ /**
+ * Executes "bmgr restore <token> <packageName>" and returns an {@link InputStream} for its
+ * output.
+ */
+ private InputStream restore(String token, String packageName) throws IOException {
+ return executeShellCommand(String.format("bmgr restore %s %s", token, packageName));
+ }
+
+ /**
+ * Executes "bmgr --user <id> restore <token> <packageName>" and returns an {@link InputStream}
+ * for its output.
+ */
+ private InputStream restoreForUser(String token, String packageName, int userId)
+ throws IOException {
+ return executeShellCommand(
+ String.format("bmgr --user %d restore %s %s", userId, token, packageName));
+ }
+
+ /**
+ * Parses the output of "bmgr restore" command and checks that the package under test
+ * was restored successfully. Closes the input stream.
+ *
+ * Expected format: "restoreFinished: 0"
+ */
+ private void assertRestoreIsSuccessful(InputStream restoreOutput) throws IOException {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(restoreOutput, StandardCharsets.UTF_8));
+ try {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (line.contains("restoreFinished: 0")) {
+ return;
+ }
+ }
+ fail("Restore not successful");
+ } finally {
+ StreamUtil.drainAndClose(reader);
+ }
+ }
+
+ /** Executes "dumpsys backup" and returns an {@link InputStream} for its output. */
+ private InputStream dumpsysBackup() throws IOException {
+ return executeShellCommand("dumpsys backup");
+ }
+
+ /**
+ * Parses the output of "dumpsys backup" command to get token. Closes the input stream finally.
+ *
+ * Expected format: "Current: token"
+ */
+ private String getCurrentTokenOrFail(InputStream dumpsysOutput) throws IOException {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(dumpsysOutput, StandardCharsets.UTF_8));
+ try {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (line.contains(BACKUP_DUMPSYS_CURRENT_TOKEN_FIELD)) {
+ return line.split(BACKUP_DUMPSYS_CURRENT_TOKEN_FIELD)[1].trim();
+ }
+ }
+ throw new AssertionError("Couldn't find token in output");
+ } finally {
+ StreamUtil.drainAndClose(reader);
+ }
+ }
+
+ /**
+ * Execute shell command and return output from this command.
+ */
+ public String executeShellCommandAndReturnOutput(String command) throws IOException {
+ InputStream in = executeShellCommand(command);
+ BufferedReader br = new BufferedReader(
+ new InputStreamReader(in, StandardCharsets.UTF_8));
+ String str;
+ StringBuilder out = new StringBuilder();
+ while ((str = br.readLine()) != null) {
+ out.append(str).append("\n");
+ }
+ return out.toString();
+ }
+
+ // Copied over from BackupQuotaTest
+ public boolean enableBackup(boolean enable) throws Exception {
+ boolean previouslyEnabled;
+ String output = getLineString(executeShellCommand("bmgr enabled"));
+ Matcher matcher = BACKUP_MANAGER_CURRENTLY_ENABLE_STATUS_PATTERN.matcher(output.trim());
+ if (matcher.find()) {
+ previouslyEnabled = "enabled".equals(matcher.group(1));
+ } else {
+ throw new RuntimeException("non-parsable output setting bmgr enabled: " + output);
+ }
+
+ executeShellCommand("bmgr enable " + enable);
+ return previouslyEnabled;
+ }
+
+ /**
+ * Execute shell command "bmgr --user <id> enable <enable> and return previous enabled state.
+ */
+ public boolean enableBackupForUser(boolean enable, int userId) throws IOException {
+ boolean previouslyEnabled = isBackupEnabledForUser(userId);
+ executeShellCommand(String.format("bmgr --user %d enable %b", userId, enable));
+ return previouslyEnabled;
+ }
+
+ /** Execute shell command "bmgr --user <id> activate <activate>." */
+ public void activateBackupForUser(boolean activate, int userId) throws IOException {
+ executeShellCommandSync(String.format("bmgr --user %d activate %b", userId, activate));
+ }
+
+ /**
+ * Executes shell command "bmgr --user <id> activated" and returns if backup is activated for
+ * the user {@code userId}.
+ */
+ public boolean isBackupActivatedForUser(int userId) throws IOException {
+ return getShellCommandOutput(String.format("bmgr --user %d activated", userId))
+ .contains("currently activated");
+ }
+
+ private String getLineString(InputStream inputStream) throws IOException {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+ String str;
+ try {
+ str = reader.readLine();
+ } finally {
+ StreamUtil.drainAndClose(reader);
+ }
+ return str;
+ }
+
+ public void waitForBackupInitialization() throws IOException {
+ long tryUntilNanos = System.nanoTime()
+ + TimeUnit.SECONDS.toNanos(BACKUP_PROVISIONING_TIMEOUT_SECONDS);
+ while (System.nanoTime() < tryUntilNanos) {
+ String output = getLineString(executeShellCommand("dumpsys backup"));
+ if (output.matches(MATCH_LINE_BACKUP_MANAGER_IS_NOT_PENDING_INIT)) {
+ return;
+ }
+ try {
+ Thread.sleep(TimeUnit.SECONDS.toMillis(BACKUP_PROVISIONING_POLL_INTERVAL_SECONDS));
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+ }
+ throw new IOException("Timed out waiting for backup initialization");
+ }
+
+ public void waitUntilBackupServiceIsRunning(int userId)
+ throws IOException, InterruptedException {
+ waitUntilBackupServiceIsRunning(userId, BACKUP_SERVICE_INIT_TIMEOUT_SECS);
+ }
+
+ @VisibleForTesting
+ void waitUntilBackupServiceIsRunning(int userId, int timeout)
+ throws IOException, InterruptedException {
+ CommonTestUtils.waitUntil(
+ "Backup Manager init timed out",
+ timeout,
+ () -> {
+ String output = getLineString(executeShellCommand("dumpsys backup users"));
+ return output.matches(
+ "Backup Manager is running for users:.* " + userId + "( .*)?");
+ });
+ }
+
+ /**
+ * Executes shell command "bmgr --user <id> list transports" and returns {@code true} if the
+ * user has the {@code transport} available.
+ */
+ public boolean userHasBackupTransport(String transport, int userId) throws IOException {
+ String output =
+ getLineString(
+ executeShellCommand(
+ String.format("bmgr --user %d list transports", userId)));
+ for (String t : output.split("\n")) {
+ // Parse out the '*' character used to denote the selected transport.
+ t = t.replace("*", "").trim();
+ if (transport.equals(t)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Executes shell command "bmgr --user <id> transport <transport>" and returns the old
+ * transport.
+ */
+ public String setBackupTransportForUser(String transport, int userId) throws IOException {
+ String output =
+ executeShellCommandAndReturnOutput(
+ String.format("bmgr --user %d transport %s", userId, transport));
+ Pattern pattern = Pattern.compile("\\(formerly (.*)\\)$");
+ Matcher matcher = pattern.matcher(output);
+ if (matcher.find()) {
+ return matcher.group(1);
+ } else {
+ throw new RuntimeException("Non-parsable output setting bmgr transport: " + output);
+ }
+ }
+}
+
diff --git a/common/util/src/com/android/compatibility/common/util/BusinessLogic.java b/common/util/src/com/android/compatibility/common/util/BusinessLogic.java
index 8a3fcb1..ec1a6ce 100644
--- a/common/util/src/com/android/compatibility/common/util/BusinessLogic.java
+++ b/common/util/src/com/android/compatibility/common/util/BusinessLogic.java
@@ -18,6 +18,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -131,7 +132,7 @@
String[] descriptions = keySet.toArray(new String[keySet.size()]);
StringBuilder msg = new StringBuilder("");
msg.append(String.format("Test %s for cases: ", (failed) ? "failed" : "skipped"));
- msg.append(String.join(", ", descriptions));
+ msg.append(Arrays.toString(descriptions));
msg.append("\nReasons include:");
for (String description : descriptions) {
RuntimeException re = exceptions.get(description);
diff --git a/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java b/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java
index a9df3cf..a89ae17 100644
--- a/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java
+++ b/common/util/src/com/android/compatibility/common/util/BusinessLogicFactory.java
@@ -16,17 +16,21 @@
package com.android.compatibility.common.util;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
import com.android.compatibility.common.util.BusinessLogic.BusinessLogicRule;
import com.android.compatibility.common.util.BusinessLogic.BusinessLogicRuleAction;
import com.android.compatibility.common.util.BusinessLogic.BusinessLogicRuleCondition;
import com.android.compatibility.common.util.BusinessLogic.BusinessLogicRulesList;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -67,16 +71,38 @@
private static final String TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
/**
+ * Create a BusinessLogic instance from a {@link FileInputStream} of business logic data,
+ * formatted in JSON. This format is identical to that which is received from the Android
+ * Partner business logic service.
+ */
+ public static BusinessLogic createFromFile(FileInputStream stream) {
+ try {
+ String businessLogicString = readStream(stream);
+ return createBL(businessLogicString);
+ } catch (IOException e) {
+ throw new RuntimeException("Business Logic failed", e);
+ }
+ }
+
+ /**
* Create a BusinessLogic instance from a file of business logic data, formatted in JSON.
* This format is identical to that which is received from the Android Partner business logic
* service.
*/
public static BusinessLogic createFromFile(File f) {
+ try {
+ String businessLogicString = readFile(f);
+ return createBL(businessLogicString);
+ } catch (IOException e) {
+ throw new RuntimeException("Business Logic failed", e);
+ }
+ }
+
+ private static BusinessLogic createBL(String businessLogicString) {
// Populate the map from testname to business rules for this new BusinessLogic instance
Map<String, List<BusinessLogicRulesList>> rulesMap = new HashMap<>();
BusinessLogic bl = new BusinessLogic();
try {
- String businessLogicString = readFile(f);
JSONObject root = new JSONObject(businessLogicString);
JSONArray jsonRulesLists = null;
if (root.has(AUTHENTICATION_STATUS)){
@@ -106,7 +132,7 @@
testRulesLists.add(extractRulesList(jsonRulesList));
rulesMap.put(testName, testRulesLists);
}
- } catch (IOException | JSONException e) {
+ } catch (JSONException e) {
throw new RuntimeException("Business Logic failed", e);
}
// Return business logic
@@ -229,4 +255,16 @@
return sb.toString();
}
}
+
+ /** Extract string from stream */
+ private static String readStream(FileInputStream stream) throws IOException {
+ int irChar = -1;
+ StringBuilder builder = new StringBuilder();
+ try (Reader ir = new BufferedReader(new InputStreamReader(stream))) {
+ while ((irChar = ir.read()) != -1) {
+ builder.append((char) irChar);
+ }
+ }
+ return builder.toString();
+ }
}
diff --git a/common/util/src/com/android/compatibility/common/util/CommonTestUtils.java b/common/util/src/com/android/compatibility/common/util/CommonTestUtils.java
new file mode 100644
index 0000000..75fa17a
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/CommonTestUtils.java
@@ -0,0 +1,42 @@
+/*
+ * 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.compatibility.common.util;
+
+import static org.junit.Assert.fail;
+
+// TODO(b/131736394): Remove duplication with HostSideTestUtils.
+/** Utility class for tests. */
+public class CommonTestUtils {
+ @FunctionalInterface
+ public interface BooleanSupplierWithThrow<E extends Throwable> {
+ boolean getAsBoolean() throws E;
+ }
+
+ /** Wait until {@code predicate} is satisfied, or fail, with a given timeout. */
+ public static <E extends Throwable> void waitUntil(
+ String message, long timeoutSeconds, BooleanSupplierWithThrow<E> predicate)
+ throws E, InterruptedException {
+ int sleep = 125;
+ final long timeout = System.currentTimeMillis() + timeoutSeconds * 1000;
+ while (System.currentTimeMillis() < timeout) {
+ if (predicate.getAsBoolean()) {
+ return;
+ }
+ Thread.sleep(sleep);
+ }
+ fail(message);
+ }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/CtsDownstreamingTest.java b/common/util/src/com/android/compatibility/common/util/CtsDownstreamingTest.java
new file mode 100644
index 0000000..5dce31c
--- /dev/null
+++ b/common/util/src/com/android/compatibility/common/util/CtsDownstreamingTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.compatibility.common.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation marking a test case as a CTS downstreaming test.
+ * <p>
+ * Test classes and test cases marked with this annotation will be excluded
+ * from CTS runs, and included in GTS releases.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface CtsDownstreamingTest {
+}
diff --git a/common/util/src/com/android/compatibility/common/util/DevicePropertyInfo.java b/common/util/src/com/android/compatibility/common/util/DevicePropertyInfo.java
index 04ab61e..7435839 100644
--- a/common/util/src/com/android/compatibility/common/util/DevicePropertyInfo.java
+++ b/common/util/src/com/android/compatibility/common/util/DevicePropertyInfo.java
@@ -43,6 +43,7 @@
private final String mModel;
private final String mProduct;
private final String mReferenceFingerprint;
+ private final String mVendorFingerprint;
private final String mSerial;
private final String mTags;
private final String mType;
@@ -52,11 +53,30 @@
private final String mVersionSecurityPatch;
private final String mVersionIncremental;
- public DevicePropertyInfo(String abi, String abi2, String abis, String abis32, String abis64,
- String board, String brand, String device, String fingerprint, String id,
- String manufacturer, String model, String product, String referenceFigerprint,
- String serial, String tags, String type, String versionBaseOs, String versionRelease,
- String versionSdk, String versionSecurityPatch, String versionIncremental) {
+ public DevicePropertyInfo(
+ String abi,
+ String abi2,
+ String abis,
+ String abis32,
+ String abis64,
+ String board,
+ String brand,
+ String device,
+ String fingerprint,
+ String vendorFingerprint,
+ String id,
+ String manufacturer,
+ String model,
+ String product,
+ String referenceFingerprint,
+ String serial,
+ String tags,
+ String type,
+ String versionBaseOs,
+ String versionRelease,
+ String versionSdk,
+ String versionSecurityPatch,
+ String versionIncremental) {
mAbi = abi;
mAbi2 = abi2;
mAbis = abis;
@@ -66,11 +86,12 @@
mBrand = brand;
mDevice = device;
mFingerprint = fingerprint;
+ mVendorFingerprint = vendorFingerprint;
mId = id;
mManufacturer = manufacturer;
mModel = model;
mProduct = product;
- mReferenceFingerprint = referenceFigerprint;
+ mReferenceFingerprint = referenceFingerprint;
mSerial = serial;
mTags = tags;
mType = type;
@@ -98,6 +119,7 @@
propertyMap.put(prefix + "brand", mBrand);
propertyMap.put(prefix + "device", mDevice);
propertyMap.put(prefix + "fingerprint", mFingerprint);
+ propertyMap.put(prefix + "vendor_fingerprint", mVendorFingerprint);
propertyMap.put(prefix + "id", mId);
propertyMap.put(prefix + "manufacturer", mManufacturer);
propertyMap.put(prefix + "model", mModel);
diff --git a/common/util/src/com/android/compatibility/common/util/DynamicConfig.java b/common/util/src/com/android/compatibility/common/util/DynamicConfig.java
index 92bd380..797afea 100644
--- a/common/util/src/com/android/compatibility/common/util/DynamicConfig.java
+++ b/common/util/src/com/android/compatibility/common/util/DynamicConfig.java
@@ -55,6 +55,12 @@
mDynamicConfigMap = createConfigMap(file);
}
+ /** Init using directly a {@link FileInputStream} from the config file. */
+ public void initializeConfig(FileInputStream fileStream)
+ throws XmlPullParserException, IOException {
+ mDynamicConfigMap = createConfigMap(fileStream);
+ }
+
public String getValue(String key) {
assertRemoteConfigRequirementMet();
List<String> singleValue = mDynamicConfigMap.get(key);
@@ -109,10 +115,17 @@
public static Map<String, List<String>> createConfigMap(File file)
throws XmlPullParserException, IOException {
+ try (FileInputStream stream = new FileInputStream(file)) {
+ return createConfigMap(stream);
+ }
+ }
+
+ public static Map<String, List<String>> createConfigMap(FileInputStream fileStream)
+ throws XmlPullParserException, IOException {
Map<String, List<String>> dynamicConfigMap = new HashMap<String, List<String>>();
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
- parser.setInput(new InputStreamReader(new FileInputStream(file)));
+ parser.setInput(new InputStreamReader(fileStream));
parser.nextTag();
parser.require(XmlPullParser.START_TAG, NS, CONFIG_TAG);
diff --git a/common/util/src/com/android/compatibility/common/util/LogcatInspector.java b/common/util/src/com/android/compatibility/common/util/LogcatInspector.java
index ed82307..053db34 100644
--- a/common/util/src/com/android/compatibility/common/util/LogcatInspector.java
+++ b/common/util/src/com/android/compatibility/common/util/LogcatInspector.java
@@ -100,12 +100,11 @@
InputStream logcatStream = executeShellCommand("logcat -v brief -d " + filterSpec);
BufferedReader logcat = new BufferedReader(new InputStreamReader(logcatStream));
String line;
- stringIndex = 0;
while ((line = logcat.readLine()) != null) {
if (line.contains(logcatStrings[stringIndex])) {
stringIndex++;
if (stringIndex >= logcatStrings.length) {
- drainAndClose(logcat);
+ StreamUtil.drainAndClose(logcat);
return stringIndex;
}
}
@@ -117,14 +116,4 @@
}
return stringIndex;
}
-
- private static void drainAndClose(BufferedReader reader) {
- try {
- while (reader.read() >= 0) {
- // do nothing.
- }
- } catch (IOException ignored) {
- }
- Closeables.closeQuietly(reader);
- }
}
diff --git a/common/util/src/com/android/compatibility/common/util/ReadElf.java b/common/util/src/com/android/compatibility/common/util/ReadElf.java
index 44c89d6..b681c1c 100644
--- a/common/util/src/com/android/compatibility/common/util/ReadElf.java
+++ b/common/util/src/com/android/compatibility/common/util/ReadElf.java
@@ -566,6 +566,9 @@
/** Rodata String List */
private List<String> mRoStrings;
+ /** Rodata byte[] */
+ private byte[] mRoData;
+
public static ReadElf read(File file) throws IOException {
return new ReadElf(file);
}
@@ -711,6 +714,7 @@
private ReadElf(File file) throws IOException {
mHasRodata = false;
+ mRoData = null;
mPath = file.getPath();
mFile = new RandomAccessFile(file, "r");
@@ -1302,11 +1306,8 @@
public List<String> getRoStrings() throws IOException {
if (mRoStrings == null) {
mRoStrings = new ArrayList<>();
- if (mHasRodata) {
- byte[] byteArr = new byte[mRodataSize];
- mFile.seek(mRodataOffset);
- mFile.readFully(byteArr);
-
+ byte[] byteArr = getRoData();
+ if (byteArr != null) {
int strOffset = 0;
for (int i = 0; i < mRodataSize; i++) {
if (byteArr[i] == 0) {
@@ -1322,4 +1323,19 @@
}
return mRoStrings;
}
+
+ /**
+ * Gets .rodata section
+ *
+ * @return byte [] of .rodata or null if there is none
+ */
+ public byte[] getRoData() throws IOException {
+ if (mHasRodata && mRoData == null) {
+ mRoData = new byte[mRodataSize];
+ mFile.seek(mRodataOffset);
+ mFile.readFully(mRoData);
+ }
+
+ return mRoData;
+ }
}
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
index 90066a4..1be3624 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -114,6 +114,7 @@
private static final String SUITE_VERSION_ATTR = "suite_version";
private static final String SUITE_BUILD_ATTR = "suite_build_number";
private static final String SUMMARY_TAG = "Summary";
+ private static final String METRIC_TAG = "Metric";
private static final String TEST_TAG = "Test";
private static final String LATEST_RESULT_DIR = "latest";
@@ -264,6 +265,10 @@
parser.require(XmlPullParser.END_TAG, NS, SCREENSHOT_TAG);
} else if (SUMMARY_TAG.equals(parser.getName())) {
test.setReportLog(ReportLog.parse(parser));
+ } else if (METRIC_TAG.equals(parser.getName())) {
+ // Ignore the new format in the old parser.
+ parser.nextText();
+ parser.require(XmlPullParser.END_TAG, NS, METRIC_TAG);
} else {
parser.nextTag();
}
@@ -546,8 +551,9 @@
}
List<File> allResultDirs = getResultDirectories(resultsDir);
if (sessionId >= allResultDirs.size()) {
- throw new IllegalArgumentException(String.format("Invalid session id [%d], results" +
- "directory contains only %d results", sessionId, allResultDirs.size()));
+ throw new IllegalArgumentException(String.format("Invalid session id [%d], results " +
+ "directory (%s) contains only %d results",
+ sessionId, resultsDir.getAbsolutePath(), allResultDirs.size()));
}
return allResultDirs.get(sessionId);
}
diff --git a/common/util/src/com/android/compatibility/common/util/StreamUtil.java b/common/util/src/com/android/compatibility/common/util/StreamUtil.java
index 4cef5c9..1909c21 100644
--- a/common/util/src/com/android/compatibility/common/util/StreamUtil.java
+++ b/common/util/src/com/android/compatibility/common/util/StreamUtil.java
@@ -16,9 +16,14 @@
package com.android.compatibility.common.util;
+import com.google.common.io.Closeables;
+
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
public class StreamUtil {
@@ -43,4 +48,25 @@
}
}
+ /**
+ * Reads {@code inputStream} converting it into a string. Does NOT close it.
+ *
+ * @throws IOException
+ */
+ public static String readInputStream(InputStream inputStream) throws IOException {
+ ByteArrayOutputStream result = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = inputStream.read(buffer)) != -1) {
+ result.write(buffer, 0, length);
+ }
+ return result.toString(StandardCharsets.UTF_8.name());
+ }
+
+ public static void drainAndClose(Reader reader) {
+ try {
+ while (reader.read() >= 0) {}
+ } catch (IOException ignored) {}
+ Closeables.closeQuietly(reader);
+ }
}
diff --git a/common/util/tests/Android.bp b/common/util/tests/Android.bp
new file mode 100644
index 0000000..2943a79
--- /dev/null
+++ b/common/util/tests/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2015 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.
+
+java_test_host {
+ name: "compatibility-common-util-tests",
+ defaults: ["cts_error_prone_rules"],
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "junit",
+ "kxml2-2.3.0",
+ "tradefed",
+ "compatibility-common-util-hostsidelib",
+ ],
+
+ // Holds golden sample files in assets for validation
+ java_resource_dirs: ["assets/"],
+}
diff --git a/common/util/tests/Android.mk b/common/util/tests/Android.mk
deleted file mode 100644
index d89db6c..0000000
--- a/common/util/tests/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := junit-host kxml2-2.3.0 tradefed compatibility-common-util-hostsidelib
-
-LOCAL_MODULE := compatibility-common-util-tests
-
-# Holds golden sample files in assets for validation
-LOCAL_JAVA_RESOURCE_DIRS := assets/
-
-LOCAL_MODULE_TAGS := optional
-include cts/error_prone_rules.mk
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/util/tests/run_tests.sh b/common/util/tests/run_tests.sh
deleted file mode 100755
index bed2c19..0000000
--- a/common/util/tests/run_tests.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2015 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.
-
-HARNESS_DIR=$(dirname ${0})/../../..
-source ${HARNESS_DIR}/test_defs.sh
-
-JARS="
- compatibility-common-util-hostsidelib\
- compatibility-common-util-tests\
- compatibility-host-util\
- compatibility-host-util-tests\
- compatibility-mock-tradefed\
- compatibility-tradefed-tests"
-
-run_tests "com.android.compatibility.common.util.UnitTests" "${JARS}" "${@}"
-
diff --git a/common/util/tests/src/com/android/compatibility/common/util/BackupUtilsTest.java b/common/util/tests/src/com/android/compatibility/common/util/BackupUtilsTest.java
new file mode 100644
index 0000000..133a545
--- /dev/null
+++ b/common/util/tests/src/com/android/compatibility/common/util/BackupUtilsTest.java
@@ -0,0 +1,448 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.util.RunUtil;
+
+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;
+
+/**
+ * Unit tests for {@link BackupUtils}
+ */
+@RunWith(JUnit4.class)
+public class BackupUtilsTest {
+ private static final int BACKUP_SERVICE_INIT_TIMEOUT_SECS = 1;
+ private static final int TEST_USER_ID = 10;
+
+ private boolean mIsDumpsysCommandCalled;
+ private boolean mIsEnableCommandCalled;
+
+ @Before
+ public void setUp() {
+ mIsDumpsysCommandCalled = false;
+ mIsEnableCommandCalled = false;
+ }
+
+ @Test
+ public void testEnableBackup_whenEnableTrueAndEnabled_returnsTrue() throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("bmgr enabled")) {
+ output = "Backup Manager currently enabled";
+ } else if (command.equals("bmgr enable true")) {
+ output = "Backup Manager now enabled";
+ mIsEnableCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ assertTrue(backupUtils.enableBackup(true));
+ assertTrue(mIsEnableCommandCalled);
+ }
+
+ @Test
+ public void testEnableBackup_whenEnableTrueAndDisabled_returnsFalse() throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("bmgr enabled")) {
+ output = "Backup Manager currently disabled";
+ } else if (command.equals("bmgr enable true")) {
+ output = "Backup Manager now enabled";
+ mIsEnableCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ assertFalse(backupUtils.enableBackup(true));
+ assertTrue(mIsEnableCommandCalled);
+ }
+
+ @Test
+ public void testEnableBackup_whenEnableFalseAndEnabled_returnsTrue() throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("bmgr enabled")) {
+ output = "Backup Manager currently enabled";
+ } else if (command.equals("bmgr enable false")) {
+ output = "Backup Manager now disabled";
+ mIsEnableCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ assertTrue(backupUtils.enableBackup(false));
+ assertTrue(mIsEnableCommandCalled);
+ }
+
+ @Test
+ public void testEnableBackup_whenEnableFalseAndDisabled_returnsFalse() throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("bmgr enabled")) {
+ output = "Backup Manager currently disabled";
+ } else if (command.equals("bmgr enable false")) {
+ output = "Backup Manager now disabled";
+ mIsEnableCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ assertFalse(backupUtils.enableBackup(false));
+ assertTrue(mIsEnableCommandCalled);
+ }
+
+ @Test
+ public void testEnableBackup_whenEnableTrueAndEnabledAndCommandsReturnMultipleLines()
+ throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("bmgr enabled")) {
+ output = "Backup Manager currently enabled" + "\n...";
+ } else if (command.equals("bmgr enable true")) {
+ output = "Backup Manager now enabled" + "\n...";
+ mIsEnableCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ assertTrue(backupUtils.enableBackup(true));
+ assertTrue(mIsEnableCommandCalled);
+ }
+
+ @Test
+ public void testEnableBackup_whenQueryCommandThrows_propagatesException() throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("bmgr enabled")) {
+ throw new IOException(String.format(
+ "enableBackup: Failed to run command: %s", command));
+ } else if (command.equals("bmgr enable true")) {
+ output = "Backup Manager now enabled";
+ mIsEnableCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+
+ boolean isExceptionHappened = false;
+ try {
+ backupUtils.enableBackup(true);
+ } catch (IOException e) {
+ // enableBackup: Failed to run command: bmgr enabled
+ isExceptionHappened = true;
+ }
+ assertTrue(isExceptionHappened);
+ assertFalse(mIsEnableCommandCalled);
+ }
+
+ @Test
+ public void testEnableBackup_whenSetCommandThrows_propagatesException() throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("bmgr enabled")) {
+ output = "Backup Manager currently enabled";
+ } else if (command.equals("bmgr enable true")) {
+ mIsEnableCommandCalled = true;
+ throw new IOException(String.format(
+ "enableBackup: Failed to run command: %s", command));
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+
+ boolean isExceptionHappened = false;
+ try {
+ backupUtils.enableBackup(true);
+ } catch (IOException e) {
+ // enableBackup: Failed to run command: bmgr enable true
+ isExceptionHappened = true;
+ }
+ assertTrue(isExceptionHappened);
+ assertTrue(mIsEnableCommandCalled);
+ }
+
+ @Test
+ public void testEnableBackup_whenQueryCommandReturnsInvalidString_throwsException()
+ throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("bmgr enabled")) {
+ output = "Backup Manager ???";
+ } else if (command.equals("bmgr enable true")) {
+ output = "Backup Manager now enabled";
+ mIsEnableCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+
+ boolean isExceptionHappened = false;
+ try {
+ backupUtils.enableBackup(true);
+ } catch (RuntimeException e) {
+ // non-parsable output setting bmgr enabled: Backup Manager ???
+ isExceptionHappened = true;
+ }
+ assertTrue(isExceptionHappened);
+ assertFalse(mIsEnableCommandCalled);
+ }
+
+ @Test
+ public void testEnableBackup_whenQueryCommandReturnsEmptyString_throwsException()
+ throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("bmgr enabled")) {
+ // output is empty already
+ } else if (command.equals("bmgr enable true")) {
+ output = "Backup Manager now enabled";
+ mIsEnableCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+
+ boolean isExceptionHappened = false;
+ try {
+ backupUtils.enableBackup(true);
+ } catch (NullPointerException e) {
+ // null output by running command, bmgr enabled
+ isExceptionHappened = true;
+ }
+ assertTrue(isExceptionHappened);
+ assertFalse(mIsEnableCommandCalled);
+ }
+
+ @Test
+ public void testWaitForBackupInitialization_whenEnabled() throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("dumpsys backup")) {
+ output = "Backup Manager is enabled / provisioned / not pending init";
+ mIsDumpsysCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ backupUtils.waitForBackupInitialization();
+ assertTrue(mIsDumpsysCommandCalled);
+ }
+
+ @Test
+ public void testWaitForBackupInitialization_whenDisabled() throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("dumpsys backup")) {
+ output = "Backup Manager is disabled / provisioned / not pending init";
+ mIsDumpsysCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ backupUtils.waitForBackupInitialization();
+ assertTrue(mIsDumpsysCommandCalled);
+ }
+
+ @Test
+ public void testWaitUntilBackupServiceIsRunning_whenRunning_doesntThrow() throws Exception {
+ BackupUtils backupUtils = constructDumpsysForBackupUsers(TEST_USER_ID);
+
+ try {
+ backupUtils.waitUntilBackupServiceIsRunning(
+ TEST_USER_ID, BACKUP_SERVICE_INIT_TIMEOUT_SECS);
+ } catch (AssertionError e) {
+ fail("BackupUtils#waitUntilBackupServiceIsRunning threw an exception");
+ }
+ assertTrue(mIsDumpsysCommandCalled);
+ }
+
+ @Test
+ public void testWaitUntilBackupServiceIsRunning_whenNotRunning_throws() throws Exception {
+ // Pass in a different userId to not have the current one among running ids.
+ BackupUtils backupUtils = constructDumpsysForBackupUsers(TEST_USER_ID + 1);
+
+ boolean wasExceptionThrown = false;
+ try {
+ backupUtils.waitUntilBackupServiceIsRunning(
+ TEST_USER_ID, BACKUP_SERVICE_INIT_TIMEOUT_SECS);
+ } catch (AssertionError e) {
+ wasExceptionThrown = true;
+ }
+
+ assertTrue(mIsDumpsysCommandCalled);
+ assertTrue(wasExceptionThrown);
+ }
+
+ private BackupUtils constructDumpsysForBackupUsers(int runningUserId) {
+ return new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("dumpsys backup users")) {
+ output = "Backup Manager is running for users: " + runningUserId;
+ mIsDumpsysCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ }
+
+ @Test
+ public void testWaitForBackupInitialization_whenEnabledAndCommandReturnsMultipleLines()
+ throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("dumpsys backup")) {
+ output = "Backup Manager is enabled / provisioned / not pending init" + "\n...";
+ mIsDumpsysCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ backupUtils.waitForBackupInitialization();
+ assertTrue(mIsDumpsysCommandCalled);
+ }
+
+ @Test
+ public void testWaitForBackupInitialization_whenCommandThrows_propagatesException()
+ throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("dumpsys backup")) {
+ mIsDumpsysCommandCalled = true;
+ throw new IOException(String.format(
+ "waitForBackupInitialization: Failed to run command: %s", command));
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+
+ boolean isExceptionHappened = false;
+ try {
+ backupUtils.waitForBackupInitialization();
+ } catch (IOException e) {
+ // waitForBackupInitialization: Failed to run command: dumpsys backup
+ isExceptionHappened = true;
+ }
+ assertTrue(isExceptionHappened);
+ assertTrue(mIsDumpsysCommandCalled);
+ }
+
+ @Test
+ public void testWaitForBackupInitialization_whenCommandReturnsInvalidString()
+ throws Exception {
+ class TestRunnable implements Runnable {
+ @Override
+ public void run() {
+ try {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command)
+ throws IOException {
+ String output = "";
+ if (command.equals("dumpsys backup")) {
+ output = "Backup Manager ???";
+ mIsDumpsysCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+ backupUtils.waitForBackupInitialization();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ TestRunnable testRunnable = new TestRunnable();
+ Thread testThread = new Thread(testRunnable);
+
+ try {
+ testThread.start();
+ RunUtil.getDefault().sleep(100);
+ assertTrue(mIsDumpsysCommandCalled);
+ assertTrue(testThread.isAlive());
+ } catch (Exception e) {
+ // ignore
+ } finally {
+ testThread.interrupt();
+ }
+ }
+
+ @Test
+ public void testWaitForBackupInitialization_whenCommandReturnsEmptyString_throwsException()
+ throws Exception {
+ BackupUtils backupUtils = new BackupUtils() {
+ @Override
+ protected InputStream executeShellCommand(String command) throws IOException {
+ String output = "";
+ if (command.equals("dumpsys backup")) {
+ // output is empty already
+ mIsDumpsysCommandCalled = true;
+ }
+ return new ByteArrayInputStream(output.getBytes("UTF-8"));
+ }
+ };
+
+ boolean isExceptionHappened = false;
+ try {
+ backupUtils.waitForBackupInitialization();
+ } catch (NullPointerException e) {
+ // null output by running command, dumpsys backup
+ isExceptionHappened = true;
+ }
+ assertTrue(isExceptionHappened);
+ assertTrue(mIsDumpsysCommandCalled);
+ }
+}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/LightInvocationResultTest.java b/common/util/tests/src/com/android/compatibility/common/util/LightInvocationResultTest.java
index 540c87e..8a87277 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/LightInvocationResultTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/LightInvocationResultTest.java
@@ -40,7 +40,7 @@
}
public void testLightInvocationResultInstatiate() throws Exception {
- File resultDir = ResultHandlerTest.writeResultDir(resultsDir);
+ File resultDir = ResultHandlerTest.writeResultDir(resultsDir, false);
IInvocationResult fullResult = ResultHandler.getResultFromDir(resultDir);
LightInvocationResult lightResult = new LightInvocationResult(fullResult);
// Ensure that light result implementation does not use a reference to the full result
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
index 1529499..50a00f0 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -148,6 +148,11 @@
" </Metric>\n" +
" </Summary>\n" +
" </Test>\n";
+ private static final String NEW_XML_TEST_RESULT =
+ " <Test result=\"pass\" name=\"%s\">\n"
+ + " <Metric key=\"%s\">%s</Metric>\n"
+ + " </Test>\n";
+
private File resultsDir = null;
private File resultDir = null;
@@ -208,49 +213,59 @@
COMMAND_LINE_ARGS);
// Parse the results and assert correctness
- checkResult(ResultHandler.getResultFromDir(resultDir));
+ checkResult(ResultHandler.getResultFromDir(resultDir), false);
}
public void testParsing() throws Exception {
- File resultDir = writeResultDir(resultsDir);
+ File resultDir = writeResultDir(resultsDir, false);
// Parse the results and assert correctness
- checkResult(ResultHandler.getResultFromDir(resultDir));
+ checkResult(ResultHandler.getResultFromDir(resultDir), false);
+ }
+
+ public void testParsing_newTestFormat() throws Exception {
+ File resultDir = writeResultDir(resultsDir, true);
+ // Parse the results and assert correctness
+ checkResult(ResultHandler.getResultFromDir(resultDir), true);
}
public void testParsing_usesUnalteredBuildFingerprintWhenPresent() throws Exception {
String buildInfo = String.format(XML_BUILD_INFO_WITH_UNALTERED_BUILD_FINGERPRINT,
EXAMPLE_BUILD_FINGERPRINT, EXAMPLE_BUILD_FINGERPRINT_UNALTERED,
EXAMPLE_BUILD_ID, EXAMPLE_BUILD_PRODUCT);
- File resultDir = writeResultDir(resultsDir, buildInfo);
- checkResult(ResultHandler.getResultFromDir(resultDir), EXAMPLE_BUILD_FINGERPRINT_UNALTERED);
+ File resultDir = writeResultDir(resultsDir, buildInfo, false);
+ checkResult(
+ ResultHandler.getResultFromDir(resultDir),
+ EXAMPLE_BUILD_FINGERPRINT_UNALTERED,
+ false);
}
public void testParsing_whenUnalteredBuildFingerprintIsEmpty_usesRegularBuildFingerprint() throws Exception {
String buildInfo = String.format(XML_BUILD_INFO_WITH_UNALTERED_BUILD_FINGERPRINT,
EXAMPLE_BUILD_FINGERPRINT, "", EXAMPLE_BUILD_ID, EXAMPLE_BUILD_PRODUCT);
- File resultDir = writeResultDir(resultsDir, buildInfo);
- checkResult(ResultHandler.getResultFromDir(resultDir), EXAMPLE_BUILD_FINGERPRINT);
+ File resultDir = writeResultDir(resultsDir, buildInfo, false);
+ checkResult(ResultHandler.getResultFromDir(resultDir), EXAMPLE_BUILD_FINGERPRINT, false);
}
public void testGetLightResults() throws Exception {
- File resultDir = writeResultDir(resultsDir);
+ File resultDir = writeResultDir(resultsDir, false);
List<IInvocationResult> lightResults = ResultHandler.getLightResults(resultsDir);
assertEquals("Expected one result", 1, lightResults.size());
IInvocationResult lightResult = lightResults.get(0);
checkLightResult(lightResult);
}
- static File writeResultDir(File resultsDir) throws IOException {
+ static File writeResultDir(File resultsDir, boolean newTestFormat) throws IOException {
String buildInfo = String.format(XML_BUILD_INFO, EXAMPLE_BUILD_FINGERPRINT,
EXAMPLE_BUILD_ID, EXAMPLE_BUILD_PRODUCT);
- return writeResultDir(resultsDir, buildInfo);
+ return writeResultDir(resultsDir, buildInfo, newTestFormat);
}
/*
* Helper to write a result to the results dir, for testing.
* @return the written resultDir
*/
- static File writeResultDir(File resultsDir, String buildInfo) throws IOException {
+ static File writeResultDir(File resultsDir, String buildInfo, boolean newTestFormat)
+ throws IOException {
File resultDir = null;
FileWriter writer = null;
try {
@@ -265,9 +280,26 @@
moduleACases);
String moduleBTest3 = String.format(XML_TEST_FAIL, METHOD_3, MESSAGE, STACK_TRACE,
BUG_REPORT, LOGCAT, SCREENSHOT);
- String moduleBTest4 = String.format(XML_TEST_RESULT, METHOD_4, SUMMARY_SOURCE,
- SUMMARY_MESSAGE, ResultType.HIGHER_BETTER.toReportString(),
- ResultUnit.SCORE.toReportString(), Double.toString(SUMMARY_VALUE));
+ String moduleBTest4 = "";
+ if (newTestFormat) {
+ moduleBTest4 =
+ String.format(
+ NEW_XML_TEST_RESULT,
+ METHOD_4,
+ SUMMARY_MESSAGE,
+ Double.toString(SUMMARY_VALUE));
+ } else {
+ moduleBTest4 =
+ String.format(
+ XML_TEST_RESULT,
+ METHOD_4,
+ SUMMARY_SOURCE,
+ SUMMARY_MESSAGE,
+ ResultType.HIGHER_BETTER.toReportString(),
+ ResultUnit.SCORE.toReportString(),
+ Double.toString(SUMMARY_VALUE));
+ }
+
String moduleBTest5 = String.format(XML_TEST_SKIP, METHOD_5);
String moduleBTests = String.join("", moduleBTest3, moduleBTest4, moduleBTest5);
String moduleBCases = String.format(XML_CASE, CLASS_B, moduleBTests);
@@ -314,11 +346,13 @@
assertEquals("Expected 2 total modules", 2, modules.size());
}
- static void checkResult(IInvocationResult result) throws Exception {
- checkResult(result, EXAMPLE_BUILD_FINGERPRINT);
+ static void checkResult(IInvocationResult result, boolean newTestFormat) throws Exception {
+ checkResult(result, EXAMPLE_BUILD_FINGERPRINT, newTestFormat);
}
- static void checkResult(IInvocationResult result, String expectedBuildFingerprint) throws Exception {
+ static void checkResult(
+ IInvocationResult result, String expectedBuildFingerprint, boolean newTestFormat)
+ throws Exception {
assertEquals("Expected 3 passes", 3, result.countResults(TestStatus.PASS));
assertEquals("Expected 1 failure", 1, result.countResults(TestStatus.FAIL));
@@ -392,16 +426,19 @@
assertNull("Unexpected screenshot", moduleBTest4.getScreenshot());
assertNull("Unexpected message", moduleBTest4.getMessage());
assertNull("Unexpected stack trace", moduleBTest4.getStackTrace());
- ReportLog report = moduleBTest4.getReportLog();
- assertNotNull("Expected report", report);
- ReportLog.Metric summary = report.getSummary();
- assertNotNull("Expected report summary", summary);
- assertEquals("Incorrect source", SUMMARY_SOURCE, summary.getSource());
- assertEquals("Incorrect message", SUMMARY_MESSAGE, summary.getMessage());
- assertEquals("Incorrect type", ResultType.HIGHER_BETTER, summary.getType());
- assertEquals("Incorrect unit", ResultUnit.SCORE, summary.getUnit());
- assertTrue("Incorrect values", Arrays.equals(new double[] { SUMMARY_VALUE },
- summary.getValues()));
+ if (!newTestFormat) {
+ ReportLog report = moduleBTest4.getReportLog();
+ assertNotNull("Expected report", report);
+ ReportLog.Metric summary = report.getSummary();
+ assertNotNull("Expected report summary", summary);
+ assertEquals("Incorrect source", SUMMARY_SOURCE, summary.getSource());
+ assertEquals("Incorrect message", SUMMARY_MESSAGE, summary.getMessage());
+ assertEquals("Incorrect type", ResultType.HIGHER_BETTER, summary.getType());
+ assertEquals("Incorrect unit", ResultUnit.SCORE, summary.getUnit());
+ assertTrue(
+ "Incorrect values",
+ Arrays.equals(new double[] {SUMMARY_VALUE}, summary.getValues()));
+ }
ITestResult moduleBTest5 = moduleBResults.get(2);
assertEquals("Incorrect name", METHOD_5, moduleBTest5.getName());
assertEquals("Incorrect result", TestStatus.PASS, moduleBTest5.getResultStatus());
diff --git a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
index 948c26e..a7f8460 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
@@ -26,6 +26,7 @@
*/
@RunWith(Suite.class)
@SuiteClasses({
+ BackupUtilsTest.class,
BusinessLogicTest.class,
CaseResultTest.class,
CrashUtilsTest.class,
diff --git a/tools/Android.mk b/tools/Android.mk
deleted file mode 100644
index 9af9f44..0000000
--- a/tools/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# 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 $(call all-subdir-makefiles)
diff --git a/tools/cts-instant-tradefed/Android.bp b/tools/cts-instant-tradefed/Android.bp
new file mode 100644
index 0000000..cbdb32f
--- /dev/null
+++ b/tools/cts-instant-tradefed/Android.bp
@@ -0,0 +1,33 @@
+// 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.
+
+java_library_host {
+ name: "cts-instant-resources",
+
+ java_resource_dirs: ["res"],
+}
+
+tradefed_binary_host {
+ name: "cts-instant-tradefed",
+ defaults: ["cts_error_prone_rules"],
+ wrapper: "etc/cts-instant-tradefed",
+ short_name: "CTS_INSTANT",
+ full_name: "Compatibility Test Suite for Instant Apps",
+ version: "9.0_r2",
+
+ static_libs: [
+ "cts-instant-resources",
+ "cts-tradefed-harness",
+ ],
+}
diff --git a/tools/cts-instant-tradefed/Android.mk b/tools/cts-instant-tradefed/Android.mk
deleted file mode 100644
index c6c89a0..0000000
--- a/tools/cts-instant-tradefed/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_JAVA_RESOURCE_DIRS := res
-
-LOCAL_SUITE_BUILD_NUMBER := $(BUILD_NUMBER_FROM_FILE)
-LOCAL_SUITE_TARGET_ARCH := $(TARGET_ARCH)
-LOCAL_SUITE_NAME := CTS_INSTANT
-LOCAL_SUITE_FULLNAME := "Compatibility Test Suite for Instant Apps"
-LOCAL_SUITE_VERSION := 9.0_r2
-LOCAL_STATIC_JAVA_LIBRARIES += cts-tradefed-harness
-
-LOCAL_MODULE := cts-instant-tradefed
-LOCAL_COMPATIBILITY_SUITE := cts_instant
-include cts/error_prone_rules.mk
-include $(BUILD_COMPATIBILITY_SUITE)
-
-# Build all sub-directories
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/cts-instant-tradefed/etc/Android.mk b/tools/cts-instant-tradefed/etc/Android.mk
deleted file mode 100644
index 2d3c098..0000000
--- a/tools/cts-instant-tradefed/etc/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PREBUILT_EXECUTABLES := cts-instant-tradefed
-include $(BUILD_HOST_PREBUILT)
-
diff --git a/tools/cts-instant-tradefed/etc/cts-instant-tradefed b/tools/cts-instant-tradefed/etc/cts-instant-tradefed
index 687eabb..e927b1c 100755
--- a/tools/cts-instant-tradefed/etc/cts-instant-tradefed
+++ b/tools/cts-instant-tradefed/etc/cts-instant-tradefed
@@ -93,8 +93,7 @@
cts-instant-tradefed
cts-instant-tradefed-tests
compatibility-common-util-tests
- compatibility-tradefed-tests
- host-libprotobuf-java-full"
+ compatibility-tradefed-tests"
for JAR in $JARS; do
checkFile ${JAR_DIR}/${JAR}.jar
diff --git a/tools/cts-instant-tradefed/res/config/retry.xml b/tools/cts-instant-tradefed/res/config/retry.xml
index fe6c6ba..0a01dc3 100644
--- a/tools/cts-instant-tradefed/res/config/retry.xml
+++ b/tools/cts-instant-tradefed/res/config/retry.xml
@@ -13,55 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Runs a retry of a previous CTS instant session.">
- <option name="dynamic-sharding" value="true" />
- <option name="disable-strict-sharding" value="true" />
-
- <device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
- <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
- <test class="com.android.compatibility.common.tradefed.testtype.retry.RetryFactoryTest" />
-
- <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" />
+<configuration description="Runs a retry of a previous CTS session.">
+ <object type="previous_loader" class="com.android.compatibility.common.tradefed.result.suite.PreviousResultLoader" />
+ <test class="com.android.tradefed.testtype.suite.retry.RetryRescheduler" />
<logger class="com.android.tradefed.log.FileLogger">
<option name="log-level-display" value="WARN" />
</logger>
-
- <include name="cts-preconditions" />
- <include name="cts-system-checkers" />
- <include name="cts-known-failures" />
- <include name="cts-exclude" />
-
- <!-- Test instant apps only for the primary API -->
- <option name="compatibility:primary-abi-only" value="true" />
-
- <!-- Include cts-instant setup -->
- <include name="cts-instant-option-setup" />
- <!-- Do not include cts-instant-filter-setup. Otherwise retry includes all instant tests. -->
-
- <option name="plan" value="cts-instant-retry" />
- <option name="test-tag" value="cts-instant" />
- <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>
-
- <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" />
-
- <!-- Include additional test metadata output. -->
- <template-include name="metadata-reporters" default="empty" />
-
</configuration>
diff --git a/tools/cts-instant-tradefed/tests/Android.bp b/tools/cts-instant-tradefed/tests/Android.bp
new file mode 100644
index 0000000..e70c85a
--- /dev/null
+++ b/tools/cts-instant-tradefed/tests/Android.bp
@@ -0,0 +1,24 @@
+// 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.
+
+java_test_host {
+ name: "cts-instant-tradefed-tests",
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "tradefed",
+ "cts-instant-tradefed",
+ ],
+}
diff --git a/tools/cts-instant-tradefed/tests/Android.mk b/tools/cts-instant-tradefed/tests/Android.mk
deleted file mode 100644
index f3b76a6..0000000
--- a/tools/cts-instant-tradefed/tests/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := cts-instant-tradefed-tests
-LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed cts-instant-tradefed
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-instant-tradefed/tests/run_tests.sh b/tools/cts-instant-tradefed/tests/run_tests.sh
deleted file mode 100755
index 5ef31fc..0000000
--- a/tools/cts-instant-tradefed/tests/run_tests.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-# 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.
-
-# Helper script for running unit tests for compatibility libraries
-
-# TODO: Change it to the new harness repo once harness code is moved
-# to a new repo.
-CTS_DIR=$(dirname ${0})/../../..
-source ${CTS_DIR}/test_defs.sh
-
-JARS="
- compatibility-common-util-hostsidelib\
- compatibility-host-util\
- cts-instant-tradefed-tests\
- cts-instant-tradefed"
-
-run_tests "com.android.compatibility.tradefed.CtsInstantTradefedTest" "${JARS}" "${@}"
diff --git a/tools/cts-tradefed/Android.bp b/tools/cts-tradefed/Android.bp
new file mode 100644
index 0000000..b11f164
--- /dev/null
+++ b/tools/cts-tradefed/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2015 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.
+
+java_library_host {
+ name: "cts-tradefed-harness",
+
+ java_resource_dirs: ["res"],
+ libs: [
+ "tradefed",
+ "compatibility-host-util",
+ ],
+ static_libs: [
+ "compatibility-tradefed",
+ ],
+}
+
+tradefed_binary_host {
+ name: "cts-tradefed",
+ wrapper: "etc/cts-tradefed",
+ short_name: "CTS",
+ full_name: "Compatibility Test Suite",
+ version: "10_r1",
+ static_libs: ["cts-tradefed-harness"],
+ required: ["compatibility-host-util"],
+}
diff --git a/tools/cts-tradefed/Android.mk b/tools/cts-tradefed/Android.mk
deleted file mode 100644
index 62fc414..0000000
--- a/tools/cts-tradefed/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, ../../common/host-side/tradefed/src)
-
-LOCAL_JAVA_RESOURCE_DIRS := res
-LOCAL_JAVA_RESOURCE_DIRS += ../../common/host-side/tradefed/res
-LOCAL_MODULE := cts-tradefed-harness
-LOCAL_JAVA_LIBRARIES += tradefed compatibility-host-util
-LOCAL_STATIC_JAVA_LIBRARIES := google-api-java-client-min-repackaged
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SUITE_BUILD_NUMBER := $(BUILD_NUMBER_FROM_FILE)
-LOCAL_SUITE_TARGET_ARCH := $(TARGET_ARCH)
-LOCAL_SUITE_NAME := CTS
-LOCAL_SUITE_FULLNAME := "Compatibility Test Suite"
-LOCAL_SUITE_VERSION := 9.0_r1
-LOCAL_STATIC_JAVA_LIBRARIES += cts-tradefed-harness
-
-LOCAL_MODULE := cts-tradefed
-LOCAL_COMPATIBILITY_SUITE := general-tests
-include cts/error_prone_rules.mk
-include $(BUILD_COMPATIBILITY_SUITE)
-
-# Build all sub-directories
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/cts-tradefed/DynamicConfig.xml b/tools/cts-tradefed/DynamicConfig.xml
index 009e2aa..60b0e98 100644
--- a/tools/cts-tradefed/DynamicConfig.xml
+++ b/tools/cts-tradefed/DynamicConfig.xml
@@ -13,6 +13,7 @@
limitations under the License.
-->
+<!--TODO(b/117957288): Remove dynamic config from suite-level.-->
<dynamicConfig>
<entry key="media_files_url">
<value>https://dl.google.com/dl/android/cts/android-cts-media-1.4.zip</value>
diff --git a/tools/cts-tradefed/etc/Android.mk b/tools/cts-tradefed/etc/Android.mk
deleted file mode 100644
index 1c376db..0000000
--- a/tools/cts-tradefed/etc/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PREBUILT_EXECUTABLES := cts-tradefed
-include $(BUILD_HOST_PREBUILT)
-
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index 5b70020..80f9c33 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -93,8 +93,7 @@
cts-tradefed
cts-tradefed-tests
compatibility-common-util-tests
- compatibility-tradefed-tests
- host-libprotobuf-java-full"
+ compatibility-tradefed-tests"
for JAR in $JARS; do
checkFile ${JAR_DIR}/${JAR}.jar
@@ -107,9 +106,12 @@
google-tradefed-tests
google-tf-prod-tests"
+STANDALONE_JAR_DIR=${ANDROID_HOST_OUT}/framework
for JAR in $OPTIONAL_JARS; do
if [ -f "${JAR_DIR}/${JAR}.jar" ]; then
JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
+ elif [ -f "${STANDALONE_JAR_DIR}/${JAR}.jar" ]; then
+ JAR_PATH=${JAR_PATH}:${STANDALONE_JAR_DIR}/${JAR}.jar
fi;
done
@@ -128,5 +130,5 @@
JAR_PATH=${JAR_PATH}:$j
done
-java $RDBG_FLAG -Xmx4g -XX:+HeapDumpOnOutOfMemoryError -cp ${JAR_PATH} -DCTS_ROOT=${CTS_ROOT} com.android.compatibility.common.tradefed.command.CompatibilityConsole "$@"
+java $RDBG_FLAG -Xmx6g -XX:+HeapDumpOnOutOfMemoryError -cp ${JAR_PATH} -DCTS_ROOT=${CTS_ROOT} com.android.compatibility.common.tradefed.command.CompatibilityConsole "$@"
diff --git a/tools/cts-tradefed/res/config/cts-common.xml b/tools/cts-tradefed/res/config/cts-common.xml
index 7fd0de0..cbd4741 100644
--- a/tools/cts-tradefed/res/config/cts-common.xml
+++ b/tools/cts-tradefed/res/config/cts-common.xml
@@ -17,6 +17,8 @@
<include name="everything" />
<option name="compatibility:run-suite-tag" value="cts" />
+ <!-- Enable module parameterization to run instant_app modules in main CTS -->
+ <option name="compatibility:enable-parameterized-modules" value="true" />
<include name="cts-preconditions" />
<include name="cts-system-checkers" />
<include name="cts-known-failures" />
diff --git a/tools/cts-tradefed/res/config/cts-dev.xml b/tools/cts-tradefed/res/config/cts-dev.xml
index 4ebda1b..11c1052 100644
--- a/tools/cts-tradefed/res/config/cts-dev.xml
+++ b/tools/cts-tradefed/res/config/cts-dev.xml
@@ -25,5 +25,7 @@
<option name="plan" value="cts-dev" />
<option name="compatibility:skip-all-system-status-check" value="true" />
<option name="compatibility:primary-abi-only" value="true" />
+ <!-- Avoid module parameterization in cts-dev -->
+ <option name="compatibility:enable-parameterized-modules" value="false" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-exclude.xml b/tools/cts-tradefed/res/config/cts-exclude.xml
index 240ffa1..f6899a4 100644
--- a/tools/cts-tradefed/res/config/cts-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-exclude.xml
@@ -18,4 +18,16 @@
<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" />
+
+ <!-- Test Harness Mode tests are not a part of CTS. They are a part
+ of their own testing plan, as they reset the device during the
+ test. It's possible and ideal in the future to incorporate the
+ tests into CTS, but until then, they should be excluded. -->
+ <option name="compatibility:exclude-filter" value="CtsTestHarnessModeTestCases" />
+
+ <!-- Exclude downstreaming tests from CTS, i.e. tests added after the
+ first major release for this API level (They are pulled into GTS
+ instead). -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:com.android.compatibility.common.util.CtsDownstreamingTest" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:com.android.compatibility.common.util.CtsDownstreamingTest" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-instant-filter-setup.xml b/tools/cts-tradefed/res/config/cts-instant-filter-setup.xml
index abbe6f9..f706ed4 100644
--- a/tools/cts-tradefed/res/config/cts-instant-filter-setup.xml
+++ b/tools/cts-tradefed/res/config/cts-instant-filter-setup.xml
@@ -156,7 +156,7 @@
<!-- CtsUiAutomationTestCases -->
<option name="compatibility:include-filter" value="CtsUiAutomationTestCases" />
- <!-- CtsActivityManagerDeviceSdk25TestCases -->
+ <!-- CtsWindowManagerSdk25TestCases -->
<!-- These tests require targeting API 25 which does not support instant apps -->
<!-- CtsHostsideWebViewTests -->
@@ -174,9 +174,6 @@
<!-- CtsUsageStatsTestCases -->
<option name="compatibility:include-filter" value="CtsUsageStatsTestCases" />
- <!-- CtsActivityManagerDeviceTestCases -->
- <!-- This module needs a permission not available to instant apps -->
-
<!-- CtsLocationTestCases -->
<option name="compatibility:include-filter" value="CtsLocationTestCases" />
diff --git a/tools/cts-tradefed/res/config/cts-instant-option-setup.xml b/tools/cts-tradefed/res/config/cts-instant-option-setup.xml
index 8db665a..2beaa51 100644
--- a/tools/cts-tradefed/res/config/cts-instant-option-setup.xml
+++ b/tools/cts-tradefed/res/config/cts-instant-option-setup.xml
@@ -157,7 +157,7 @@
<!-- CtsUiAutomationTestCases -->
<option name="compatibility:module-arg" value="CtsUiAutomationTestCases:instant-mode:true" />
- <!-- CtsActivityManagerDeviceSdk25TestCases -->
+ <!-- CtsWindowManagerSdk25TestCases -->
<!-- These tests require targeting API 25 which does not support instant apps -->
<!-- CtsHostsideWebViewTests -->
@@ -175,9 +175,6 @@
<!-- CtsUsageStatsTestCases -->
<option name="compatibility:module-arg" value="CtsUsageStatsTestCases:instant-mode:true" />
- <!-- CtsActivityManagerDeviceTestCases -->
- <!-- This module needs a permission not available to instant apps -->
-
<!-- CtsLocationTestCases -->
<option name="compatibility:module-arg" value="CtsLocationTestCases:instant-mode:true" />
@@ -197,6 +194,18 @@
<!-- CtsOsHostTestCases -->
<option name="compatibility:module-arg" value="CtsOsHostTestCases:instant-mode:true" />
+ <!-- CtsOmapiTestCases -->
+ <option name="compatibility:module-arg" value="CtsOmapiTestCases:instant-mode:true" />
+
+ <!-- signed-CtsSecureElementAccessControlTestCases1 -->
+ <option name="compatibility:module-arg" value="signed-CtsSecureElementAccessControlTestCases1:instant-mode:true" />
+
+ <!-- signed-CtsSecureElementAccessControlTestCases2 -->
+ <option name="compatibility:module-arg" value="signed-CtsSecureElementAccessControlTestCases2:instant-mode:true" />
+
+ <!-- signed-CtsSecureElementAccessControlTestCases3 -->
+ <option name="compatibility:module-arg" value="signed-CtsSecureElementAccessControlTestCases3:instant-mode:true" />
+
<!-- CtsEdiHostTestCases -->
<!-- Included not for instant-app but to collect the required information for the run -->
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-jvmti.xml b/tools/cts-tradefed/res/config/cts-jvmti.xml
index 6a48d81..ce60582 100644
--- a/tools/cts-tradefed/res/config/cts-jvmti.xml
+++ b/tools/cts-tradefed/res/config/cts-jvmti.xml
@@ -107,6 +107,7 @@
<option name="compatibility:include-filter" value="CtsJvmtiRunTest1941HostTestCases" />
<option name="compatibility:include-filter" value="CtsJvmtiRunTest1942HostTestCases" />
<option name="compatibility:include-filter" value="CtsJvmtiRunTest1943HostTestCases" />
+ <option name="compatibility:include-filter" value="CtsJvmtiRunTest1953HostTestCases" />
<option name="compatibility:include-filter" value="CtsJvmtiTaggingHostTestCases" />
<option name="compatibility:include-filter" value="CtsJvmtiTrackingHostTestCases" />
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 1502bd4..40b195b 100755
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -22,10 +22,6 @@
<!-- b/38182235 -->
<option name="compatibility:exclude-filter" value="CtsLocationTestCases android.location.cts.GnssTtffTests#testTtffWithNetwork" />
- <!-- b/35314835 -->
- <option name="compatibility:exclude-filter" value="CtsActivityManagerDeviceTestCases android.server.am.ActivityManagerPinnedStackTests#testAlwaysFocusablePipActivity" />
- <option name="compatibility:exclude-filter" value="CtsActivityManagerDeviceTestCases android.server.am.ActivityManagerPinnedStackTests#testLaunchIntoPinnedStack" />
-
<!-- b/17989532 -->
<option name="compatibility:exclude-filter" value="CtsCameraTestCases android.hardware.camera2.cts.SurfaceViewPreviewTest#testPreparePerformance" />
@@ -125,29 +121,9 @@
<option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1280x0720" />
<option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1920x1080" />
- <!-- b/37482372 -->
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowHistoryPreservePortraitTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowInOutPortraitTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowInitialHeaderOnBackPortraitTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#multiWindowInnerFragmentInOutPortraitTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#startWithFragmentAndInitTitleMultiWindowPortraitTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowPortraitTest#startWithFragmentNoHeadersMultiWindowPortraitTest" />
-
<!-- b/63916274 -->
<option name="compatibility:exclude-filter" value="CtsTelecomTestCases android.telecom.cts.WiredHeadsetTest" />
- <!-- b/38177396 -->
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowLandscapeTest#multiWindowHistoryPreserveLandscapeTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowLandscapeTest#multiWindowInOutLandscapeTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowLandscapeTest#multiWindowInitialHeaderOnBackLandscapeTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowLandscapeTest#multiWindowInnerFragmentInOutLandscapeTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowLandscapeTest#startWithFragmentAndInitTitleMultiWindowLandscapeTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityFlowLandscapeTest#startWithFragmentNoHeadersMultiWindowLandscapeTest" />
-
- <!-- b/62924649 -->
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityLegacyFlowTest#legacyActivityMultiWindowTest" />
- <option name="compatibility:exclude-filter" value="CtsPreference2TestCases android.preference2.cts.PreferenceActivityLegacyFlowTest#legacyActivityMultiWindowToggleTest" />
-
<!-- b/38224690 -->
<option name="compatibility:exclude-filter" value="CtsMediaTestCases android.media.cts.NativeEncoderTest" />
@@ -205,14 +181,31 @@
<!-- b/80309889 -->
<option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.atom.UidAtomTests#testCpuActiveTime" />
+ <!-- b/132274449 -->
+ <option name="compatibility:exclude-filter" value="CtsStatsdHostTestCases android.cts.statsd.validation.BatteryStatsValidationTests#testConnectivityStateChange" />
+
<!-- b/110354076 -->
<option name="compatibility:exclude-filter" value="CtsDevicePolicyManagerTestCases com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_DontSkipSetupWizard" />
- <!-- b/112125308 -->
- <option name="compatibility:exclude-filter" value="CtsActivityManagerDeviceTestCases android.server.am.ActivityManagerActivityVisibilityTests#testTurnScreenOnAttrNoLockScreen" />
+ <!-- b/123280814 -->
+ <option name="compatibility:exclude-filter" value="CtsLocation2TestCases android.location2.cts.LocationManagerTest#testGetCoarseLocationUpdates_withListener" />
+ <option name="compatibility:exclude-filter" value="CtsLocation2TestCases android.location2.cts.LocationManagerTest#testGetNetworkProviderLocationUpdates_withListener" />
- <!-- b/112688380 -->
- <option name="compatibility:exclude-filter" value="CtsActivityManagerDeviceTestCases android.server.am.ActivityManagerAppConfigurationTests#testAppOrientationRequestConfigClears" />
- <option name="compatibility:exclude-filter" value="CtsActivityManagerDeviceTestCases android.server.am.ActivityManagerAppConfigurationTests#testTaskCloseRestoreFreeOrientation" />
+ <!-- b/116002979 -->
+ <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.ListeningPortsTest" />
+
+ <!-- b/117107760 -->
+ <option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testDismissDialog" />
+ <option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testLaunchAnyway" />
+ <option name="compatibility:exclude-filter" value="CtsHarmfulAppWarningHostTestCases android.harmfulappwarning.cts.HarmfulAppWarningTest#testUninstall" />
+
+ <!-- b/119312212 -->
+ <option name="compatibility:exclude-filter" value="CtsAngleIntegrationHostTestCases android.angle.cts.CtsAngleDebugOptionHostTest#testDebugOptionOn" />
+
+ <!-- b/129859594 -->
+ <option name="compatibility:exclude-filter" value="CtsAtomicInstallTestCases com.android.tests.atomicinstall.AtomicInstallTest#testFailInconsistentMultiPackageCommit" />
+
+ <!-- b/126548816 -->
+ <option name="compatibility:exclude-filter" value="CtsRcsTestCases" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-suite-automated.xml b/tools/cts-tradefed/res/config/cts-suite-automated.xml
deleted file mode 100644
index 68d450f..0000000
--- a/tools/cts-tradefed/res/config/cts-suite-automated.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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="Runs CTS with common options set for an automated run on userdebug/eng builds">
-
- <include name="cts-suite" />
-
- <option name="plan" value="cts-suite" />
-
- <option name="skip-preconditions" value="false" />
-
- <!-- 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" />
-
- <!-- Tell all HostTests to exclude certain annotations -->
- <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
- <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:android.platform.test.annotations.RestrictedBuildTest" />
-
-</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-suite-virtual-device.xml b/tools/cts-tradefed/res/config/cts-suite-virtual-device.xml
deleted file mode 100644
index 822ffe1..0000000
--- a/tools/cts-tradefed/res/config/cts-suite-virtual-device.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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="Runs CTS with common options set for an automated run on userdebug/eng builds, and per module rules suitable for virtual devices">
-
- <include name="cts-suite-automated" />
-
- <!-- add per module rules for virtual devices below -->
- <option name="compatibility:module-arg" value="CtsDevicePolicyManagerTestCases:exclude-annotation:android.platform.test.annotations.RequiresDevice" />
- <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-GLES2.functional.prerequisite#*" />
- <option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-EGL.*" />
- <option name="compatibility:module-arg" value="CtsLibcoreTestCases:core-expectation:/virtualdeviceknownfailures.txt" />
-</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-suite.xml b/tools/cts-tradefed/res/config/cts-suite.xml
deleted file mode 100644
index f04b25b..0000000
--- a/tools/cts-tradefed/res/config/cts-suite.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?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="Runs CTS as a suite">
- <!-- running config -->
- <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
- <test class="com.android.compatibility.common.tradefed.testtype.suite.CompatibilityTestSuite">
- <option name="run-suite-tag" value="cts" />
- </test>
-
- <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>
- <!-- setup configs -->
- <include name="cts-preconditions" />
- <include name="cts-system-checkers" />
- <include name="cts-known-failures" />
- <include name="cts-exclude" />
- <include name="cts-exclude-instant" />
-
- <option name="plan" value="cts-suite" />
- <option name="test-tag" value="cts-suite" />
-
- <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" />
-
- <result_reporter class="com.android.compatibility.common.tradefed.result.ConsoleReporter" />
- <result_reporter class="com.android.compatibility.common.tradefed.result.ResultReporter" />
- <result_reporter class="com.android.compatibility.common.tradefed.result.suite.CertificationSuiteResultReporter">
- <!-- Avoid double posting from this reporter until ResultReporter is removed -->
- <option name="disable-result-posting" value="true" />
- </result_reporter>
-
-</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-system-checkers.xml b/tools/cts-tradefed/res/config/cts-system-checkers.xml
index 62744bf..7639bf9 100644
--- a/tools/cts-tradefed/res/config/cts-system-checkers.xml
+++ b/tools/cts-tradefed/res/config/cts-system-checkers.xml
@@ -16,7 +16,15 @@
<configuration description="CTS system checker configs">
<system_checker class="com.android.tradefed.suite.checker.UserChecker" />
<system_checker class="com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.ShellStatusChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.EnforcedSeLinuxChecker">
+ <!-- We expect selinux enforced for CTS -->
+ <option name="expect-enforced" value="true" />
+ </system_checker>
<system_checker class="com.android.tradefed.suite.checker.KeyguardStatusChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.LeakedThreadStatusChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.TimeStatusChecker" />
+ <system_checker class="com.android.tradefed.suite.checker.DeviceSettingChecker" />
<system_checker class="com.android.tradefed.suite.checker.SystemServerStatusChecker" />
<system_checker class="com.android.tradefed.suite.checker.SystemServerFileDescriptorChecker" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-virtual-device.xml b/tools/cts-tradefed/res/config/cts-virtual-device.xml
index 10945f0..697ee2f 100644
--- a/tools/cts-tradefed/res/config/cts-virtual-device.xml
+++ b/tools/cts-tradefed/res/config/cts-virtual-device.xml
@@ -17,9 +17,20 @@
<include name="cts-automated" />
+ <!-- Tell all AndroidJUnitTests to exclude certain annotations -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.support.test.filters.RequiresDevice" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:androidx.test.filters.RequiresDevice" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:exclude-annotation:android.platform.test.annotations.RequiresDevice" />
+
+ <!-- Tell all HostTests to exclude certain annotations -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:exclude-annotation:android.platform.test.annotations.RequiresDevice" />
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:exclude-annotation:android.platform.test.annotations.RequiresDevice" />
+
<!-- add per module rules for virtual devices below -->
- <option name="compatibility:module-arg" value="CtsDevicePolicyManagerTestCases:exclude-annotation:android.platform.test.annotations.RequiresDevice" />
<option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-GLES2.functional.prerequisite#*" />
<option name="compatibility:module-arg" value="CtsDeqpTestCases:include-filter:dEQP-EGL.*" />
<option name="compatibility:module-arg" value="CtsLibcoreTestCases:core-expectation:/virtualdeviceknownfailures.txt" />
+
+ <!-- Virtual devices usually run as root -->
+ <option name="compatibility:skip-system-status-check" value="com.android.tradefed.suite.checker.ShellStatusChecker" />
</configuration>
diff --git a/tools/cts-tradefed/res/config/retry.xml b/tools/cts-tradefed/res/config/retry.xml
index 76d5ba9..0a01dc3 100644
--- a/tools/cts-tradefed/res/config/retry.xml
+++ b/tools/cts-tradefed/res/config/retry.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
@@ -14,48 +14,10 @@
limitations under the License.
-->
<configuration description="Runs a retry of a previous CTS session.">
- <option name="dynamic-sharding" value="true" />
- <option name="disable-strict-sharding" value="true" />
-
- <device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
- <build_provider class="com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider" />
- <test class="com.android.compatibility.common.tradefed.testtype.retry.RetryFactoryTest" />
-
- <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" />
+ <object type="previous_loader" class="com.android.compatibility.common.tradefed.result.suite.PreviousResultLoader" />
+ <test class="com.android.tradefed.testtype.suite.retry.RetryRescheduler" />
<logger class="com.android.tradefed.log.FileLogger">
<option name="log-level-display" value="WARN" />
</logger>
-
- <include name="cts-preconditions" />
- <include name="cts-system-checkers" />
- <include name="cts-known-failures" />
- <include name="cts-exclude" />
- <include name="cts-exclude-instant" />
-
- <option name="plan" value="cts-retry" />
- <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>
-
- <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" />
-
- <!-- Include additional test metadata output. -->
- <template-include name="metadata-reporters" default="empty" />
-
</configuration>
diff --git a/tools/cts-tradefed/tests/Android.bp b/tools/cts-tradefed/tests/Android.bp
new file mode 100644
index 0000000..0d0bcea
--- /dev/null
+++ b/tools/cts-tradefed/tests/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2015 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.
+
+java_library_host {
+ name: "cts-tradefed-tests",
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "tradefed",
+ "cts-tradefed",
+ ],
+ // We ship the Deqp Runner tests with the CTS one to validate them.
+ static_libs: ["CtsDeqpRunnerTests"],
+}
diff --git a/tools/cts-tradefed/tests/Android.mk b/tools/cts-tradefed/tests/Android.mk
deleted file mode 100644
index 2a391c0..0000000
--- a/tools/cts-tradefed/tests/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2015 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_MODULE := cts-tradefed-tests
-LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed cts-tradefed
-# We ship the Deqp Runner tests with the CTS one to validate them.
-LOCAL_STATIC_JAVA_LIBRARIES := CtsDeqpRunnerTests
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-tradefed/tests/run_cts_tests.sh b/tools/cts-tradefed/tests/run_cts_tests.sh
new file mode 100755
index 0000000..428b9ec
--- /dev/null
+++ b/tools/cts-tradefed/tests/run_cts_tests.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# 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.
+
+# A simple helper script that runs the CTS harness unit tests
+
+CTS_DIR=`dirname $0`/../etc
+
+${CTS_DIR}/cts-tradefed run singleCommand host -n \
+ --console-result-reporter:suppress-passed-tests \
+ --class com.android.compatibility.common.tradefed.UnitTests \
+ --class com.android.compatibility.common.util.HostUnitTests \
+ --class com.android.compatibility.common.util.UnitTests \
+ --class com.android.compatibility.tradefed.CtsTradefedTest \
+ --class com.drawelements.deqp.runner.DeqpTestRunnerTest \
+ "$@"
diff --git a/tools/cts-tradefed/tests/run_tests.sh b/tools/cts-tradefed/tests/run_tests.sh
deleted file mode 100755
index 610d157..0000000
--- a/tools/cts-tradefed/tests/run_tests.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2015 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.
-
-# Helper script for running unit tests for compatibility libraries
-
-HARNESS_DIR=$(dirname ${0})/../../..
-source ${HARNESS_DIR}/test_defs.sh
-
-JARS="
- compatibility-common-util-hostsidelib\
- compatibility-host-util\
- cts-tradefed-tests\
- cts-tradefed"
-
-run_tests "com.android.compatibility.tradefed.CtsTradefedTest" "${JARS}" "${@}"
diff --git a/tools/dex-tools/Android.bp b/tools/dex-tools/Android.bp
new file mode 100644
index 0000000..d8c1148
--- /dev/null
+++ b/tools/dex-tools/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 2008 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.
+
+// dex-tools java library
+// ============================================================
+java_library_host {
+ name: "dex-tools",
+
+ srcs: ["src/**/*.java"],
+
+ libs: ["dx"],
+}
diff --git a/tools/dex-tools/Android.mk b/tools/dex-tools/Android.mk
deleted file mode 100644
index fa5a566..0000000
--- a/tools/dex-tools/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2008 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.
-
-LOCAL_PATH := $(call my-dir)
-
-# dex-tools java library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-
-LOCAL_MODULE := dex-tools
-LOCAL_JAVA_LIBRARIES := dx
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-