Add a CTS test to test app compilation.
Bug: 238080180
Test: atest CtsCompilationTestCases:CompilationTest
Change-Id: I4941f026613470f053e1b28abfe32be62699239a
Merged-In: I4941f026613470f053e1b28abfe32be62699239a
(cherry picked from commit 936b937c7fad8a38d43c515cda141fc65e93e447)
diff --git a/hostsidetests/compilation/src/android/compilation/cts/CompilationTest.java b/hostsidetests/compilation/src/android/compilation/cts/CompilationTest.java
new file mode 100644
index 0000000..764562e
--- /dev/null
+++ b/hostsidetests/compilation/src/android/compilation/cts/CompilationTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 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 android.compilation.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.FileUtil;
+
+import com.google.common.io.ByteStreams;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Compilation tests that don't require root access.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CompilationTest extends BaseHostJUnit4Test {
+ private static final String APPLICATION_PACKAGE = "android.compilation.cts";
+
+ private ITestDevice mDevice;
+ private File mCtsCompilationAppApkFile;
+
+ @Before
+ public void setUp() throws Exception {
+ mDevice = getDevice();
+
+ mCtsCompilationAppApkFile = copyResourceToFile(
+ "/CtsCompilationApp.apk", File.createTempFile("CtsCompilationApp", ".apk"));
+ mDevice.uninstallPackage(APPLICATION_PACKAGE); // in case it's still installed
+ String error = mDevice.installPackage(mCtsCompilationAppApkFile, false);
+ assertWithMessage("Got install error: " + error).that(error).isNull();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtil.deleteFile(mCtsCompilationAppApkFile);
+ mDevice.uninstallPackage(APPLICATION_PACKAGE);
+ }
+
+ @Test
+ public void testCompile() throws Exception {
+ assertCommandSucceeds("pm", "compile", "-m", "speed", APPLICATION_PACKAGE);
+ assertThat(getCompilerFilter(APPLICATION_PACKAGE)).isEqualTo("speed");
+ }
+
+ private File copyResourceToFile(String resourceName, File file) throws Exception {
+ try (OutputStream outputStream = new FileOutputStream(file);
+ InputStream inputStream = getClass().getResourceAsStream(resourceName)) {
+ assertThat(ByteStreams.copy(inputStream, outputStream)).isGreaterThan(0);
+ }
+ return file;
+ }
+
+ private String assertCommandSucceeds(String... command) throws DeviceNotAvailableException {
+ CommandResult result = mDevice.executeShellV2Command(String.join(" ", command));
+ assertWithMessage(result.toString()).that(result.getExitCode()).isEqualTo(0);
+ // Remove trailing \n's.
+ return result.getStdout().trim();
+ }
+
+ /**
+ * Returns the compiler filter fo the given package. Only works if the package has one apk file.
+ */
+ private String getCompilerFilter(String packageName) throws DeviceNotAvailableException {
+ String[] dumpsysOutput =
+ assertCommandSucceeds("dumpsys", "package", packageName).split("\n");
+
+ // Matches " x86_64: [status=verify] [reason=first-boot]"
+ Pattern pattern = Pattern.compile("\\[status=(\\w+)\\]");
+
+ String currentSection = null;
+ for (String line : dumpsysOutput) {
+ // A section title has no indent.
+ if (!line.isEmpty() && line.charAt(0) != ' ') {
+ currentSection = line;
+ continue;
+ }
+ if ("Dexopt state:".equals(currentSection)) {
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.find()) {
+ return matcher.group(1);
+ }
+ }
+ }
+ fail("No occurrence of compiler filter in: " + Arrays.toString(dumpsysOutput));
+ return null;
+ }
+}