diff --git a/src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/AndroidInstrumentationTestRetryProcessor.java b/src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/AndroidInstrumentationTestRetryProcessor.java
index 5eb5b28e2c..f484356e0b 100644
--- a/src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/AndroidInstrumentationTestRetryProcessor.java
+++ b/src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/AndroidInstrumentationTestRetryProcessor.java
@@ -24,11 +24,11 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
-import com.google.devtools.mobileharness.platform.android.instrumentation.result.TestSuiteResultLoader;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestCase;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestResult;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestStatus;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestSuiteResult;
+import com.google.devtools.mobileharness.shared.util.testresult.loader.TestSuiteResultLoader;
import com.google.wireless.qa.mobileharness.shared.constant.PropertyName.Test;
import com.google.wireless.qa.mobileharness.shared.model.job.TestInfo;
import java.util.Optional;
diff --git a/src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/BUILD b/src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/BUILD
index 486d1d415d..cecb281264 100644
--- a/src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/BUILD
+++ b/src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/BUILD
@@ -40,8 +40,8 @@ java_library(
deps = [
"//src/devtools/mobileharness/api/model/proto:test_java_proto",
"//src/devtools/mobileharness/platform/android/instrumentation/result/proto:test_suite_result_java_proto",
- "//src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result:test_suite_result_loader",
"//src/java/com/google/devtools/mobileharness/shared/util/logging:google_logger",
+ "//src/java/com/google/devtools/mobileharness/shared/util/testresult/loader",
"//src/java/com/google/wireless/qa/mobileharness/shared/constant:property",
"//src/java/com/google/wireless/qa/mobileharness/shared/model/job",
"@maven//:com_google_guava_guava",
diff --git a/src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result/BUILD b/src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result/BUILD
index 886485d302..5a5bf47f41 100644
--- a/src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result/BUILD
+++ b/src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result/BUILD
@@ -36,18 +36,3 @@ java_library(
"@protobuf//:protobuf_java_util",
],
)
-
-java_library(
- name = "test_suite_result_loader",
- srcs = ["TestSuiteResultLoader.java"],
- deps = [
- "//src/devtools/mobileharness/platform/android/instrumentation/result/proto:test_suite_result_java_proto",
- "//src/java/com/google/devtools/mobileharness/api/model/error",
- "//src/java/com/google/devtools/mobileharness/shared/util/file/local",
- "//src/java/com/google/devtools/mobileharness/shared/util/logging:google_logger",
- "//src/java/com/google/devtools/mobileharness/shared/util/path",
- "//src/java/com/google/wireless/qa/mobileharness/shared/model/job",
- "@maven//:com_google_guava_guava",
- "@protobuf//:protobuf_java",
- ],
-)
diff --git a/src/java/com/google/devtools/mobileharness/shared/util/testresult/loader/BUILD b/src/java/com/google/devtools/mobileharness/shared/util/testresult/loader/BUILD
new file mode 100644
index 0000000000..6124b71cb1
--- /dev/null
+++ b/src/java/com/google/devtools/mobileharness/shared/util/testresult/loader/BUILD
@@ -0,0 +1,38 @@
+# Copyright 2022 Google LLC
+#
+# 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
+#
+# https://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.
+#
+
+load("@rules_java//java:java_library.bzl", "java_library")
+
+package(
+ default_applicable_licenses = ["//:license"],
+ default_visibility = [
+ "//:deviceinfra_all_pkg",
+ ],
+)
+
+java_library(
+ name = "loader",
+ srcs = ["TestSuiteResultLoader.java"],
+ deps = [
+ "//src/devtools/mobileharness/platform/android/instrumentation/result/proto:test_suite_result_java_proto",
+ "//src/java/com/google/devtools/mobileharness/api/model/error",
+ "//src/java/com/google/devtools/mobileharness/shared/util/file/local",
+ "//src/java/com/google/devtools/mobileharness/shared/util/logging:google_logger",
+ "//src/java/com/google/devtools/mobileharness/shared/util/path",
+ "//src/java/com/google/wireless/qa/mobileharness/shared/model/job",
+ "@maven//:com_google_guava_guava",
+ "@protobuf//:protobuf_java",
+ ],
+)
diff --git a/src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result/TestSuiteResultLoader.java b/src/java/com/google/devtools/mobileharness/shared/util/testresult/loader/TestSuiteResultLoader.java
similarity index 57%
rename from src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result/TestSuiteResultLoader.java
rename to src/java/com/google/devtools/mobileharness/shared/util/testresult/loader/TestSuiteResultLoader.java
index 69a826b36b..fdc438d8b7 100644
--- a/src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result/TestSuiteResultLoader.java
+++ b/src/java/com/google/devtools/mobileharness/shared/util/testresult/loader/TestSuiteResultLoader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.devtools.mobileharness.platform.android.instrumentation.result;
+package com.google.devtools.mobileharness.shared.util.testresult.loader;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.flogger.FluentLogger;
@@ -27,11 +27,14 @@
import com.google.wireless.qa.mobileharness.shared.model.job.TestInfo;
import java.util.Optional;
-/** Loader for Android instrumentation test result. */
+/** Loader for test suite result across platforms (Android and iOS). */
public class TestSuiteResultLoader {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private static final String ANDROID_RESULT_FILE_NAME = "instrument_test_result.pb";
+ private static final String IOS_RESULT_FILE_NAME = "xctest_test_result.pb";
+
private final LocalFileUtil localFileUtil;
public TestSuiteResultLoader() {
@@ -39,25 +42,50 @@ public TestSuiteResultLoader() {
}
@VisibleForTesting
- TestSuiteResultLoader(LocalFileUtil localFileUtil) {
+ public TestSuiteResultLoader(LocalFileUtil localFileUtil) {
this.localFileUtil = localFileUtil;
}
+ /**
+ * Loads test result from the gen file directory of the test.
+ *
+ *
It first tries to load from {@code instrument_test_result.pb} (Android), and if not found,
+ * falls back to {@code xctest_test_result.pb} (iOS).
+ */
public Optional loadTestResult(TestInfo testInfo) {
try {
String genFileDir = testInfo.getGenFileDir();
- String pbPath = PathUtil.join(genFileDir, "instrument_test_result.pb");
+
+ // Try loading Android result file first
+ Optional androidResult =
+ loadFromFile(testInfo, genFileDir, ANDROID_RESULT_FILE_NAME);
+ if (androidResult.isPresent()) {
+ return androidResult;
+ }
+
+ // Fallback to iOS result file
+ return loadFromFile(testInfo, genFileDir, IOS_RESULT_FILE_NAME);
+ } catch (MobileHarnessException e) {
+ logger.atWarning().withCause(e).log(
+ "Failed to get gen file directory for test %s.", testInfo.locator().getId());
+ }
+ return Optional.empty();
+ }
+
+ private Optional loadFromFile(
+ TestInfo testInfo, String genFileDir, String fileName) {
+ try {
+ String pbPath = PathUtil.join(genFileDir, fileName);
if (localFileUtil.isFileExist(pbPath)) {
byte[] bytes = localFileUtil.readBinaryFile(pbPath);
return Optional.of(
TestSuiteResult.parseFrom(bytes, ExtensionRegistryLite.getEmptyRegistry()));
} else {
- logger.atInfo().log(
- "No instrument_test_result.pb found for test %s.", testInfo.locator().getId());
+ logger.atInfo().log("No %s found for test %s.", fileName, testInfo.locator().getId());
}
} catch (InvalidProtocolBufferException | MobileHarnessException e) {
logger.atWarning().withCause(e).log(
- "Failed to load test result for test %s.", testInfo.locator().getId());
+ "Failed to load test result from %s for test %s.", fileName, testInfo.locator().getId());
}
return Optional.empty();
}
diff --git a/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/BUILD b/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/BUILD
index 0dde75a3ae..0038b9afaf 100644
--- a/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/BUILD
+++ b/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/BUILD
@@ -26,24 +26,21 @@ java_library(
name = "job_result_util",
srcs = ["JobResultUtil.java"],
deps = [
- ":android_instrumentation_test_suite_result_converter",
":outcome",
":state",
":test_case",
":test_case_reference",
":test_result",
":test_suite_overview",
+ ":test_suite_result_converter",
"//src/devtools/mobileharness/api/model/proto:test_java_proto",
"//src/devtools/mobileharness/platform/android/instrumentation/result/proto:test_suite_result_java_proto",
- "//src/java/com/google/devtools/mobileharness/api/model/error",
"//src/java/com/google/devtools/mobileharness/api/model/job/out",
"//src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor:retry_tests_grouper",
- "//src/java/com/google/devtools/mobileharness/shared/util/file/local",
"//src/java/com/google/devtools/mobileharness/shared/util/logging:google_logger",
- "//src/java/com/google/devtools/mobileharness/shared/util/path",
+ "//src/java/com/google/devtools/mobileharness/shared/util/testresult/loader",
"//src/java/com/google/wireless/qa/mobileharness/shared/model/job",
"@maven//:com_google_guava_guava",
- "@protobuf//:protobuf_java",
],
)
@@ -117,8 +114,8 @@ java_library(
)
java_library(
- name = "android_instrumentation_test_suite_result_converter",
- srcs = ["AndroidInstrumentationTestSuiteResultConverter.java"],
+ name = "test_suite_result_converter",
+ srcs = ["TestSuiteResultConverter.java"],
deps = [
":outcome",
":stack_trace",
diff --git a/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/JobResultUtil.java b/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/JobResultUtil.java
index 169bb2783a..1384043331 100644
--- a/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/JobResultUtil.java
+++ b/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/JobResultUtil.java
@@ -22,21 +22,19 @@
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.flogger.FluentLogger;
-import com.google.devtools.mobileharness.api.model.error.MobileHarnessException;
import com.google.devtools.mobileharness.api.model.job.out.Result.ResultTypeWithCause;
import com.google.devtools.mobileharness.infra.client.api.controller.job.retry.processor.RetryTestsGrouper;
import com.google.devtools.mobileharness.infra.client.api.controller.job.retry.processor.RetryTestsGrouper.GroupedTests;
import com.google.devtools.mobileharness.infra.client.api.controller.job.retry.processor.RetryTestsGrouper.ShardTestRuns;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestSuiteResult;
-import com.google.devtools.mobileharness.shared.util.file.local.LocalFileUtil;
-import com.google.devtools.mobileharness.shared.util.path.PathUtil;
+import com.google.devtools.mobileharness.shared.util.testresult.loader.TestSuiteResultLoader;
import com.google.devtools.mobileharness.shared.util.testresult.rollup.Outcome.OutcomeSummary;
-import com.google.protobuf.ExtensionRegistryLite;
-import com.google.protobuf.InvalidProtocolBufferException;
import com.google.wireless.qa.mobileharness.shared.model.job.JobInfo;
import com.google.wireless.qa.mobileharness.shared.model.job.TestInfo;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
/** Utility for computing job-level rolled up test results. */
public final class JobResultUtil {
@@ -93,24 +91,14 @@ private static TestResult loadTestResult(TestInfo testInfo) {
State.COMPLETE);
}
- LocalFileUtil localFileUtil = new LocalFileUtil();
- try {
- String genFileDir = testInfo.getGenFileDir();
- String pbPath = PathUtil.join(genFileDir, "instrument_test_result.pb");
- if (localFileUtil.isFileExist(pbPath)) {
- byte[] bytes = localFileUtil.readBinaryFile(pbPath);
- TestSuiteResult testSuiteResult =
- TestSuiteResult.parseFrom(bytes, ExtensionRegistryLite.getEmptyRegistry());
- return AndroidInstrumentationTestSuiteResultConverter.toTestResult(testSuiteResult);
- } else {
- logger.atInfo().log(
- "No instrument_test_result.pb found for test %s.", testInfo.locator().getId());
+ TestSuiteResultLoader loader = new TestSuiteResultLoader();
+ Optional testSuiteResultOpt = loader.loadTestResult(testInfo);
+ if (testSuiteResultOpt.isPresent()) {
+ boolean isIos = false;
+ if (testInfo.jobInfo() != null && testInfo.jobInfo().type() != null) {
+ isIos = Objects.equals(testInfo.jobInfo().type().getDriver(), "IosNativeXcTest");
}
- } catch (InvalidProtocolBufferException | MobileHarnessException e) {
- // Fall back to simple TestResult
- logger.atWarning().withCause(e).log(
- "Failed to load test result for test %s, fallback to simple TestResult.",
- testInfo.locator().getId());
+ return TestSuiteResultConverter.toTestResult(testSuiteResultOpt.get(), isIos);
}
return buildFallbackTestResult(testInfo);
}
diff --git a/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/AndroidInstrumentationTestSuiteResultConverter.java b/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/TestSuiteResultConverter.java
similarity index 74%
rename from src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/AndroidInstrumentationTestSuiteResultConverter.java
rename to src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/TestSuiteResultConverter.java
index 97e9fa2623..4cacb33742 100644
--- a/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/AndroidInstrumentationTestSuiteResultConverter.java
+++ b/src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup/TestSuiteResultConverter.java
@@ -17,6 +17,8 @@
package com.google.devtools.mobileharness.shared.util.testresult.rollup;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.Multimaps;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestResult;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestStatus;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestSuiteResult;
@@ -25,17 +27,17 @@
import java.time.Duration;
import java.time.Instant;
-/** Helper converter class for Android Instrumentation test result formats. */
-public final class AndroidInstrumentationTestSuiteResultConverter {
+/** Helper converter class for test suite result formats. */
+public final class TestSuiteResultConverter {
- private AndroidInstrumentationTestSuiteResultConverter() {}
+ private TestSuiteResultConverter() {}
/**
* Converts a {@link TestSuiteResult} to a rollup {@link
* com.google.devtools.mobileharness.shared.util.testresult.rollup.TestResult}.
*/
public static com.google.devtools.mobileharness.shared.util.testresult.rollup.TestResult
- toTestResult(TestSuiteResult testSuiteResult) {
+ toTestResult(TestSuiteResult testSuiteResult, boolean isIos) {
ImmutableList.Builder testCasesBuilder = ImmutableList.builder();
String suiteName =
testSuiteResult.hasTestSuiteMetaData()
@@ -43,14 +45,34 @@ private AndroidInstrumentationTestSuiteResultConverter() {}
: "";
for (TestResult testResult : testSuiteResult.getTestResultList()) {
- testCasesBuilder.add(toTestCase(testResult, suiteName));
+ testCasesBuilder.add(toTestCase(testResult, suiteName, isIos));
}
ImmutableList testCases = testCasesBuilder.build();
- Duration totalElapsed =
- testCases.stream().map(TestCase::elapsedTime).reduce(Duration.ZERO, Duration::plus);
- TestSuiteOverview suiteOverview =
- TestSuiteOverview.builder().setName(suiteName).setElapsedTime(totalElapsed).build();
+
+ ImmutableList testSuiteOverviews;
+ if (isIos) {
+ // Group test cases by their suite name (which is the iOS package name, i.e., target name)
+ // and create an overview for each target.
+ ImmutableListMultimap groupedCases =
+ Multimaps.index(testCases, tc -> tc.testCaseReference().testSuiteName());
+ ImmutableList.Builder overviewsBuilder = ImmutableList.builder();
+ for (String name : groupedCases.keySet()) {
+ Duration targetElapsed =
+ groupedCases.get(name).stream()
+ .map(TestCase::elapsedTime)
+ .reduce(Duration.ZERO, Duration::plus);
+ overviewsBuilder.add(
+ TestSuiteOverview.builder().setName(name).setElapsedTime(targetElapsed).build());
+ }
+ testSuiteOverviews = overviewsBuilder.build();
+ } else {
+ Duration totalElapsed =
+ testCases.stream().map(TestCase::elapsedTime).reduce(Duration.ZERO, Duration::plus);
+ testSuiteOverviews =
+ ImmutableList.of(
+ TestSuiteOverview.builder().setName(suiteName).setElapsedTime(totalElapsed).build());
+ }
OutcomeSummary outcomeSummary =
getOutcomeSummaryFromTestStatus(testSuiteResult.getTestStatus());
@@ -58,11 +80,11 @@ private AndroidInstrumentationTestSuiteResultConverter() {}
State state = State.COMPLETE;
return com.google.devtools.mobileharness.shared.util.testresult.rollup.TestResult.create(
- testCases, ImmutableList.of(suiteOverview), outcome, state);
+ testCases, testSuiteOverviews, outcome, state);
}
- /** Converts an Android Instrumentation test case {@link TestResult} to a {@link TestCase}. */
- public static TestCase toTestCase(TestResult testResult, String suiteName) {
+ /** Converts a test case {@link TestResult} to a {@link TestCase}. */
+ public static TestCase toTestCase(TestResult testResult, String suiteName, boolean isIos) {
com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestCase
instrumentationTestCase = testResult.getTestCase();
@@ -73,11 +95,13 @@ public static TestCase toTestCase(TestResult testResult, String suiteName) {
+ "."
+ instrumentationTestCase.getTestClass();
+ String finalSuiteName = isIos ? instrumentationTestCase.getTestPackage() : suiteName;
+
TestCaseReference testCaseRef =
TestCaseReference.builder()
.setName(instrumentationTestCase.getTestMethod())
.setClassName(className)
- .setTestSuiteName(suiteName)
+ .setTestSuiteName(finalSuiteName)
.build();
TestCase.Builder testCaseBuilder = TestCase.builder().setTestCaseReference(testCaseRef);
diff --git a/src/javatests/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/AndroidInstrumentationTestRetryProcessorTest.java b/src/javatests/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/AndroidInstrumentationTestRetryProcessorTest.java
index 1be1a21dff..19e1116f46 100644
--- a/src/javatests/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/AndroidInstrumentationTestRetryProcessorTest.java
+++ b/src/javatests/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/AndroidInstrumentationTestRetryProcessorTest.java
@@ -21,11 +21,11 @@
import com.google.devtools.mobileharness.api.model.error.BasicErrorId;
import com.google.devtools.mobileharness.api.model.error.MobileHarnessException;
-import com.google.devtools.mobileharness.platform.android.instrumentation.result.TestSuiteResultLoader;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestCase;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestResult;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestStatus;
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestSuiteResult;
+import com.google.devtools.mobileharness.shared.util.testresult.loader.TestSuiteResultLoader;
import com.google.wireless.qa.mobileharness.shared.constant.PropertyName;
import com.google.wireless.qa.mobileharness.shared.model.job.JobInfo;
import com.google.wireless.qa.mobileharness.shared.model.job.JobLocator;
diff --git a/src/javatests/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/BUILD b/src/javatests/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/BUILD
index 8c565ae07a..6391847988 100644
--- a/src/javatests/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/BUILD
+++ b/src/javatests/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor/BUILD
@@ -32,7 +32,7 @@ java_library(
"//src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor:retry_tests_grouper",
"//src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/processor:test_retry_processor",
"//src/java/com/google/devtools/mobileharness/infra/client/api/controller/job/retry/strategy:flaky_test_retry_constants",
- "//src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result:test_suite_result_loader",
+ "//src/java/com/google/devtools/mobileharness/shared/util/testresult/loader",
"//src/java/com/google/wireless/qa/mobileharness/shared/constant:property",
"//src/java/com/google/wireless/qa/mobileharness/shared/model/job",
"//src/java/com/google/wireless/qa/mobileharness/shared/proto:job_java_proto",
diff --git a/src/javatests/com/google/devtools/mobileharness/platform/android/instrumentation/result/BUILD b/src/javatests/com/google/devtools/mobileharness/platform/android/instrumentation/result/BUILD
index 7a76ad3d58..64d43ce9a7 100644
--- a/src/javatests/com/google/devtools/mobileharness/platform/android/instrumentation/result/BUILD
+++ b/src/javatests/com/google/devtools/mobileharness/platform/android/instrumentation/result/BUILD
@@ -33,12 +33,7 @@ java_library(
deps = [
"//src/devtools/mobileharness/platform/android/instrumentation/result/proto:test_suite_result_java_proto",
"//src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result:test_suite_result_converter",
- "//src/java/com/google/devtools/mobileharness/platform/android/instrumentation/result:test_suite_result_loader",
- "//src/java/com/google/devtools/mobileharness/shared/util/file/local",
"//src/java/com/google/devtools/mobileharness/shared/util/junit/xmlwriter/model",
- "//src/java/com/google/devtools/mobileharness/shared/util/path",
- "//src/java/com/google/wireless/qa/mobileharness/shared/model/job",
- "//src/java/com/google/wireless/qa/mobileharness/shared/proto:job_java_proto",
"//src/javatests/com/google/devtools/mobileharness/builddefs:truth",
"//src/javatests/com/google/devtools/mobileharness/shared/util/runfiles:runfiles_util",
"@maven//:com_google_protobuf_protobuf_java",
diff --git a/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/loader/BUILD b/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/loader/BUILD
new file mode 100644
index 0000000000..904f7245e3
--- /dev/null
+++ b/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/loader/BUILD
@@ -0,0 +1,45 @@
+# Copyright 2022 Google LLC
+#
+# 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
+#
+# https://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.
+#
+
+load("@rules_java//java:defs.bzl", "java_library")
+load("//src/javatests/com/google/devtools/mobileharness/builddefs:junit_test_suites.bzl", "junit_test_suites")
+
+package(default_applicable_licenses = ["//:license"])
+
+java_library(
+ name = "loader",
+ testonly = 1,
+ srcs = glob(["*.java"]),
+ deps = [
+ "//src/devtools/mobileharness/platform/android/instrumentation/result/proto:test_suite_result_java_proto",
+ "//src/java/com/google/devtools/mobileharness/shared/util/file/local",
+ "//src/java/com/google/devtools/mobileharness/shared/util/path",
+ "//src/java/com/google/devtools/mobileharness/shared/util/testresult/loader",
+ "//src/java/com/google/wireless/qa/mobileharness/shared/model/job",
+ "//src/java/com/google/wireless/qa/mobileharness/shared/proto:job_java_proto",
+ "//src/javatests/com/google/devtools/mobileharness/builddefs:truth",
+ "@maven//:junit_junit",
+ ],
+)
+
+junit_test_suites(
+ name = "gen_tests",
+ sizes = [
+ "small",
+ ],
+ deps = [
+ ":loader",
+ ],
+)
diff --git a/src/javatests/com/google/devtools/mobileharness/platform/android/instrumentation/result/TestSuiteResultLoaderTest.java b/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/loader/TestSuiteResultLoaderTest.java
similarity index 81%
rename from src/javatests/com/google/devtools/mobileharness/platform/android/instrumentation/result/TestSuiteResultLoaderTest.java
rename to src/javatests/com/google/devtools/mobileharness/shared/util/testresult/loader/TestSuiteResultLoaderTest.java
index 8e213c7b68..25d12319b2 100644
--- a/src/javatests/com/google/devtools/mobileharness/platform/android/instrumentation/result/TestSuiteResultLoaderTest.java
+++ b/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/loader/TestSuiteResultLoaderTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.devtools.mobileharness.platform.android.instrumentation.result;
+package com.google.devtools.mobileharness.shared.util.testresult.loader;
import static com.google.common.truth.Truth.assertThat;
@@ -68,7 +68,7 @@ public void loadTestResult_resultFileDoesNotExist_returnsEmpty() throws Exceptio
}
@Test
- public void loadTestResult_resultFileExists_returnsParsedResult() throws Exception {
+ public void loadTestResult_androidResultFileExists_returnsParsedResult() throws Exception {
String genFileDir = testInfo.getGenFileDir();
TestSuiteResult testSuiteResult =
TestSuiteResult.newBuilder().setTestStatus(TestStatus.PASSED).build();
@@ -83,6 +83,22 @@ public void loadTestResult_resultFileExists_returnsParsedResult() throws Excepti
assertThat(result.get().getTestStatus()).isEqualTo(TestStatus.PASSED);
}
+ @Test
+ public void loadTestResult_iosResultFileExists_returnsParsedResult() throws Exception {
+ String genFileDir = testInfo.getGenFileDir();
+ TestSuiteResult testSuiteResult =
+ TestSuiteResult.newBuilder().setTestStatus(TestStatus.PASSED).build();
+ byte[] testSuiteResultBytes = testSuiteResult.toByteArray();
+
+ String testSuiteResultPbPath = PathUtil.join(genFileDir, "xctest_test_result.pb");
+ realLocalFileUtil.writeToFile(testSuiteResultPbPath, testSuiteResultBytes);
+
+ Optional result = loader.loadTestResult(testInfo);
+
+ assertThat(result).isPresent();
+ assertThat(result.get().getTestStatus()).isEqualTo(TestStatus.PASSED);
+ }
+
@Test
public void loadTestResult_invalidProtoBytes_returnsEmpty() throws Exception {
String genFileDir = testInfo.getGenFileDir();
diff --git a/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/rollup/BUILD b/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/rollup/BUILD
index 263fac9ec1..7fc462f58c 100644
--- a/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/rollup/BUILD
+++ b/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/rollup/BUILD
@@ -38,6 +38,7 @@ java_library(
"//src/java/com/google/devtools/mobileharness/shared/util/testresult/rollup:test_suite_overview_converter",
"//src/java/com/google/wireless/qa/mobileharness/shared/constant:property",
"//src/java/com/google/wireless/qa/mobileharness/shared/model/job",
+ "//src/java/com/google/wireless/qa/mobileharness/shared/proto:job_java_proto",
"//src/javatests/com/google/devtools/mobileharness/builddefs:truth",
"@maven//:com_google_guava_guava",
"@maven//:junit_junit",
diff --git a/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/rollup/JobResultUtilTest.java b/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/rollup/JobResultUtilTest.java
index b46dd749ce..a5565bdf37 100644
--- a/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/rollup/JobResultUtilTest.java
+++ b/src/javatests/com/google/devtools/mobileharness/shared/util/testresult/rollup/JobResultUtilTest.java
@@ -28,10 +28,12 @@
import com.google.devtools.mobileharness.platform.android.instrumentation.result.proto.TestSuiteResult;
import com.google.devtools.mobileharness.shared.util.testresult.rollup.Outcome.OutcomeSummary;
import com.google.protobuf.util.Timestamps;
+import com.google.wireless.qa.mobileharness.shared.constant.PropertyName;
import com.google.wireless.qa.mobileharness.shared.model.job.JobInfo;
import com.google.wireless.qa.mobileharness.shared.model.job.TestInfo;
import com.google.wireless.qa.mobileharness.shared.model.job.out.Properties;
import com.google.wireless.qa.mobileharness.shared.model.job.out.Timing;
+import com.google.wireless.qa.mobileharness.shared.proto.Job.JobType;
import java.io.File;
import java.io.FileOutputStream;
import java.time.Duration;
@@ -714,4 +716,70 @@ private void writeProto(File directory, String filename, TestSuiteResult proto)
.setElapsedTime(Duration.ofSeconds(endTimeSeconds - startTimeSeconds))
.build();
}
+
+ @Test
+ public void computeJobLevelTestResult_ios_success() throws Exception {
+ TestInfo runShard0 =
+ mockIosTestRun(
+ "test_shard_0",
+ "0",
+ com.google.devtools.mobileharness.api.model.proto.Test.TestResult.PASS,
+ /* flakyAttemptIndex= */ 0,
+ /* errorAttemptIndex= */ 0,
+ "com.example.Suite",
+ TestStatus.PASSED,
+ ImmutableList.of(
+ buildTestCaseInfo("MyClass", "testFoo", TestStatus.PASSED, Duration.ofSeconds(5))));
+
+ JobInfo jobInfo = mock(JobInfo.class, Mockito.RETURNS_DEEP_STUBS);
+ when(jobInfo.locator().getId()).thenReturn("job-1");
+ when(jobInfo.tests().getAll().values()).thenReturn(ImmutableList.of(runShard0));
+
+ com.google.devtools.mobileharness.shared.util.testresult.rollup.TestResult result =
+ JobResultUtil.computeJobRunResult(jobInfo);
+
+ assertThat(result.outcome().summary()).isEqualTo(OutcomeSummary.SUCCESS);
+ assertThat(result.testCases()).hasSize(1);
+ // In iOS, the testSuiteName of the test case should be mapped to the package name of the test
+ // case ("com.example")
+ // rather than the overall metadata suite name ("com.example.Suite")
+ assertThat(result.testCases().get(0).testCaseReference().testSuiteName())
+ .isEqualTo("com.example");
+ }
+
+ private TestInfo mockIosTestRun(
+ String shardName,
+ String shardIndex,
+ com.google.devtools.mobileharness.api.model.proto.Test.TestResult mockResult,
+ int flakyAttemptIndex,
+ int errorAttemptIndex,
+ String testSuiteName,
+ TestStatus suiteStatus,
+ ImmutableList cases)
+ throws Exception {
+ TestInfo testInfo = mock(TestInfo.class, Mockito.RETURNS_DEEP_STUBS);
+ File genDir = tempFolder.newFolder();
+ when(testInfo.getGenFileDir()).thenReturn(genDir.getAbsolutePath());
+
+ Properties properties = new Properties(new Timing());
+ properties.add("flaky_attempt_index", String.valueOf(flakyAttemptIndex));
+ properties.add("error_attempt_index", String.valueOf(errorAttemptIndex));
+ if (shardIndex != null) {
+ properties.add(PropertyName.Test.SHARD_INDEX, shardIndex);
+ }
+ when(testInfo.properties()).thenReturn(properties);
+
+ when(testInfo.locator().getName()).thenReturn(shardName);
+ when(testInfo.resultWithCause().get().type()).thenReturn(mockResult);
+
+ JobType jobType = JobType.newBuilder().setDriver("IosNativeXcTest").build();
+ when(testInfo.jobInfo().type()).thenReturn(jobType);
+
+ if (testSuiteName != null) {
+ TestSuiteResult testSuiteResult = buildTestSuiteResult(testSuiteName, suiteStatus, cases);
+ writeProto(genDir, "xctest_test_result.pb", testSuiteResult);
+ }
+
+ return testInfo;
+ }
}