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

Commit ceedd1fb authored by Garfield Tan's avatar Garfield Tan
Browse files

Add a functional test for copy large amount of documents.

Bug: 37882979
Test: Test passes on Pixel C & Reef.
Change-Id: Ie6b19c08f9312b71145b4fcd3c39cb6bfa1a31d7
parent 8c465e98
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -163,7 +163,7 @@ public class DocumentsProviderHelper {
    }

    public void assertChildCount(String parentId, int expected) throws Exception {
        List<DocumentInfo> children = listChildren(parentId);
        List<DocumentInfo> children = listChildren(parentId, -1);
        assertEquals("Incorrect file count after copy", expected, children.size());
    }

@@ -264,10 +264,19 @@ public class DocumentsProviderHelper {
    }

    public List<DocumentInfo> listChildren(String documentId) throws Exception {
        return listChildren(documentId, 100);
    }

    public List<DocumentInfo> listChildren(Uri parentUri, int maxCount) throws Exception {
        String id = DocumentsContract.getDocumentId(parentUri);
        return listChildren(id, maxCount);
    }

    public List<DocumentInfo> listChildren(String documentId, int maxCount) throws Exception {
        Uri uri = buildChildDocumentsUri(mAuthority, documentId);
        List<DocumentInfo> children = new ArrayList<>();
        try (Cursor cursor = mClient.query(uri, null, null, null, null, null)) {
            Cursor wrapper = new RootCursorWrapper(mAuthority, "totally-fake", cursor, 100);
            Cursor wrapper = new RootCursorWrapper(mAuthority, "totally-fake", cursor, maxCount);
            while (wrapper.moveToNext()) {
                children.add(DocumentInfo.fromDirectoryCursor(wrapper));
            }
@@ -314,4 +323,8 @@ public class DocumentsProviderHelper {
        extra.putLong(DocumentsContract.EXTRA_LOADING, duration);
        mClient.call("setLoadingDuration", null, extra);
    }

    public void configure(String args, Bundle configuration) throws RemoteException {
        mClient.call("configure", args, configuration);
    }
}
+10 −4
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ public class StubProvider extends DocumentsProvider {
    public static final String EXTRA_STREAM_TYPES
            = "com.android.documentsui.stubprovider.STREAM_TYPES";
    public static final String EXTRA_CONTENT = "com.android.documentsui.stubprovider.CONTENT";
    public static final String EXTRA_ENABLE_ROOT_NOTIFICATION
            = "com.android.documentsui.stubprovider.ROOT_NOTIFICATION";

    public static final String EXTRA_FLAGS = "com.android.documentsui.stubprovider.FLAGS";
    public static final String EXTRA_PARENT_ID = "com.android.documentsui.stubprovider.PARENT";
@@ -91,6 +93,7 @@ public class StubProvider extends DocumentsProvider {
    private SharedPreferences mPrefs;
    private Set<String> mSimulateReadErrorIds = new HashSet<>();
    private long mLoadingDuration = 0;
    private boolean mRootNotification = true;

    @Override
    public void attachInfo(Context context, ProviderInfo info) {
@@ -630,16 +633,19 @@ public class StubProvider extends DocumentsProvider {
    private void configure(String arg, Bundle extras) {
        Log.d(TAG, "Configure " + arg);
        String rootName = extras.getString(EXTRA_ROOT, ROOT_0_ID);
        long rootSize = extras.getLong(EXTRA_SIZE, 1) * 1024 * 1024;
        long rootSize = extras.getLong(EXTRA_SIZE, 100) * 1024 * 1024;
        setSize(rootName, rootSize);
        mRootNotification = extras.getBoolean(EXTRA_ENABLE_ROOT_NOTIFICATION, true);
    }

    private void notifyParentChanged(String parentId) {
        getContext().getContentResolver().notifyChange(
                DocumentsContract.buildChildDocumentsUri(mAuthority, parentId), null, false);
        if (mRootNotification) {
            // Notify also about possible change in remaining space on the root.
        getContext().getContentResolver().notifyChange(DocumentsContract.buildRootsUri(mAuthority),
                null, false);
            getContext().getContentResolver().notifyChange(
                    DocumentsContract.buildRootsUri(mAuthority), null, false);
        }
    }

    private void includeDocument(MatrixCursor result, StubDocument document) {
+0 −1
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ import static org.hamcrest.Matchers.endsWith;

import android.content.Context;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.action.ViewActions;
import android.support.test.espresso.matcher.BoundedMatcher;
import android.support.test.espresso.matcher.ViewMatchers;
+4 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
@@ -124,6 +125,9 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen
        // so if a drawer is on top of a file we want to select, it will actually click the drawer.
        // Thus to start a clean state, we always try to close first.
        bots.roots.closeDrawer();

        // Configure the provider back to default.
        mDocsHelper.configure(null, Bundle.EMPTY);
    }

    @Override
+75 −0
Original line number Diff line number Diff line
@@ -20,12 +20,19 @@ import static com.android.documentsui.StubProvider.ROOT_0_ID;
import static com.android.documentsui.StubProvider.ROOT_1_ID;

import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.support.test.filters.LargeTest;
import android.support.test.filters.Suppress;
import android.view.KeyEvent;

import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.Shared;
import com.android.documentsui.files.FilesActivity;
import com.android.documentsui.sorting.SortDimension;
import com.android.documentsui.sorting.SortModel;

import java.util.List;

@LargeTest
public class FileManagementUiTest extends ActivityTest<FilesActivity> {
@@ -122,4 +129,72 @@ public class FileManagementUiTest extends ActivityTest<FilesActivity> {

        bots.directory.waitForDocument("file1.png");
    }

    public void testCopyLargeAmountOfFiles() throws Exception {
        // Suppress root notification. We're gonna create tons of files and it will soon crash
        // DocsUI because too many root refreshes are queued in an executor.
        Bundle conf = new Bundle();
        conf.putBoolean(StubProvider.EXTRA_ENABLE_ROOT_NOTIFICATION, false);
        mDocsHelper.configure(null, conf);

        final Uri test = mDocsHelper.createFolder(rootDir0, "test");
        final Uri target = mDocsHelper.createFolder(rootDir0, "target");
        String nameOfLastFile = "";
        for (int i = 0; i <= Shared.MAX_DOCS_IN_INTENT; ++i) {
            final String name = i + ".txt";
            final Uri doc =
                    mDocsHelper.createDocument(test, "text/plain", name);
            mDocsHelper.writeDocument(doc, Integer.toString(i).getBytes());
            nameOfLastFile = nameOfLastFile.compareTo(name) < 0 ? name : nameOfLastFile;
        }

        bots.roots.openRoot(ROOT_0_ID);
        bots.directory.openDocument("test");
        bots.sortHeader.sortBy(
                SortModel.SORT_DIMENSION_ID_TITLE, SortDimension.SORT_DIRECTION_ASCENDING);
        bots.directory.waitForDocument("0.txt");
        bots.keyboard.pressKey(
                KeyEvent.KEYCODE_A, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON);
        bots.keyboard.pressKey(
                KeyEvent.KEYCODE_C, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_CTRL_ON);

        bots.roots.openRoot(ROOT_0_ID);
        bots.directory.openDocument("target");
        bots.directory.pasteFilesFromClipboard();

        // Use these 2 events as a signal that many files have already been copied. Only considering
        // Android devices a more reliable way is to wait until notification goes away, but ARC++
        // uses Chrome OS notifications so it isn't even an option.
        bots.directory.waitForDocument("0.txt");
        bots.directory.waitForDocument(nameOfLastFile);

        final int expectedCount = Shared.MAX_DOCS_IN_INTENT + 1;
        List<DocumentInfo> children = mDocsHelper.listChildren(target, -1);
        if (children.size() == expectedCount) {
            return;
        }

        // Files weren't copied fast enough, so gonna do some polling until they all arrive or copy
        // seems stalled.
        while (true) {
            Thread.sleep(200);
            List<DocumentInfo> newChildren = mDocsHelper.listChildren(target, -1);
            if (newChildren.size() == expectedCount) {
                return;
            }

            if (newChildren.size() > expectedCount) {
                // Should never happen
                fail("Something wrong with this test case. Copied file count "
                        + newChildren.size() + " exceeds expected number " + expectedCount);
            }

            if (newChildren.size() <= children.size()) {
                fail("Only copied " + children.size()
                        + " files, expected to copy " + expectedCount + " files.");
            }

            children = newChildren;
        }
    }
}