diff options
author | 2016-02-24 12:53:44 +0900 | |
---|---|---|
committer | 2016-03-02 13:01:11 +0900 | |
commit | e29e3416fddc34f72234a7ece191289ad3ba3a21 (patch) | |
tree | 95db2480b02f282a2a040030956fc0281e149f16 /perf-tests | |
parent | 191af919bb063c85544b72053e1eb33cc1daa5a0 (diff) |
Add scaffolds for performance tests of DocumentsUI
Bug: 27370274
Change-Id: I14dea1b85cd84c8bb3c0eee27b2954108bfa4f8b
Diffstat (limited to 'perf-tests')
-rw-r--r-- | perf-tests/Android.mk | 22 | ||||
-rw-r--r-- | perf-tests/AndroidManifest.xml | 24 | ||||
-rw-r--r-- | perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java | 144 | ||||
-rw-r--r-- | perf-tests/src/com/android/documentsui/StressProvider.java | 149 |
4 files changed, 339 insertions, 0 deletions
diff --git a/perf-tests/Android.mk b/perf-tests/Android.mk new file mode 100644 index 000000000..c83094e35 --- /dev/null +++ b/perf-tests/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +#LOCAL_SDK_VERSION := current + +LOCAL_SRC_FILES := $(call all-java-files-under, src) \ + $(call all-java-files-under, ../tests/src/com/android/documentsui/bots) \ + ../tests/src/com/android/documentsui/ActivityTest.java \ + ../tests/src/com/android/documentsui/DocumentsProviderHelper.java \ + ../tests/src/com/android/documentsui/StubProvider.java + +LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target ub-uiautomator + +LOCAL_PACKAGE_NAME := DocumentsUIPerfTests +LOCAL_INSTRUMENTATION_FOR := DocumentsUI + +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) + diff --git a/perf-tests/AndroidManifest.xml b/perf-tests/AndroidManifest.xml new file mode 100644 index 000000000..97353e7df --- /dev/null +++ b/perf-tests/AndroidManifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.documentsui.perftests"> + + <application> + <uses-library android:name="android.test.runner" /> + <provider + android:name="com.android.documentsui.StressProvider" + android:authorities="com.android.documentsui.stressprovider" + android:exported="true" + android:grantUriPermissions="true" + android:permission="android.permission.MANAGE_DOCUMENTS" + android:enabled="true"> + <intent-filter> + <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> + </intent-filter> + </provider> + </application> + + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.documentsui" + android:label="Performance tests for DocumentsUI" /> + +</manifest> diff --git a/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java b/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java new file mode 100644 index 000000000..8c39aac43 --- /dev/null +++ b/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java @@ -0,0 +1,144 @@ +/* + * 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. + */ + +package com.android.documentsui; + +import static com.android.documentsui.StressProvider.DEFAULT_AUTHORITY; +import static com.android.documentsui.StressProvider.STRESS_ROOT_0_ID; +import static com.android.documentsui.StressProvider.STRESS_ROOT_1_ID; + +import android.app.Activity; +import android.net.Uri; +import android.os.Bundle; +import android.os.RemoteException; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; +import android.view.KeyEvent; + +import com.android.documentsui.model.RootInfo; +import com.android.documentsui.EventListener; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + +@LargeTest +public class FilesActivityPerfTest extends ActivityTest<FilesActivity> { + + // Constants starting with KEY_ are used to report metrics to APCT. + private static final String KEY_FILES_LISTED_PERFORMANCE_FIRST = + "files-listed-performance-first"; + + private static final String KEY_FILES_LISTED_PERFORMANCE_MEDIAN = + "files-listed-performance-median"; + + private static final String TESTED_URI = + "content://com.android.documentsui.stressprovider/document/STRESS_ROOT_1_DOC"; + + private static final int NUM_MEASUREMENTS = 10; + + public FilesActivityPerfTest() { + super(FilesActivity.class); + } + + @Override + protected RootInfo getInitialRoot() { + return rootDir0; + } + + @Override + protected String getTestingProviderAuthority() { + return DEFAULT_AUTHORITY; + } + + @Override + protected void setupTestingRoots() throws RemoteException { + rootDir0 = mDocsHelper.getRoot(STRESS_ROOT_0_ID); + rootDir1 = mDocsHelper.getRoot(STRESS_ROOT_1_ID); + } + + @Override + public void initTestFiles() throws RemoteException { + // Nothing to create, already done by StressProvider. + } + + public void testFilesListedPerformance() throws Exception { + final BaseActivity activity = getActivity(); + + final List<Long> measurements = new ArrayList<Long>(); + CountDownLatch signal; + EventListener listener; + for (int i = 0; i < 10; i++) { + signal = new CountDownLatch(1); + listener = new EventListener() { + @Override + public void onDirectoryNavigated(Uri uri) { + if (uri != null && TESTED_URI.equals(uri.toString())) { + mStartTime = System.currentTimeMillis(); + } else { + mStartTime = -1; + } + } + + @Override + public void onDirectoryLoaded(Uri uri) { + if (uri == null || !TESTED_URI.equals(uri.toString())) { + return; + } + assertTrue(mStartTime != -1); + getInstrumentation().waitForIdle(new Runnable() { + @Override + public void run() { + assertTrue(mStartTime != -1); + measurements.add(System.currentTimeMillis() - mStartTime); + signal.countDown(); + } + }); + } + + private long mStartTime = -1; + }; + + try { + activity.addEventListener(listener); + bots.roots.openRoot(STRESS_ROOT_1_ID); + signal.await(); + } finally { + activity.removeEventListener(listener); + } + + assertEquals(i, measurements.size()); + + // Go back to the empty root. + bots.roots.openRoot(STRESS_ROOT_0_ID); + } + + assertEquals(NUM_MEASUREMENTS, measurements.size()); + + final Bundle status = new Bundle(); + status.putDouble(KEY_FILES_LISTED_PERFORMANCE_FIRST, measurements.get(0)); + + final Long[] rawMeasurements = measurements.toArray(new Long[NUM_MEASUREMENTS]); + Arrays.sort(rawMeasurements); + + final long median = rawMeasurements[NUM_MEASUREMENTS / 2 - 1]; + status.putDouble(KEY_FILES_LISTED_PERFORMANCE_MEDIAN, median); + + getInstrumentation().sendStatus(Activity.RESULT_OK, status); + } +} diff --git a/perf-tests/src/com/android/documentsui/StressProvider.java b/perf-tests/src/com/android/documentsui/StressProvider.java new file mode 100644 index 000000000..1bc802a00 --- /dev/null +++ b/perf-tests/src/com/android/documentsui/StressProvider.java @@ -0,0 +1,149 @@ +/* + * 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. + */ + +package com.android.documentsui; + +import android.content.Context; +import android.content.pm.ProviderInfo; +import android.database.Cursor; +import android.database.MatrixCursor.RowBuilder; +import android.database.MatrixCursor; +import android.os.CancellationSignal; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; +import android.provider.DocumentsContract.Document; +import android.provider.DocumentsContract.Root; +import android.provider.DocumentsContract; +import android.provider.DocumentsProvider; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Provider with thousands of files for testing loading time of directories in DocumentsUI. + * It doesn't support any file operations. + */ +public class StressProvider extends DocumentsProvider { + + public static final String DEFAULT_AUTHORITY = "com.android.documentsui.stressprovider"; + + // Empty root. + public static final String STRESS_ROOT_0_ID = "STRESS_ROOT_0"; + + // Root with thousands of items. + public static final String STRESS_ROOT_1_ID = "STRESS_ROOT_1"; + + private static final String STRESS_ROOT_0_DOC_ID = "STRESS_ROOT_0_DOC"; + private static final String STRESS_ROOT_1_DOC_ID = "STRESS_ROOT_1_DOC"; + + private static final String[] DEFAULT_ROOT_PROJECTION = new String[] { + Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID, + Root.COLUMN_AVAILABLE_BYTES + }; + private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] { + Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME, + Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE, + }; + + private String mAuthority = DEFAULT_AUTHORITY; + private ArrayList<String> mIds = new ArrayList<>(); + + @Override + public void attachInfo(Context context, ProviderInfo info) { + mAuthority = info.authority; + super.attachInfo(context, info); + } + + @Override + public boolean onCreate() { + mIds = new ArrayList(); + for (int i = 0; i < 10000; i++) { + mIds.add(createRandomId(i)); + } + mIds.add(STRESS_ROOT_0_DOC_ID); + mIds.add(STRESS_ROOT_1_DOC_ID); + return true; + } + + @Override + public Cursor queryRoots(String[] projection) throws FileNotFoundException { + final MatrixCursor result = new MatrixCursor(DEFAULT_ROOT_PROJECTION); + includeRoot(result, STRESS_ROOT_0_ID, STRESS_ROOT_0_DOC_ID); + includeRoot(result, STRESS_ROOT_1_ID, STRESS_ROOT_1_DOC_ID); + return result; + } + + @Override + public Cursor queryDocument(String documentId, String[] projection) + throws FileNotFoundException { + final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION); + includeDocument(result, documentId); + return result; + } + + @Override + public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) + throws FileNotFoundException { + final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION); + if (STRESS_ROOT_1_DOC_ID.equals(parentDocumentId)) { + for (String id : mIds) { + includeDocument(result, id); + } + } + return result; + } + + @Override + public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal) + throws FileNotFoundException { + throw new UnsupportedOperationException(); + } + + private void includeRoot(MatrixCursor result, String rootId, String docId) { + final RowBuilder row = result.newRow(); + row.add(Root.COLUMN_ROOT_ID, rootId); + row.add(Root.COLUMN_FLAGS, 0); + row.add(Root.COLUMN_TITLE, rootId); + row.add(Root.COLUMN_DOCUMENT_ID, docId); + } + + private void includeDocument(MatrixCursor result, String id) { + final RowBuilder row = result.newRow(); + row.add(Document.COLUMN_DOCUMENT_ID, id); + row.add(Document.COLUMN_DISPLAY_NAME, id); + row.add(Document.COLUMN_SIZE, 0); + row.add(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR); + row.add(Document.COLUMN_FLAGS, 0); + row.add(Document.COLUMN_LAST_MODIFIED, null); + } + + private static String getDocumentIdForFile(File file) { + return file.getAbsolutePath(); + } + + private String createRandomId(int index) { + final Random random = new Random(index); + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 20; i++) { + builder.append((char) (random.nextInt(96) + 32)); + } + builder.append(index); // Append a number to guarantee uniqueness. + return builder.toString(); + } +} |