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

Commit 448dbbbf authored by Ben Kwa's avatar Ben Kwa
Browse files

Implement some tests for com.android.documentsui.CopyService.

- Add a unit test for CopyService.
- Make some changes to StubProvider to make it more configurable, for
  testing.

Change-Id: I3d726099feaf6b7a3fdd40bf2449f4ee3e848d77
parent 5c1e3065
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target guava

LOCAL_PACKAGE_NAME := DocumentsUITests
LOCAL_INSTRUMENTATION_FOR := DocumentsUI
+281 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.model.DocumentInfo.getCursorString;

import android.app.NotificationManager;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.RemoteException;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.test.MoreAsserts;
import android.test.ServiceTestCase;
import android.util.Log;

import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
import com.google.common.collect.Lists;

import libcore.io.IoUtils;
import libcore.io.Streams;

import org.mockito.Mockito;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CopyTest extends ServiceTestCase<CopyService> {

    public CopyTest() {
        super(CopyService.class);
    }

    private static String TAG = "CopyTest";
    // This must match the authority for the StubProvider.
    private static String AUTHORITY = "com.android.documentsui.stubprovider";
    private List<RootInfo> mRoots;
    private Context mContext;
    private ContentResolver mResolver;
    private ContentProviderClient mClient;
    private NotificationManager mNotificationManager;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        setupTestContext();

        mResolver = mContext.getContentResolver();
        mClient = mResolver.acquireContentProviderClient(AUTHORITY);

        // Reset the stub provider's storage.
        mClient.call("clear", "", null);

        mRoots = Lists.newArrayList();
        Uri queryUri = DocumentsContract.buildRootsUri(AUTHORITY);
        Cursor cursor = null;
        try {
            cursor = mClient.query(queryUri, null, null, null, null);
            while (cursor.moveToNext()) {
                final RootInfo root = RootInfo.fromRootsCursor(AUTHORITY, cursor);
                final String id = root.rootId;
                mRoots.add(root);
            }
        } finally {
            IoUtils.closeQuietly(cursor);
        }

    }

    @Override
    protected void tearDown() throws Exception {
        mClient.release();
        super.tearDown();
    }

    public List<Uri> setupTestFiles() throws Exception {
        Uri rootUri = DocumentsContract.buildDocumentUri(AUTHORITY, mRoots.get(0).documentId);
        List<Uri> testFiles = Lists.newArrayList(
                DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test0.txt"),
                DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test1.txt"),
                DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test2.txt")
        );
        String testContent[] = {
                "The five boxing wizards jump quickly",
                "The quick brown fox jumps over the lazy dog",
                "Jackdaws love my big sphinx of quartz"
        };
        for (int i = 0; i < testFiles.size(); ++i) {
            ParcelFileDescriptor pfd = null;
            OutputStream out = null;
            try {
                pfd = mClient.openFile(testFiles.get(i), "w");
                out = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
                out.write(testContent[i].getBytes());
            } finally {
                IoUtils.closeQuietly(out);
            }
        }
        return testFiles;
    }

    /**
     * Test copying a single file.
     */
    public void testCopyFile() throws Exception {
        Uri testFile = setupTestFiles().get(0);

        // Just copy one file.
        copyToDestination(Lists.newArrayList(testFile));

        // A call to NotificationManager.cancel marks the end of the copy operation.
        Mockito.verify(mNotificationManager, Mockito.timeout(1000)).cancel(Mockito.anyString(),
                Mockito.anyInt());

        // Verify that one file was copied; check file contents.
        assertDstFileCountEquals(1);
        assertCopied(testFile);
    }

    /**
     * Test copying multiple files.
     */
    public void testCopyMultipleFiles() throws Exception {
        List<Uri> testFiles = setupTestFiles();
        // Copy all the test files.
        copyToDestination(testFiles);

        // A call to NotificationManager.cancel marks the end of the copy operation.
        Mockito.verify(mNotificationManager, Mockito.timeout(1000)).cancel(Mockito.anyString(),
                Mockito.anyInt());

        assertDstFileCountEquals(3);
        for (Uri testFile : testFiles) {
            assertCopied(testFile);
        }
    }

    /**
     * Copies the given files to a pre-determined destination.
     *
     * @throws FileNotFoundException
     */
    private void copyToDestination(List<Uri> srcs) throws FileNotFoundException {
        final ArrayList<DocumentInfo> srcDocs = Lists.newArrayList();
        for (Uri src : srcs) {
            srcDocs.add(DocumentInfo.fromUri(mResolver, src));
        }

        final Uri dst = DocumentsContract.buildDocumentUri(AUTHORITY, mRoots.get(1).documentId);
        DocumentStack stack = new DocumentStack();
        stack.push(DocumentInfo.fromUri(mResolver, dst));
        final Intent copyIntent = new Intent(mContext, CopyService.class);
        copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST, srcDocs);
        copyIntent.putExtra(CopyService.EXTRA_STACK, (Parcelable) stack);

        startService(copyIntent);
    }

    /**
     * Returns a count of the files in the given directory.
     */
    private void assertDstFileCountEquals(int expected) throws RemoteException {
        final Uri queryUri = DocumentsContract.buildChildDocumentsUri(AUTHORITY,
                mRoots.get(1).documentId);
        Cursor c = null;
        int count = 0;
        try {
            c = mClient.query(queryUri, null, null, null, null);
            count = c.getCount();
        } finally {
            IoUtils.closeQuietly(c);
        }
        assertEquals("Incorrect file count after copy", expected, count);
    }

    /**
     * Verifies that the file pointed to by the given URI was correctly copied to the destination.
     */
    private void assertCopied(Uri src) throws Exception {
        Cursor cursor = null;
        String srcName = null;
        try {
            cursor = mClient.query(src, null, null, null, null);
            if (cursor.moveToFirst()) {
                srcName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
            }
        } finally {
            IoUtils.closeQuietly(cursor);
        }
        Uri dst = getDstFileUri(srcName);

        InputStream in0 = null;
        InputStream in1 = null;
        try {
            in0 = new ParcelFileDescriptor.AutoCloseInputStream(mClient.openFile(src, "r"));
            in1 = new ParcelFileDescriptor.AutoCloseInputStream(mClient.openFile(dst, "r"));

            byte[] buffer0 = Streams.readFully(in0);
            byte[] buffer1 = Streams.readFully(in1);

            MoreAsserts.assertEquals(buffer0, buffer1);
        } finally {
            IoUtils.closeQuietly(in0);
            IoUtils.closeQuietly(in1);
        }
    }

    /**
     * Generates a file URI from a given filename. This assumes the file already exists in the
     * destination root.
     */
    private Uri getDstFileUri(String filename) throws RemoteException {
        final Uri dstFileQuery = DocumentsContract.buildChildDocumentsUri(AUTHORITY,
                mRoots.get(1).documentId);
        Cursor cursor = null;
        try {
            // StubProvider doesn't seem to support query strings; filter the results manually.
            cursor = mClient.query(dstFileQuery, null, null, null, null);
            while (cursor.moveToNext()) {
                if (filename.equals(getCursorString(cursor, Document.COLUMN_DISPLAY_NAME))) {
                    return DocumentsContract.buildDocumentUri(AUTHORITY,
                            getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
                }
            }
        } finally {
            IoUtils.closeQuietly(cursor);
        }
        return null;
    }

    /**
     * Sets up a ContextWrapper that substitutes a stub NotificationManager. This allows the test to
     * listen for notification events, to gauge copy progress.
     */
    private void setupTestContext() {
        mContext = getSystemContext();
        System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());

        mNotificationManager = Mockito.spy((NotificationManager) mContext
                .getSystemService(Context.NOTIFICATION_SERVICE));

        // Insert a stub NotificationManager that enables us to listen for when copying is complete.
        setContext(new ContextWrapper(mContext) {
            @Override
            public Object getSystemService(String name) {
                if (Context.NOTIFICATION_SERVICE.equals(name)) {
                    return mNotificationManager;
                } else {
                    return super.getSystemService(name);
                }
            }
        });
    }
}
+200 −60

File changed.

Preview size limit exceeded, changes collapsed.