diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2020-04-04 06:46:31 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-04-04 06:46:31 +0000 |
commit | 77e890265d3a9c66ecaccf252ec989f5490f6ad8 (patch) | |
tree | 797f602756e6c828aaf838d1901b1abc7466b61f | |
parent | 0f17014fa54773711d43f1d408a81cd5ee962349 (diff) | |
parent | 293e8625a53e5caad3324b445aa4d7a3fc0d526a (diff) |
Merge "iorap_functional_test: Add iorap function test." into rvc-dev am: d3e541eb03 am: 77bf81a749 am: 54b18d3205 am: 293e8625a5
Change-Id: I94ac5e811d5263ebafaf2ba25291066fe8e0a97f
6 files changed, 270 insertions, 213 deletions
diff --git a/startop/iorap/functional_tests/Android.bp b/startop/iorap/functional_tests/Android.bp index ce9dc325c76d..ad85f1430bdf 100644 --- a/startop/iorap/functional_tests/Android.bp +++ b/startop/iorap/functional_tests/Android.bp @@ -15,6 +15,7 @@ android_test { name: "iorap-functional-tests", srcs: ["src/**/*.java"], + data: ["test_data/*"], static_libs: [ // Non-test dependencies // library under test diff --git a/startop/iorap/functional_tests/AndroidTest.xml b/startop/iorap/functional_tests/AndroidTest.xml index 3d5a2294f8d5..31d4f6c47b11 100644 --- a/startop/iorap/functional_tests/AndroidTest.xml +++ b/startop/iorap/functional_tests/AndroidTest.xml @@ -45,6 +45,20 @@ <option name="run-command" value="sleep 1" /> </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="abort-on-push-failure" value="true" /> + <option name="push-file" + key="iorap_test_app_v1.apk" + value="/data/misc/iorapd/iorap_test_app_v1.apk" /> + <option name="push-file" + key="iorap_test_app_v2.apk" + value="/data/misc/iorapd/iorap_test_app_v2.apk" /> + <option name="push-file" + key="iorap_test_app_v3.apk" + value="/data/misc/iorapd/iorap_test_app_v3.apk" /> + </target_preparer> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.google.android.startop.iorap.tests" /> <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> diff --git a/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java b/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java index 9abbcd71cfd2..c35dd3b783b1 100644 --- a/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java +++ b/startop/iorap/functional_tests/src/com/google/android/startop/iorap/IorapWorkFlowTest.java @@ -37,45 +37,46 @@ import androidx.test.uiautomator.By; import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.Until; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.Duration; import java.util.ArrayList; import java.util.concurrent.TimeUnit; +import java.util.Date; import java.util.function.BooleanSupplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.List; - +import java.text.SimpleDateFormat; /** * Test for the work flow of iorap. * - * <p> This test tests the function of iorap from perfetto collection -> compilation -> - * prefetching. - * </p> + * <p> This test tests the function of iorap from: + * perfetto collection -> compilation -> prefetching -> version update -> perfetto collection. */ @RunWith(AndroidJUnit4.class) public class IorapWorkFlowTest { - private static final String TAG = "IorapWorkFlowTest"; - private static final String TEST_PACKAGE_NAME = "com.android.settings"; - private static final String TEST_ACTIVITY_NAME = "com.android.settings.Settings"; + private static final String TEST_APP_VERSION_ONE_PATH = "/data/misc/iorapd/iorap_test_app_v1.apk"; + private static final String TEST_APP_VERSION_TWO_PATH = "/data/misc/iorapd/iorap_test_app_v2.apk"; + private static final String TEST_APP_VERSION_THREE_PATH = "/data/misc/iorapd/iorap_test_app_v3.apk"; private static final String DB_PATH = "/data/misc/iorapd/sqlite.db"; private static final Duration TIMEOUT = Duration.ofSeconds(300L); - private static final String READAHEAD_INDICATOR = - "Description = /data/misc/iorapd/com.android.settings/-?\\d+/com.android.settings.Settings/compiled_traces/compiled_trace.pb"; - private UiDevice mDevice; @Before - public void startMainActivityFromHomeScreen() throws Exception { + public void setUp() throws Exception { // Initialize UiDevice instance mDevice = UiDevice.getInstance(getInstrumentation()); @@ -88,21 +89,81 @@ public class IorapWorkFlowTest { mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), TIMEOUT.getSeconds()); } + @After + public void tearDown() throws Exception { + String packageName = "com.example.ioraptestapp"; + uninstallApk(packageName); + } + @Test (timeout = 300000) - public void testApp() throws Exception { + public void testNormalWorkFlow() throws Exception { assertThat(mDevice, notNullValue()); + // Install test app version one + installApk(TEST_APP_VERSION_ONE_PATH); + String packageName = "com.example.ioraptestapp"; + String activityName = "com.example.ioraptestapp.MainActivity"; + // Perfetto trace collection phase. - assertTrue(startAppForPerfettoTrace(/*expectPerfettoTraceCount=*/1)); - assertTrue(startAppForPerfettoTrace(/*expectPerfettoTraceCount=*/2)); - assertTrue(startAppForPerfettoTrace(/*expectPerfettoTraceCount=*/3)); - assertTrue(checkPerfettoTracesExistence(TIMEOUT, 3)); + assertTrue(startAppForPerfettoTrace( + packageName, activityName, /*version=*/1L)); + assertTrue(startAppForPerfettoTrace( + packageName, activityName, /*version=*/1L)); + assertTrue(startAppForPerfettoTrace( + packageName, activityName, /*version=*/1L)); // Trigger maintenance service for compilation. - assertTrue(compile(TIMEOUT)); + TimeUnit.SECONDS.sleep(5L); + assertTrue(compile(packageName, activityName, /*version=*/1L)); - // Check if prefetching works. - assertTrue(waitForPrefetchingFromLogcat(/*expectPerfettoTraceCount=*/3)); + // Run app with prefetching + assertTrue(startAppWithCompiledTrace( + packageName, activityName, /*version=*/1L)); + } + + @Test (timeout = 300000) + public void testUpdateApp() throws Exception { + assertThat(mDevice, notNullValue()); + + // Install test app version two, + String packageName = "com.example.ioraptestapp"; + String activityName = "com.example.ioraptestapp.MainActivity"; + installApk(TEST_APP_VERSION_TWO_PATH); + + // Perfetto trace collection phase. + assertTrue(startAppForPerfettoTrace( + packageName, activityName, /*version=*/2L)); + assertTrue(startAppForPerfettoTrace( + packageName, activityName, /*version=*/2L)); + assertTrue(startAppForPerfettoTrace( + packageName, activityName, /*version=*/2L)); + + // Trigger maintenance service for compilation. + TimeUnit.SECONDS.sleep(5L); + assertTrue(compile(packageName, activityName, /*version=*/2L)); + + // Run app with prefetching + assertTrue(startAppWithCompiledTrace( + packageName, activityName, /*version=*/2L)); + + // Update test app to version 3 + installApk(TEST_APP_VERSION_THREE_PATH); + + // Rerun app, should do pefetto tracing. + assertTrue(startAppForPerfettoTrace( + packageName, activityName, /*version=*/3L)); + } + + private static void installApk(String apkPath) throws Exception { + // Disable the selinux to allow pm install apk in the dir. + executeShellCommand("setenforce 0"); + executeShellCommand("pm install -r -d " + apkPath); + executeShellCommand("setenforce 1"); + + } + + private static void uninstallApk(String apkPath) throws Exception { + executeShellCommand("pm uninstall " + apkPath); } /** @@ -110,43 +171,81 @@ public class IorapWorkFlowTest { * * @param expectPerfettoTraceCount is the expected count of perfetto traces. */ - private boolean startAppForPerfettoTrace(long expectPerfettoTraceCount) + private boolean startAppForPerfettoTrace( + String packageName, String activityName, long version) + throws Exception { + LogcatTimestamp timestamp = runAppOnce(packageName, activityName); + return waitForPerfettoTraceSavedFromLogcat( + packageName, activityName, version, timestamp); + } + + private boolean startAppWithCompiledTrace( + String packageName, String activityName, long version) throws Exception { + LogcatTimestamp timestamp = runAppOnce(packageName, activityName); + return waitForPrefetchingFromLogcat( + packageName, activityName, version, timestamp); + } + + private LogcatTimestamp runAppOnce(String packageName, String activityName) throws Exception { // Close the specified app if it's open - closeApp(); + closeApp(packageName); + LogcatTimestamp timestamp = new LogcatTimestamp(); // Launch the specified app - startApp(); + startApp(packageName, activityName); // Wait for the app to appear - mDevice.wait(Until.hasObject(By.pkg(TEST_PACKAGE_NAME).depth(0)), TIMEOUT.getSeconds()); - - String sql = "SELECT COUNT(*) FROM activities " - + "JOIN app_launch_histories ON activities.id = app_launch_histories.activity_id " - + "JOIN raw_traces ON raw_traces.history_id = app_launch_histories.id " - + "WHERE activities.name = ?"; - return checkAndWaitEntriesNum(sql, new String[]{TEST_ACTIVITY_NAME}, expectPerfettoTraceCount, - TIMEOUT); + mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), TIMEOUT.getSeconds()); + return timestamp; } // Invokes the maintenance to compile the perfetto traces to compiled trace. - private boolean compile(Duration timeout) throws Exception { + private boolean compile( + String packageName, String activityName, long version) throws Exception { // The job id (283673059) is defined in class IorapForwardingService. - executeShellCommand("cmd jobscheduler run -f android 283673059"); - - // Wait for the compilation. - String sql = "SELECT COUNT(*) FROM activities JOIN prefetch_files ON " - + "activities.id = prefetch_files.activity_id " - + "WHERE activities.name = ?"; - boolean result = checkAndWaitEntriesNum(sql, new String[]{TEST_ACTIVITY_NAME}, /*count=*/1, - timeout); - if (!result) { - return false; + executeShellCommandViaTmpFile("cmd jobscheduler run -f android 283673059"); + return waitForFileExistence(getCompiledTracePath(packageName, activityName, version)); + } + + private String getCompiledTracePath( + String packageName, String activityName, long version) { + return String.format( + "/data/misc/iorapd/%s/%d/%s/compiled_traces/compiled_trace.pb", + packageName, version, activityName); + } + + /** + * Starts the testing app. + */ + private void startApp(String packageName, String activityName) throws Exception { + executeShellCommandViaTmpFile( + String.format("am start %s/%s", packageName, activityName)); + } + + /** + * Closes the testing app. + * <p> Keep trying to kill the process of the app until no process of the app package + * appears.</p> + */ + private void closeApp(String packageName) throws Exception { + while (true) { + String pid = executeShellCommand("pidof " + packageName); + if (pid.isEmpty()) { + Log.i(TAG, "Closed app " + packageName); + return; + } + executeShellCommand("kill -9 " + pid); + TimeUnit.SECONDS.sleep(1L); } + } - return retryWithTimeout(timeout, () -> { + /** Waits for a file to appear. */ + private boolean waitForFileExistence(String fileName) throws Exception { + return retryWithTimeout(TIMEOUT, () -> { try { - String compiledTrace = getCompiledTraceFilePath(); - File compiledTraceLocal = copyFileToLocal(compiledTrace, "compiled_trace.tmp"); - return compiledTraceLocal.exists(); + String fileExists = executeShellCommandViaTmpFile( + String.format("test -f %s; echo $?", fileName)); + Log.i(TAG, fileName + " existence is " + fileExists); + return fileExists.trim().equals("0"); } catch (Exception e) { Log.i(TAG, e.getMessage()); return false; @@ -154,92 +253,96 @@ public class IorapWorkFlowTest { }); } - /** - * Check if all the perfetto traces in the db exist. - */ - private boolean checkPerfettoTracesExistence(Duration timeout, int expectPerfettoTraceCount) + /** Waits for the perfetto trace saved message from logcat. */ + private boolean waitForPerfettoTraceSavedFromLogcat( + String packageName, String activityName, long version, LogcatTimestamp timestamp) throws Exception { - return retryWithTimeout(timeout, () -> { + Pattern p = Pattern.compile(".*" + + getPerfettoTraceSavedIndicator(packageName, activityName, version) + + "(.*[.]perfetto_trace[.]pb)\n.*", Pattern.DOTALL); + + return retryWithTimeout(TIMEOUT, () -> { try { - File dbFile = getIorapDb(); - List<String> traces = getPerfettoTracePaths(dbFile); - assertEquals(traces.size(), expectPerfettoTraceCount); - - int count = 0; - for (String trace : traces) { - File tmp = copyFileToLocal(trace, "perfetto_trace.tmp" + count); - ++count; - Log.i(TAG, "Check perfetto trace: " + trace); - if (!tmp.exists()) { - Log.i(TAG, "Perfetto trace does not exist: " + trace); - return false; - } + String log = timestamp.getLogcatAfter(); + Matcher m = p.matcher(log); + Log.d(TAG, "Tries to find perfetto trace..."); + if (!m.matches()) { + Log.i(TAG, "Cannot find perfetto trace saved in log."); + return false; } + String filePath = m.group(1); + Log.i(TAG, "Perfetto trace is saved to " + filePath); return true; - } catch (Exception e) { - Log.i(TAG, e.getMessage()); + } catch(Exception e) { + Log.e(TAG, e.getMessage()); return false; } - }); - } - - /** - * Gets the perfetto traces file path from the db. - */ - private List<String> getPerfettoTracePaths(File dbFile) throws Exception { - String sql = "SELECT raw_traces.file_path FROM activities " - + "JOIN app_launch_histories ON activities.id = app_launch_histories.activity_id " - + "JOIN raw_traces ON raw_traces.history_id = app_launch_histories.id " - + "WHERE activities.name = ?"; - - List<String> perfettoTraces = new ArrayList<>(); - try (SQLiteDatabase db = SQLiteDatabase - .openDatabase(dbFile.getPath(), null, SQLiteDatabase.OPEN_READONLY)) { - Cursor cursor = db.rawQuery(sql, new String[]{TEST_ACTIVITY_NAME}); - while (cursor.moveToNext()) { - perfettoTraces.add(cursor.getString(0)); - } - } - return perfettoTraces; + }); } - private String getCompiledTraceFilePath() throws Exception { - File dbFile = getIorapDb(); - try (SQLiteDatabase db = SQLiteDatabase - .openDatabase(dbFile.getPath(), null, SQLiteDatabase.OPEN_READONLY)) { - String sql = "SELECT prefetch_files.file_path FROM activities JOIN prefetch_files ON " - + "activities.id = prefetch_files.activity_id " - + "WHERE activities.name = ?"; - return DatabaseUtils.stringForQuery(db, sql, new String[]{TEST_ACTIVITY_NAME}); - } + private String getPerfettoTraceSavedIndicator( + String packageName, String activityName, long version) { + return String.format( + "Perfetto TraceBuffer saved to file: /data/misc/iorapd/%s/%d/%s/raw_traces/", + packageName, version, activityName); } /** - * Checks the number of entries in the database table. + * Waits for the prefetching log in the logcat. * - * <p> Keep checking until the timeout. + * <p> When prefetching works, the perfetto traces should not be collected. </p> */ - private boolean checkAndWaitEntriesNum(String sql, String[] selectionArgs, long count, - Duration timeout) + private boolean waitForPrefetchingFromLogcat( + String packageName, String activityName, long version, LogcatTimestamp timestamp) throws Exception { - return retryWithTimeout(timeout, () -> { + Pattern p = Pattern.compile( + ".*" + getReadaheadIndicator(packageName, activityName, version) + + ".*Total File Paths=(\\d+) \\(good: (\\d+[.]?\\d*)%\\)\n" + + ".*Total Entries=(\\d+) \\(good: (\\d+[.]?\\d*)%\\)\n" + + ".*Total Bytes=(\\d+) \\(good: (\\d+[.]?\\d*)%\\).*", + Pattern.DOTALL); + + return retryWithTimeout(TIMEOUT, () -> { try { - File db = getIorapDb(); - long curCount = getEntriesNum(db, selectionArgs, sql); - Log.i(TAG, String - .format("For %s, current count is %d, expected count is :%d.", sql, curCount, - count)); - return curCount == count; - } catch (Exception e) { - Log.i(TAG, e.getMessage()); + String log = timestamp.getLogcatAfter(); + Matcher m = p.matcher(log); + if (!m.matches()) { + Log.i(TAG, "Cannot find readahead log."); + return false; + } + + int totalFilePath = Integer.parseInt(m.group(1)); + float totalFilePathGoodRate = Float.parseFloat(m.group(2)) / 100; + int totalEntries = Integer.parseInt(m.group(3)); + float totalEntriesGoodRate = Float.parseFloat(m.group(4)) / 100; + int totalBytes = Integer.parseInt(m.group(5)); + float totalBytesGoodRate = Float.parseFloat(m.group(6)) / 100; + + Log.i(TAG, String.format( + "totalFilePath: %d (good %.2f) totalEntries: %d (good %.2f) totalBytes: %d (good %.2f)", + totalFilePath, totalFilePathGoodRate, totalEntries, totalEntriesGoodRate, totalBytes, + totalBytesGoodRate)); + + return totalFilePath > 0 && + totalEntries > 0 && + totalBytes > 0 && + totalFilePathGoodRate > 0.5 && + totalEntriesGoodRate > 0.5 && + totalBytesGoodRate > 0.5; + } catch(Exception e) { return false; } - }); + }); } - /** - * Retry until timeout. - */ + private static String getReadaheadIndicator( + String packageName, String activityName, long version) { + return String.format( + "Description = /data/misc/iorapd/%s/%d/%s/compiled_traces/compiled_trace.pb", + packageName, version, activityName); + } + + /** Retry until timeout. */ private boolean retryWithTimeout(Duration timeout, BooleanSupplier supplier) throws Exception { long totalSleepTimeSeconds = 0L; long sleepIntervalSeconds = 2L; @@ -256,113 +359,28 @@ public class IorapWorkFlowTest { } /** - * Gets the number of entries in the query of sql. - */ - private long getEntriesNum(File dbFile, String[] selectionArgs, String sql) throws Exception { - try (SQLiteDatabase db = SQLiteDatabase - .openDatabase(dbFile.getPath(), null, SQLiteDatabase.OPEN_READONLY)) { - return DatabaseUtils.longForQuery(db, sql, selectionArgs); - } - } - - /** - * Gets the iorapd sqlite db file. + * Executes command in adb shell via a tmp file. * - * <p> The test cannot access the db file directly under "/data/misc/iorapd". - * Copy it to the local directory and change the mode. - */ - private File getIorapDb() throws Exception { - File tmpDb = copyFileToLocal("/data/misc/iorapd/sqlite.db", "tmp.db"); - // Change the mode of the file to allow the access from test. - executeShellCommand("chmod 777 " + tmpDb.getPath()); - return tmpDb; - } - - /** - * Copys a file to local directory. - */ - private File copyFileToLocal(String src, String tgtFileName) throws Exception { - File localDir = getApplicationContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE); - File localFile = new File(localDir, tgtFileName); - executeShellCommand(String.format("cp %s %s", src, localFile.getPath())); - return localFile; - } - - /** - * Starts the testing app. - */ - private void startApp() throws Exception { - Context context = getApplicationContext(); - final Intent intent = context.getPackageManager() - .getLaunchIntentForPackage(TEST_PACKAGE_NAME); - context.startActivity(intent); - Log.i(TAG, "Started app " + TEST_PACKAGE_NAME); - } - - /** - * Closes the testing app. - * <p> Keep trying to kill the process of the app until no process of the app package - * appears.</p> + * <p> This should be run as root.</p> */ - private void closeApp() throws Exception { - while (true) { - String pid = executeShellCommand("pidof " + TEST_PACKAGE_NAME); - if (pid.isEmpty()) { - Log.i(TAG, "Closed app " + TEST_PACKAGE_NAME); - return; + private static String executeShellCommandViaTmpFile(String cmd) throws Exception { + Log.i(TAG, "Execute via tmp file: " + cmd); + Path tmp = null; + try { + tmp = Files.createTempFile(/*prefix=*/null, /*suffix=*/".sh"); + Files.write(tmp, cmd.getBytes(StandardCharsets.UTF_8)); + tmp.toFile().setExecutable(true); + return UiDevice.getInstance( + InstrumentationRegistry.getInstrumentation()). + executeShellCommand(tmp.toString()); + } finally { + if (tmp != null) { + Files.delete(tmp); } - executeShellCommand("kill -9 " + pid); - TimeUnit.SECONDS.sleep(1L); } } /** - * Waits for the prefetching log in the logcat. - * - * <p> When prefetching works, the perfetto traces should not be collected. </p> - */ - private boolean waitForPrefetchingFromLogcat(long expectPerfettoTraceCount) throws Exception { - if (!startAppForPerfettoTrace(expectPerfettoTraceCount)) { - return false; - } - - String log = executeShellCommand("logcat -d"); - - Pattern p = Pattern.compile( - ".*" + READAHEAD_INDICATOR - + ".*Total File Paths=(\\d+) \\(good: (\\d+[.]?\\d*)%\\)\n" - + ".*Total Entries=(\\d+) \\(good: (\\d+[.]?\\d*)%\\)\n" - + ".*Total Bytes=(\\d+) \\(good: (\\d+[.]?\\d*)%\\).*", - Pattern.DOTALL); - Matcher m = p.matcher(log); - - if (!m.matches()) { - Log.i(TAG, "Cannot find readahead log."); - return false; - } - - int totalFilePath = Integer.parseInt(m.group(1)); - float totalFilePathGoodRate = Float.parseFloat(m.group(2)) / 100; - int totalEntries = Integer.parseInt(m.group(3)); - float totalEntriesGoodRate = Float.parseFloat(m.group(4)) / 100; - int totalBytes = Integer.parseInt(m.group(5)); - float totalBytesGoodRate = Float.parseFloat(m.group(6)) / 100; - - Log.i(TAG, String.format( - "totalFilePath: %d (good %.2f) totalEntries: %d (good %.2f) totalBytes: %d (good %.2f)", - totalFilePath, totalFilePathGoodRate, totalEntries, totalEntriesGoodRate, totalBytes, - totalBytesGoodRate)); - - return totalFilePath > 0 && - totalEntries > 0 && - totalBytes > 100000 && - totalFilePathGoodRate > 0.5 && - totalEntriesGoodRate > 0.5 && - totalBytesGoodRate > 0.5; - } - - - /** * Executes command in adb shell. * * <p> This should be run as root.</p> @@ -372,6 +390,27 @@ public class IorapWorkFlowTest { return UiDevice.getInstance( InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd); } -} + static class LogcatTimestamp { + private String epochTime; + + public LogcatTimestamp() throws Exception{ + long currentTimeMillis = System.currentTimeMillis(); + epochTime = String.format( + "%d.%d", currentTimeMillis/1000, currentTimeMillis%1000); + Log.i(TAG, "Current logcat timestamp is " + epochTime); + } + + // For example, 1585264100.000 + public String getEpochTime() { + return epochTime; + } + + // Gets the logcat after this epoch time. + public String getLogcatAfter() throws Exception { + return executeShellCommandViaTmpFile( + "logcat -v epoch -t '" + epochTime + "'"); + } + } +} diff --git a/startop/iorap/functional_tests/test_data/iorap_test_app_v1.apk b/startop/iorap/functional_tests/test_data/iorap_test_app_v1.apk new file mode 120000 index 000000000000..1c1a437f6a55 --- /dev/null +++ b/startop/iorap/functional_tests/test_data/iorap_test_app_v1.apk @@ -0,0 +1 @@ +../../../../../../packages/modules/ArtPrebuilt/iorap/test/iorap_test_app_v1.apk
\ No newline at end of file diff --git a/startop/iorap/functional_tests/test_data/iorap_test_app_v2.apk b/startop/iorap/functional_tests/test_data/iorap_test_app_v2.apk new file mode 120000 index 000000000000..7cd41c48ba3a --- /dev/null +++ b/startop/iorap/functional_tests/test_data/iorap_test_app_v2.apk @@ -0,0 +1 @@ +../../../../../../packages/modules/ArtPrebuilt/iorap/test/iorap_test_app_v2.apk
\ No newline at end of file diff --git a/startop/iorap/functional_tests/test_data/iorap_test_app_v3.apk b/startop/iorap/functional_tests/test_data/iorap_test_app_v3.apk new file mode 120000 index 000000000000..7f4e996e57d0 --- /dev/null +++ b/startop/iorap/functional_tests/test_data/iorap_test_app_v3.apk @@ -0,0 +1 @@ +../../../../../../packages/modules/ArtPrebuilt/iorap/test/iorap_test_app_v3.apk
\ No newline at end of file |