Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8ee8ebfa authored by Tomasz Mikolajewski's avatar Tomasz Mikolajewski
Browse files

Add basic jank tests for DocumentsUI.

This CL adds two jank tests:
* For opening a root (directory) with many files.
* For flinging through a directory with many files.

Bug: 27383277
Change-Id: Ie67efe6d5495ff3a8ed63135ed7ec2d4e6262bd2
parent 95ee171e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) \
    ../tests/src/com/android/documentsui/StubProvider.java

LOCAL_JAVA_LIBRARIES := android-support-v4 android.test.runner
LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator
LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator ub-janktesthelper

LOCAL_PACKAGE_NAME := DocumentsUIPerfTests
LOCAL_INSTRUMENTATION_FOR := DocumentsUI
+90 −0
Original line number Diff line number Diff line
/*
 * 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_2_ID;

import android.app.Activity;
import android.os.RemoteException;
import android.test.suitebuilder.annotation.LargeTest;

import android.content.Intent;
import android.content.Context;
import android.support.test.jank.JankTest;
import android.support.test.jank.JankTestBase;
import android.support.test.uiautomator.UiDevice;
import android.support.test.jank.GfxMonitor;
import android.support.test.uiautomator.UiScrollable;
import android.util.Log;

import com.android.documentsui.FilesActivity;
import com.android.documentsui.bots.RootsListBot;
import com.android.documentsui.bots.DirectoryListBot;

@LargeTest
public class FilesJankPerfTest extends JankTestBase {
    private static final String DOCUMENTSUI_PACKAGE = "com.android.documentsui";
    private static final int MAX_FLINGS = 10;
    private static final int BOT_TIMEOUT = 5000;

    private RootsListBot mRootsListBot;
    private DirectoryListBot mDirListBot;
    private Activity mActivity = null;

    public void setUpInLoop() {
        final UiDevice device = UiDevice.getInstance(getInstrumentation());
        final Context context = getInstrumentation().getTargetContext();
        mRootsListBot = new RootsListBot(device, context, BOT_TIMEOUT);
        mDirListBot = new DirectoryListBot(device, context, BOT_TIMEOUT);

        final Intent intent = new Intent(context, FilesActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mActivity = getInstrumentation().startActivitySync(intent);
    }

    public void tearDownInLoop() {
        if (mActivity != null) {
            mActivity.finish();
            mActivity = null;
        }
    }

    public void setupAndOpenInLoop() throws Exception {
        setUpInLoop();
        openRoot();
    }

    public void openRoot() throws Exception {
        mRootsListBot.openRoot(STRESS_ROOT_2_ID);
    }

    @JankTest(expectedFrames=0, beforeLoop="setUpInLoop", afterLoop="tearDownInLoop")
    @GfxMonitor(processName=DOCUMENTSUI_PACKAGE)
    public void testOpenRootJankPerformance() throws Exception {
        openRoot();
        getInstrumentation().waitForIdleSync();
    }

    @JankTest(expectedFrames=0, beforeLoop="setupAndOpenInLoop", afterLoop="tearDownInLoop")
    @GfxMonitor(processName=DOCUMENTSUI_PACKAGE)
    public void testFlingJankPerformance() throws Exception {
        new UiScrollable(mDirListBot.findDocumentsList().getSelector()).flingToEnd(MAX_FLINGS);
        getInstrumentation().waitForIdleSync();
    }
}
+126 −33
Original line number Diff line number Diff line
@@ -32,7 +32,9 @@ import android.provider.DocumentsProvider;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
@@ -46,11 +48,21 @@ public class StressProvider extends DocumentsProvider {
    // Empty root.
    public static final String STRESS_ROOT_0_ID = "STRESS_ROOT_0";

    // Root with thousands of items.
    // Root with thousands of directories.
    public static final String STRESS_ROOT_1_ID = "STRESS_ROOT_1";

    // Root with hundreds of files.
    public static final String STRESS_ROOT_2_ID = "STRESS_ROOT_2";

    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 STRESS_ROOT_2_DOC_ID = "STRESS_ROOT_2_DOC";

    private static final int STRESS_ROOT_1_ITEMS = 10000;
    private static final int STRESS_ROOT_2_ITEMS = 300;

    private static final String MIME_TYPE_IMAGE = "image/jpeg";
    private static final long REFERENCE_TIMESTAMP = 1459159369359L;

    private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
            Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
@@ -62,7 +74,12 @@ public class StressProvider extends DocumentsProvider {
    };

    private String mAuthority = DEFAULT_AUTHORITY;
    private ArrayList<String> mIds = new ArrayList<>();

    // Map from a root document id to children document ids.
    private Map<String, ArrayList<StubDocument>> mChildDocuments = new HashMap<>();

    private Map<String, StubDocument> mDocuments = new HashMap<>();
    private Map<String, StubRoot> mRoots = new HashMap<>();

    @Override
    public void attachInfo(Context context, ProviderInfo info) {
@@ -72,20 +89,41 @@ public class StressProvider extends DocumentsProvider {

    @Override
    public boolean onCreate() {
        mIds = new ArrayList();
        for (int i = 0; i < 10000; i++) {
            mIds.add(createRandomId(i));
        StubDocument document;

        ArrayList<StubDocument> children = new ArrayList<StubDocument>();
        mChildDocuments.put(STRESS_ROOT_1_DOC_ID, children);
        for (int i = 0; i < STRESS_ROOT_1_ITEMS; i++) {
            document = StubDocument.createDirectory(i);
            mDocuments.put(document.id, document);
            children.add(document);
        }

        children = new ArrayList<StubDocument>();
        mChildDocuments.put(STRESS_ROOT_2_DOC_ID, children);
        for (int i = 0; i < STRESS_ROOT_2_ITEMS; i++) {
            document = StubDocument.createFile(STRESS_ROOT_1_ITEMS + i);
            mDocuments.put(document.id, document);
            children.add(document);
        }
        mIds.add(STRESS_ROOT_0_DOC_ID);
        mIds.add(STRESS_ROOT_1_DOC_ID);

        mRoots.put(STRESS_ROOT_0_ID, new StubRoot(STRESS_ROOT_0_ID, STRESS_ROOT_0_DOC_ID));
        mRoots.put(STRESS_ROOT_1_ID, new StubRoot(STRESS_ROOT_1_ID, STRESS_ROOT_1_DOC_ID));
        mRoots.put(STRESS_ROOT_2_ID, new StubRoot(STRESS_ROOT_2_ID, STRESS_ROOT_2_DOC_ID));

        mDocuments.put(STRESS_ROOT_0_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_0_DOC_ID));
        mDocuments.put(STRESS_ROOT_1_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_1_DOC_ID));
        mDocuments.put(STRESS_ROOT_2_DOC_ID, StubDocument.createDirectory(STRESS_ROOT_2_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);
        for (StubRoot root : mRoots.values()) {
            includeRoot(result, root);
        }
        return result;
    }

@@ -93,51 +131,84 @@ public class StressProvider extends DocumentsProvider {
    public Cursor queryDocument(String documentId, String[] projection)
            throws FileNotFoundException {
        final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
        includeDocument(result, documentId);
        final StubDocument document = mDocuments.get(documentId);
        includeDocument(result, document);
        return result;
    }

    @Override
    public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder)
    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);
        final ArrayList<StubDocument> childDocuments = mChildDocuments.get(parentDocumentId);
        if (childDocuments != null) {
            for (StubDocument document : childDocuments) {
                includeDocument(result, document);
            }
        }
        return result;
    }

    @Override
    public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
    public ParcelFileDescriptor openDocument(String docId, String mode,
            CancellationSignal signal)
            throws FileNotFoundException {
        throw new UnsupportedOperationException();
    }

    private void includeRoot(MatrixCursor result, String rootId, String docId) {
    private void includeRoot(MatrixCursor result, StubRoot root) {
        final RowBuilder row = result.newRow();
        row.add(Root.COLUMN_ROOT_ID, rootId);
        row.add(Root.COLUMN_ROOT_ID, root.id);
        row.add(Root.COLUMN_FLAGS, 0);
        row.add(Root.COLUMN_TITLE, rootId);
        row.add(Root.COLUMN_DOCUMENT_ID, docId);
        row.add(Root.COLUMN_TITLE, root.id);
        row.add(Root.COLUMN_DOCUMENT_ID, root.documentId);
    }

    private void includeDocument(MatrixCursor result, String id) {
    private void includeDocument(MatrixCursor result, StubDocument document) {
        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_DOCUMENT_ID, document.id);
        row.add(Document.COLUMN_DISPLAY_NAME, document.id);
        row.add(Document.COLUMN_SIZE, document.size);
        row.add(Document.COLUMN_MIME_TYPE, document.mimeType);
        row.add(Document.COLUMN_FLAGS, 0);
        row.add(Document.COLUMN_LAST_MODIFIED, null);
        row.add(Document.COLUMN_LAST_MODIFIED, document.lastModified);
    }

    private static String getDocumentIdForFile(File file) {
    private static String getStubDocumentIdForFile(File file) {
        return file.getAbsolutePath();
    }

    private String createRandomId(int index) {
    private static class StubDocument {
        final String mimeType;
        final String id;
        final int size;
        final long lastModified;

        private StubDocument(String mimeType, String id, int size, long lastModified) {
            this.mimeType = mimeType;
            this.id = id;
            this.size = size;
            this.lastModified = lastModified;
        }

        public static StubDocument createDirectory(int index) {
            return new StubDocument(
                    DocumentsContract.Document.MIME_TYPE_DIR, createRandomId(index), 0,
                    createRandomTime(index));
        }

        public static StubDocument createDirectory(String id) {
            return new StubDocument(DocumentsContract.Document.MIME_TYPE_DIR, id, 0, 0);
        }

        public static StubDocument createFile(int index) {
            return new StubDocument(
                    MIME_TYPE_IMAGE, createRandomId(index), createRandomSize(index),
                    createRandomTime(index));
        }

        private static String createRandomId(int index) {
            final Random random = new Random(index);
            final StringBuilder builder = new StringBuilder();
            for (int i = 0; i < 20; i++) {
@@ -146,4 +217,26 @@ public class StressProvider extends DocumentsProvider {
            builder.append(index);  // Append a number to guarantee uniqueness.
            return builder.toString();
        }

        private static int createRandomSize(int index) {
            final Random random = new Random(index);
            return random.nextInt(1024 * 1024 * 100);  // Up to 100 MB.
        }

        private static long createRandomTime(int index) {
            final Random random = new Random(index);
            // Up to 30 days backwards from REFERENCE_TIMESTAMP.
            return REFERENCE_TIMESTAMP - random.nextLong() % 1000L * 60 * 60 * 24 * 30;
        }
    }

    private static class StubRoot {
        final String id;
        final String documentId;

        public StubRoot(String id, String documentId) {
            this.id = id;
            this.documentId = documentId;
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ public class DirectoryListBot extends BaseBot {
        return true;
    }

    private UiObject findDocumentsList() {
    public UiObject findDocumentsList() {
        return findObject(
                "com.android.documentsui:id/container_directory",
                DIR_LIST_ID);