Skip to content

Commit cff3af6

Browse files
j-gaocopybara-github
authored andcommitted
Internal change
PiperOrigin-RevId: 941549876
1 parent c443c7e commit cff3af6

6 files changed

Lines changed: 154 additions & 22 deletions

File tree

src/java/com/google/devtools/mobileharness/platform/android/xts/common/util/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ java_library(
5050
visibility = [
5151
"//src/java/com/google/devtools/mobileharness/infra/ats:__subpackages__",
5252
"//src/java/com/google/devtools/mobileharness/platform/android/xts/suite:__subpackages__",
53+
"//src/java/com/google/wireless/qa/mobileharness/shared/api/decorator:__pkg__",
5354
"//src/java/com/google/wireless/qa/mobileharness/shared/api/driver:__subpackages__",
5455
"//src/javatests/com/google/devtools/mobileharness/infra/ats/console/integration/concord:__pkg__",
5556
"//src/javatests/com/google/devtools/mobileharness/platform/android/xts/common/util:__subpackages__",

src/java/com/google/wireless/qa/mobileharness/shared/api/decorator/AndroidAtsDynamicConfigPusherDecorator.java

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.google.devtools.mobileharness.platform.android.lightning.apkinstaller.ApkInstallArgs;
2929
import com.google.devtools.mobileharness.platform.android.lightning.apkinstaller.ApkInstaller;
3030
import com.google.devtools.mobileharness.platform.android.systemsetting.AndroidSystemSettingUtil;
31+
import com.google.devtools.mobileharness.platform.android.xts.common.util.XtsDirUtil;
3132
import com.google.devtools.mobileharness.platform.android.xts.config.DynamicConfig;
3233
import com.google.devtools.mobileharness.platform.android.xts.config.DynamicConfigHandler;
3334
import com.google.devtools.mobileharness.shared.util.file.local.LocalFileUtil;
@@ -42,14 +43,20 @@
4243
import com.google.wireless.qa.mobileharness.shared.proto.spec.decorator.AndroidAtsDynamicConfigPusherDecoratorSpec.TestTarget;
4344
import java.io.File;
4445
import java.io.IOException;
46+
import java.io.InputStream;
4547
import java.net.URI;
4648
import java.net.URISyntaxException;
4749
import java.net.URL;
50+
import java.nio.file.Files;
51+
import java.nio.file.Path;
52+
import java.nio.file.StandardCopyOption;
4853
import java.util.HashMap;
4954
import java.util.List;
5055
import java.util.Locale;
5156
import java.util.Map;
5257
import java.util.Optional;
58+
import java.util.zip.ZipEntry;
59+
import java.util.zip.ZipFile;
5360
import javax.annotation.Nullable;
5461
import javax.inject.Inject;
5562
import org.xmlpull.v1.XmlPullParserException;
@@ -102,22 +109,25 @@ protected void skippableSetUp(TestInfo testInfo)
102109
AndroidAtsDynamicConfigPusherDecoratorSpec spec =
103110
testInfo.jobInfo().combinedSpec(this, deviceId);
104111

105-
Map<String, String> xtsSuiteInfoMap = xtsSuiteInfoSplitter.split(spec.getXtsSuiteInfo());
112+
Map<String, String> xtsSuiteInfoMap =
113+
spec.getXtsSuiteInfo().isEmpty()
114+
? new HashMap<>()
115+
: xtsSuiteInfoSplitter.split(spec.getXtsSuiteInfo());
106116
String suiteName = xtsSuiteInfoMap.get("suite_name");
107-
if (suiteName == null) {
108-
throw new MobileHarnessException(
109-
AndroidErrorId.ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_INVALID_PARAMETER,
110-
"suite_name is missing from xtsSuiteInfo");
111-
}
112117
String suiteVersion = xtsSuiteInfoMap.getOrDefault("suite_version", "");
113118
if (spec.getConfigFilename().isEmpty()) {
119+
if (suiteName == null) {
120+
throw new MobileHarnessException(
121+
AndroidErrorId.ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_INVALID_PARAMETER,
122+
"suite_name is missing from xtsSuiteInfo");
123+
}
114124
spec = spec.toBuilder().setConfigFilename(Ascii.toLowerCase(suiteName)).build();
115125
}
116126
if (spec.getVersion().isEmpty()) {
117127
spec = spec.toBuilder().setVersion(suiteVersion).build();
118128
}
119129

120-
File localConfigFile = getLocalConfigFile(spec);
130+
File localConfigFile = getLocalConfigFile(spec, suiteName);
121131
String apfeConfig = fetchApfeConfig(spec, xtsSuiteInfoMap);
122132
File hostFile = mergeConfigFiles(spec, localConfigFile, apfeConfig);
123133
if (spec.getTarget().equals(TestTarget.DEVICE)) {
@@ -171,30 +181,66 @@ protected void skippableTearDown(TestInfo testInfo)
171181
}
172182
}
173183

174-
private File getLocalConfigFile(AndroidAtsDynamicConfigPusherDecoratorSpec spec)
184+
/**
185+
* Gets the local config file.
186+
*
187+
* <p>If {@code extractFromResource} is true, it attempts to extract the dynamic config file from
188+
* the suite's tradefed JAR.
189+
*
190+
* <p>If {@code extractFromResource} is false, it searches for the dynamic config file directly in
191+
* the XTS test directory.
192+
*/
193+
private File getLocalConfigFile(
194+
AndroidAtsDynamicConfigPusherDecoratorSpec spec, @Nullable String suiteName)
175195
throws MobileHarnessException {
196+
String lookupName =
197+
spec.getExtractFromResource()
198+
? (spec.getDynamicResourceName().isEmpty()
199+
? spec.getConfigFilename()
200+
: spec.getDynamicResourceName())
201+
: (spec.getDynamicConfigName().isEmpty()
202+
? spec.getConfigFilename()
203+
: spec.getDynamicConfigName());
204+
String fileName = String.format("%s.dynamic", lookupName);
205+
176206
if (spec.getExtractFromResource()) {
207+
if (suiteName != null && !spec.getXtsTestDir().isEmpty()) {
208+
Path xtsRootDir = Path.of(spec.getXtsTestDir()).getParent().getParent();
209+
File toolsDir = XtsDirUtil.getXtsToolsDir(xtsRootDir, suiteName).toFile();
210+
File tradefedJar = new File(toolsDir, Ascii.toLowerCase(suiteName) + "-tradefed.jar");
211+
if (tradefedJar.exists()) {
212+
try (ZipFile zipFile = new ZipFile(tradefedJar)) {
213+
ZipEntry entry = zipFile.getEntry(fileName);
214+
if (entry != null) {
215+
try (InputStream inputStream = zipFile.getInputStream(entry)) {
216+
File localConfigFile = File.createTempFile(lookupName, ".dynamic");
217+
Files.copy(
218+
inputStream, localConfigFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
219+
return localConfigFile;
220+
}
221+
}
222+
} catch (IOException e) {
223+
logger.atWarning().withCause(e).log(
224+
"Failed to read from %s", tradefedJar.getAbsolutePath());
225+
}
226+
}
227+
}
228+
177229
throw new MobileHarnessException(
178-
AndroidErrorId.ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_PARAM_NOT_SUPPORTED,
179-
"Extract from resource is not supported yet.");
230+
AndroidErrorId.ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_LOCAL_CONFIG_NOT_FOUND,
231+
String.format("Fail to find '%s' in tradefed jar", fileName));
180232
}
181233

182-
String lookupName =
183-
String.format(
184-
"%s.dynamic",
185-
spec.getDynamicConfigName().isEmpty()
186-
? spec.getConfigFilename()
187-
: spec.getDynamicConfigName());
188234
List<File> files = localFileUtil.listFiles(spec.getXtsTestDir(), /* recursively= */ true);
189235
return files.stream()
190-
.filter(file -> file.getName().equals(lookupName))
236+
.filter(file -> file.getName().equals(fileName))
191237
.findFirst()
192238
.orElseThrow(
193239
() ->
194240
new MobileHarnessException(
195241
AndroidErrorId
196242
.ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_LOCAL_CONFIG_NOT_FOUND,
197-
String.format("Config file %s not found.", lookupName)));
243+
String.format("Config file %s not found.", fileName)));
198244
}
199245

200246
@Nullable
@@ -204,13 +250,19 @@ private String fetchApfeConfig(
204250
if (!spec.getHasServerSideConfig()) {
205251
return null;
206252
}
253+
String suiteName = xtsSuiteInfoMap.get("suite_name");
254+
if (suiteName == null) {
255+
throw new MobileHarnessException(
256+
AndroidErrorId.ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_INVALID_PARAMETER,
257+
"suite_name is missing from xtsSuiteInfo");
258+
}
207259

208260
try {
209261
// TODO: Support to read URL from UrlReplacement.xml. More context in
210262
// com.android.compatibility.common.util.UrlReplacement.java
211263
String requestUrl =
212264
spec.getConfigUrl()
213-
.replace("{suite-name}", xtsSuiteInfoMap.get("suite_name").toUpperCase(Locale.ROOT))
265+
.replace("{suite-name}", suiteName.toUpperCase(Locale.ROOT))
214266
.replace("{module}", spec.getConfigFilename())
215267
.replace("{version}", spec.getVersion())
216268
.replace("{api-key}", spec.getApiKey());

src/java/com/google/wireless/qa/mobileharness/shared/api/decorator/AndroidFilePullerDecorator.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,20 @@ public void run(TestInfo testInfo) throws MobileHarnessException, InterruptedExc
107107
}
108108
if (removeFilesBeforeTest) {
109109
for (String path : fileOrDirPathsOnDevice) {
110-
androidFileUtil.removeFiles(deviceId, path);
111-
testInfo.log().atInfo().alsoTo(logger).log("Remove file/dir in device: %s", path);
110+
try {
111+
androidFileUtil.removeFiles(deviceId, path);
112+
testInfo.log().atInfo().alsoTo(logger).log("Remove file/dir in device: %s", path);
113+
} catch (MobileHarnessException e) {
114+
testInfo
115+
.log()
116+
.atWarning()
117+
.alsoTo(logger)
118+
.withCause(e)
119+
.log("Failed to remove file/dir %s on device before test.", path);
120+
if (!spec.getIgnoreRemovingFilesError()) {
121+
throw e;
122+
}
123+
}
112124
}
113125
}
114126
boolean ignoreFilesNotExist = true;

src/java/com/google/wireless/qa/mobileharness/shared/api/decorator/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ java_library(
153153
"//src/java/com/google/devtools/mobileharness/platform/android/file:android_file_util",
154154
"//src/java/com/google/devtools/mobileharness/platform/android/lightning/apkinstaller",
155155
"//src/java/com/google/devtools/mobileharness/platform/android/systemsetting:system_setting_util",
156+
"//src/java/com/google/devtools/mobileharness/platform/android/xts/common/util:xts_dir_util",
156157
"//src/java/com/google/devtools/mobileharness/platform/android/xts/config:dynamic_config",
157158
"//src/java/com/google/devtools/mobileharness/platform/android/xts/config:dynamic_config_handler",
158159
"//src/java/com/google/devtools/mobileharness/shared/util/file/local",

src/java/com/google/wireless/qa/mobileharness/shared/proto/spec/decorator/android_file_puller_decorator_spec.proto

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ message AndroidFilePullerDecoratorSpec {
7070
];
7171

7272
map<string, string> property = 7 [(field_detail) = {
73-
help: "Only pull files if the device properties match the specified values. If a property does not match, file pulling is skipped but the test still runs. Map of property key to expected value."
73+
help: "Only pull files if the device properties match the specified values."
74+
" If a property does not match, file pulling is skipped but the test "
75+
"still runs. Map of property key to expected value."
7476
}];
77+
78+
optional bool ignore_removing_files_error = 8 [
79+
default = false,
80+
(field_detail) = {
81+
help: "Whether to ignore errors when removing files on device before "
82+
"the test."
83+
}
84+
];
7585
}

src/javatests/com/google/wireless/qa/mobileharness/shared/api/decorator/AndroidAtsDynamicConfigPusherDecoratorTest.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818

1919
import static com.google.common.truth.Truth.assertThat;
2020
import static java.nio.charset.StandardCharsets.UTF_8;
21+
import static org.junit.Assert.assertThrows;
2122
import static org.mockito.ArgumentMatchers.any;
2223
import static org.mockito.ArgumentMatchers.anyInt;
2324
import static org.mockito.ArgumentMatchers.eq;
2425
import static org.mockito.Mockito.verify;
2526
import static org.mockito.Mockito.when;
2627

28+
import com.google.devtools.mobileharness.api.model.error.MobileHarnessException;
2729
import com.google.devtools.mobileharness.platform.android.file.AndroidFileUtil;
2830
import com.google.devtools.mobileharness.platform.android.lightning.apkinstaller.ApkInstaller;
2931
import com.google.devtools.mobileharness.platform.android.systemsetting.AndroidSystemSettingUtil;
@@ -169,4 +171,58 @@ public void skippableTearDown_success() throws Exception {
169171
verify(androidFileUtil).removeFiles("device_id", "device_path");
170172
verify(apkInstaller).uninstallApk(eq(device), eq("content_provider_pkg"), eq(true), any());
171173
}
174+
175+
@Test
176+
public void skippableSetUp_extractFromResource_resourceNotFound_throwsException()
177+
throws Exception {
178+
spec =
179+
AndroidAtsDynamicConfigPusherDecoratorSpec.newBuilder()
180+
.setExtractFromResource(true)
181+
.setConfigFilename("cts")
182+
.setTarget(TestTarget.DEVICE)
183+
.setCleanup(true)
184+
.build();
185+
when(jobInfo.combinedSpec(
186+
ArgumentMatchers.<SpecConfigable<AndroidAtsDynamicConfigPusherDecoratorSpec>>any(),
187+
eq("device_id")))
188+
.thenReturn(spec);
189+
190+
MobileHarnessException exception =
191+
assertThrows(MobileHarnessException.class, () -> decorator.skippableSetUp(testInfo));
192+
assertThat(exception).hasMessageThat().contains("Fail to find 'cts.dynamic' in tradefed jar");
193+
}
194+
195+
@Test
196+
public void skippableSetUp_emptyXtsSuiteInfo_success() throws Exception {
197+
spec =
198+
AndroidAtsDynamicConfigPusherDecoratorSpec.newBuilder()
199+
.setTarget(TestTarget.DEVICE)
200+
.setCleanup(true)
201+
.setHasServerSideConfig(false)
202+
.setConfigFilename("cts")
203+
.build();
204+
when(jobInfo.combinedSpec(
205+
ArgumentMatchers.<SpecConfigable<AndroidAtsDynamicConfigPusherDecoratorSpec>>any(),
206+
eq("device_id")))
207+
.thenReturn(spec);
208+
209+
when(resUtil.getResourceFile(any(), any())).thenReturn("apk_path");
210+
when(apkInstaller.installApkIfNotExist(any(), any(), any())).thenReturn("content_provider_pkg");
211+
212+
File tempDir = Files.createTempDirectory("test").toFile();
213+
File configFile = new File(tempDir, "cts.dynamic");
214+
configFile.createNewFile();
215+
try (Writer writer = Files.newBufferedWriter(configFile.toPath(), UTF_8)) {
216+
writer.write("<dynamicConfig></dynamicConfig>");
217+
}
218+
configFile.deleteOnExit();
219+
tempDir.deleteOnExit();
220+
List<File> files = new ArrayList<>();
221+
files.add(configFile);
222+
when(localFileUtil.listFiles(any(), eq(true))).thenReturn(files);
223+
224+
decorator.skippableSetUp(testInfo);
225+
226+
verify(androidFileUtil).push(eq("device_id"), anyInt(), any(), any());
227+
}
172228
}

0 commit comments

Comments
 (0)