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

Commit f72d2dc9 authored by Rana Mouawi's avatar Rana Mouawi Committed by Android (Google) Code Review
Browse files

Merge "Add unit tests for BugreportProgressService in Shell" into main

parents 454655dd c4a0fa49
Loading
Loading
Loading
Loading
+25 −20
Original line number Diff line number Diff line
@@ -767,7 +767,8 @@ public class BugreportProgressService extends Service {
    }

    // Sets up BugreportInfo. If needed, creates bugreport and screenshot files.
    private BugreportInfo setupFilesAndCreateBugreportInfo(
    @VisibleForTesting
    BugreportInfo setupFilesAndCreateBugreportInfo(
            Intent intent,
            int bugreportType,
            String baseName,
@@ -2081,7 +2082,8 @@ public class BugreportProgressService extends Service {
    /**
     * Information about a bugreport process while its in progress.
     */
    private static final class BugreportInfo implements Parcelable {
    @VisibleForTesting
    static final class BugreportInfo implements Parcelable {
        private final Context context;

        /**
@@ -2191,7 +2193,7 @@ public class BugreportProgressService extends Service {
        final long nonce;

        @Nullable
        public List<Uri> extraAttachments = null;
        List<Uri> extraAttachments = null;

        private final Object mLock = new Object();

@@ -2490,9 +2492,10 @@ public class BugreportProgressService extends Service {
     * <li>If no URI is provided in the bugreport request, Shell will create a bugreport file and
     *     manage its lifecycle.
     */
    private static final class BugreportLocationInfo {
    @VisibleForTesting
    static final class BugreportLocationInfo {
        /** Path of the main bugreport file. */
        @Nullable private File mBugreportFile;
        @Nullable File mBugreportFile;

        /** Uri to bugreport location. */
        @Nullable private Uri mBugreportUri;
@@ -2501,7 +2504,8 @@ public class BugreportProgressService extends Service {
            this.mBugreportFile = bugreportFile;
        }

        BugreportLocationInfo(Uri bugreportUri, File bugreportsDir, String baseName, String name) {
        BugreportLocationInfo(Uri bugreportUri, File bugreportsDir, String baseName,
                String name) {
            if (bugreportUri != null) {
                this.mBugreportUri = bugreportUri;
            } else {
@@ -2509,7 +2513,7 @@ public class BugreportProgressService extends Service {
            }
        }

        private boolean maybeCreateBugreportFile() {
        boolean maybeCreateBugreportFile() {
            if (mBugreportFile != null && mBugreportFile.exists()) {
                Log.e(
                        TAG,
@@ -2522,13 +2526,13 @@ public class BugreportProgressService extends Service {
            return true;
        }

        private void createBugreportFile() {
        void createBugreportFile() {
            if (mBugreportUri == null) {
                createReadWriteFile(mBugreportFile);
            }
        }

        private ParcelFileDescriptor getBugreportFd(Context context) {
        ParcelFileDescriptor getBugreportFd(Context context) {
            if (mBugreportUri != null) {
                try {
                    return context.getContentResolver()
@@ -2555,7 +2559,7 @@ public class BugreportProgressService extends Service {
            mBugreportFile.delete();
        }

        private boolean isValidBugreportResult() {
       boolean isValidBugreportResult() {
            if (mBugreportFile != null) {
                return mBugreportFile.exists() && mBugreportFile.canRead();
            }
@@ -2564,7 +2568,7 @@ public class BugreportProgressService extends Service {
            return true;
        }

        private void maybeDeleteEmptyBugreport() {
        void maybeDeleteEmptyBugreport() {
            if (mBugreportFile == null) {
                // This means a URI is provided and shell is not responsible for the file's
                // lifecycle.
@@ -2590,14 +2594,14 @@ public class BugreportProgressService extends Service {
            }
        }

        private boolean isPlainText() {
        boolean isPlainText() {
            if (mBugreportFile != null) {
                return mBugreportFile.getName().toLowerCase().endsWith(".txt");
            }
            return false;
        }

        private boolean isFileEmpty(Context context) {
        boolean isFileEmpty(Context context) {
            if (mBugreportFile != null) {
                return mBugreportFile.length() == 0;
            }
@@ -2614,7 +2618,7 @@ public class BugreportProgressService extends Service {
                    + '}';
        }

        private String getBugreportPath() {
        String getBugreportPath() {
            if (mBugreportUri != null) {
                return mBugreportUri.getLastPathSegment();
            }
@@ -2630,13 +2634,14 @@ public class BugreportProgressService extends Service {
     * <li>If no URI is provided in the bugreport request, Shell will create the screenshot file and
     *     manage its lifecycle.
     */
    private static final class ScreenshotLocationInfo {
    @VisibleForTesting
    static final class ScreenshotLocationInfo {

        /** Uri to screenshot location. */
        @Nullable private Uri mScreenshotUri;

        /** Path to screenshot files. */
        private List<File> mScreenshotFiles = new ArrayList<>(1);
        List<File> mScreenshotFiles = new ArrayList<>(1);

        ScreenshotLocationInfo(Uri screenshotUri) {
            if (screenshotUri != null) {
@@ -2644,7 +2649,7 @@ public class BugreportProgressService extends Service {
            }
        }

        private ParcelFileDescriptor getScreenshotFd(Context context) {
        ParcelFileDescriptor getScreenshotFd(Context context) {
            if (mScreenshotUri != null) {
                try {
                    return context.getContentResolver()
@@ -2671,14 +2676,14 @@ public class BugreportProgressService extends Service {
                    + '}';
        }

        private String getScreenshotPath() {
        String getScreenshotPath() {
            if (mScreenshotUri != null) {
                return mScreenshotUri.getLastPathSegment();
            }
            return getScreenshotForIntent();
        }

        private void renameScreenshots(String initialName, String name) {
        void renameScreenshots(String initialName, String name) {
            if (mScreenshotUri != null) {
                // If a screenshot uri is provided, then shell is not responsible for the
                // screenshot's naming.
@@ -2712,7 +2717,7 @@ public class BugreportProgressService extends Service {
            mScreenshotFiles = renamedFiles;
        }

        private void deleteEmptyScreenshots() {
        void deleteEmptyScreenshots() {
            mScreenshotFiles.removeIf(
                    file -> {
                        final long length = file.length();
+425 −3
Original line number Diff line number Diff line
@@ -19,26 +19,47 @@ import static com.android.shell.BugreportProgressService.findSendToAccount;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import static junit.framework.TestCase.assertTrue;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.BugreportParams;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.os.UserManager;

import androidx.core.content.FileProvider;

import android.test.mock.MockContext;
import android.util.Pair;

import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import junit.framework.Assert;

import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@@ -46,13 +67,34 @@ import java.util.List;
 * Test for {@link BugreportProgressServiceTest}.
 *
 * Usage:
   adb shell am instrument -w \
     -e class com.android.shell.BugreportProgressServiceTest \
     com.android.shell.tests
 * adb shell am instrument -w \
 * -e class com.android.shell.BugreportProgressServiceTest \
 * com.android.shell.tests
 */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BugreportProgressServiceTest {

    public static final String BASE_NAME = "baseName";
    public static final String NAME = "name";
    public static final String BUGREPORT_TXT = "bugreport.txt";
    public static final String BUGREPORT_ZIP = "bugreport.zip";
    public static final String SCREENSHOT_PNG = "screenshot.png";
    public static final String RENAMED_SCREENSHOT_PNG = "renamed_screenshot.png";
    public static final String BASE_BUGREPORT = "bugreport";
    public static final String REPORT_NAME = "my_report";
    public static final String BUGREPORT_TITLE = "My Bug Report";
    public static final String BUGREPORT_DESCRIPTION = "Details of the bug";

    @Rule
    public TemporaryFolder mTempFolder = new TemporaryFolder();
    private File mBugreportsDir;

    @Before
    public void setUp() throws IOException {
        mBugreportsDir = mTempFolder.newFolder("bugreports");
    }

    private static class MyContext extends MockContext {
        @Mock
        public UserManager userManager;
@@ -347,4 +389,384 @@ public class BugreportProgressServiceTest {
        checkFindSendToAccount(0, "abc@gmail.com", "gmail.com");
        checkFindSendToAccount(0, "abc@gmail.com", "@gmail.com");
    }

    @Test
    public void testMaybeCreateBugreportFile_withoutUri_createsFile() {
        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(/* bugreportUri= */ null,
                        mTempFolder.getRoot(), BASE_NAME, NAME);

        boolean result = info.maybeCreateBugreportFile();

        assertTrue("maybeCreateBugreportFile should return true when file does not exist", result);
        File createdFile = new File(mTempFolder.getRoot(), BASE_NAME + "-" + NAME + ".zip");
        assertTrue("Bugreport file should be created", createdFile.exists());
    }


    @Test
    public void testMaybeCreateBugreportFile_withoutUri_doesNotCreateFile() throws IOException {
        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(/* bugreportUri= */ null,
                        mTempFolder.getRoot(), BASE_NAME, NAME);

        mTempFolder.newFile(BASE_NAME + "-" + NAME + ".zip");

        boolean result = info.maybeCreateBugreportFile();

        assertFalse("maybeCreateBugreportFile should return false when file exist", result);
    }


    @Test
    public void testIsPlainText_withTxtFile() throws IOException {
        File bugreportFile = mTempFolder.newFile(BUGREPORT_TXT);

        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(bugreportFile);

        assertTrue("isPlainText should return true for .txt bugreport files", info.isPlainText());

    }

    @Test
    public void testIsPlainText_withZipFile() throws IOException {
        File zipBugreportFile = mTempFolder.newFile(BUGREPORT_ZIP);

        BugreportProgressService.BugreportLocationInfo zipInfo =
                new BugreportProgressService.BugreportLocationInfo(zipBugreportFile);

        assertFalse("isPlainText should return false for non-.txt bugreport files",
                zipInfo.isPlainText());
    }

    @Test
    public void testIsFileEmpty_withEmptyFile() throws IOException {
        File bugreportFile = mTempFolder.newFile(BUGREPORT_TXT);

        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(bugreportFile);

        assertTrue("isFileEmpty should return true for an empty file",
                info.isFileEmpty(mTestContext));
    }

    @Test
    public void testIsFileEmpty_withNonEmptyFile() throws IOException {
        File bugreportFile = mTempFolder.newFile(BUGREPORT_TXT);
        try (FileOutputStream fos = new FileOutputStream(bugreportFile)) {
            fos.write("Bugreport data".getBytes());
        }

        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(bugreportFile);

        assertFalse("isFileEmpty should return false for a non-empty file",
                info.isFileEmpty(mTestContext));
    }


    @Test
    public void testIsValidBugreportResult_withUri() {
        Uri mockUri = Uri.parse("content://com.android.shell/bugreport.txt");
        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(mockUri, mBugreportsDir,
                        BASE_NAME, NAME);

        assertTrue("isValidBugreportResult should always return true for URI case",
                info.isValidBugreportResult());
    }

    @Test
    public void testIsValidBugreportResult_withFile_createdFile_returnsTrue() {
        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(/* bugreportUri= */ null,
                        mBugreportsDir, BASE_NAME, NAME);
        info.createBugreportFile();
        assertTrue("isValidBugreportResult should return true if the file exists and is readable",
                info.isValidBugreportResult());
    }

    @Test
    public void testIsValidBugreportResult_withFile_withoutCreatedFile_return_False() {
        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(/* bugreportUri= */ null,
                        mBugreportsDir, BASE_NAME, NAME);

        assertFalse("isValidBugreportResult should return false if the file does not exist",
                info.isValidBugreportResult());
    }

    @Test
    public void testMaybeDeleteEmptyBugreport_withEmptyFile() {
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();

        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(/* bugreportUri= */ null,
                        mBugreportsDir, BASE_NAME, NAME);
        info.createBugreportFile();
        assertNotNull("Bugreport file descriptor should still be accessible",
                info.getBugreportFd(appContext));

        info.maybeDeleteEmptyBugreport();

        assertNull("Bugreport file descriptor should not still be accessible",
                info.getBugreportFd(appContext));
    }

    @Test
    public void testGetBugreportPath_withFile() throws IOException {
        File bugreportFile = mTempFolder.newFile(BUGREPORT_TXT);

        BugreportProgressService.BugreportLocationInfo info =
                new BugreportProgressService.BugreportLocationInfo(bugreportFile);

        assertEquals("getBugreportPath should return the absolute file path",
                bugreportFile.getAbsolutePath(), info.getBugreportPath());
    }

    @Test
    public void testGetScreenshotFd_withFile() throws IOException {
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
        File screenshotFile = mTempFolder.newFile(SCREENSHOT_PNG);

        BugreportProgressService.ScreenshotLocationInfo info =
                new BugreportProgressService.ScreenshotLocationInfo(null);
        info.mScreenshotFiles.add(screenshotFile);

        ParcelFileDescriptor fd = info.getScreenshotFd(appContext);

        assertNotNull("File descriptor should not be null for file case", fd);
        fd.close();
    }

    @Test
    public void testGetScreenshotPath_withFile() throws IOException {
        File screenshotFile = mTempFolder.newFile(SCREENSHOT_PNG);
        screenshotFile.createNewFile();

        BugreportProgressService.ScreenshotLocationInfo info =
                new BugreportProgressService.ScreenshotLocationInfo(null);
        info.mScreenshotFiles.add(screenshotFile);

        assertEquals("getScreenshotPath should return the correct path",
                screenshotFile.getAbsolutePath(),
                info.getScreenshotPath());
    }

    @Test
    public void testRenameScreenshots_withFile() throws IOException {
        File screenshotFile = mTempFolder.newFile(SCREENSHOT_PNG);
        screenshotFile.createNewFile();
        try (FileOutputStream fos = new FileOutputStream(screenshotFile)) {
            fos.write(0x00);
        }

        BugreportProgressService.ScreenshotLocationInfo info =
                new BugreportProgressService.ScreenshotLocationInfo(null);
        info.mScreenshotFiles.add(screenshotFile);

        info.renameScreenshots(SCREENSHOT_PNG, RENAMED_SCREENSHOT_PNG);

        assertTrue("Screenshot file should be renamed",
                info.mScreenshotFiles.getFirst().getAbsolutePath()
                        .contains(RENAMED_SCREENSHOT_PNG));
    }

    @Test
    public void testDeleteEmptyScreenshots_withNonEmptyFile() throws IOException {
        File screenshotFile = mTempFolder.newFile(SCREENSHOT_PNG);
        screenshotFile.createNewFile();
        try (FileOutputStream fos = new FileOutputStream(screenshotFile)) {
            fos.write(0x00);
        }

        BugreportProgressService.ScreenshotLocationInfo info =
                new BugreportProgressService.ScreenshotLocationInfo(null);
        info.mScreenshotFiles.add(screenshotFile);

        info.deleteEmptyScreenshots();

        assertFalse("Screenshot list should not be empty", info.mScreenshotFiles.isEmpty());
    }

    @Test
    public void testDeleteEmptyScreenshots_withEmptyFile() throws IOException {
        File screenshotFile = mTempFolder.newFile(SCREENSHOT_PNG);
        screenshotFile.createNewFile();

        BugreportProgressService.ScreenshotLocationInfo info =
                new BugreportProgressService.ScreenshotLocationInfo(null);
        info.mScreenshotFiles.add(screenshotFile);

        info.deleteEmptyScreenshots();

        assertTrue("Screenshot list should be empty", info.mScreenshotFiles.isEmpty());
    }

    @Test
    public void testGetScreenshotFd_withUri() throws IOException {
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
        BugreportProgressService.ScreenshotLocationInfo info =
                getScreenshotLocationInfoFromUri(SCREENSHOT_PNG);

        ParcelFileDescriptor fd = info.getScreenshotFd(appContext);

        assertNotNull("File descriptor should not be null for URI case", fd);
        fd.close();
    }

    @Test
    public void testGetScreenshotPath_withUri() throws IOException {
        BugreportProgressService.ScreenshotLocationInfo info =
                getScreenshotLocationInfoFromUri(SCREENSHOT_PNG);

        assertEquals("getScreenshotPath should return the screenshot name when URI is "
                        + "provided", SCREENSHOT_PNG, info.getScreenshotPath());
    }


    @Test
    public void testMaybeCreateBugreportFile_withUriProvided() throws IOException {
        BugreportProgressService.BugreportLocationInfo info = getBugreportLocationInfoFromUri(
                BUGREPORT_TXT);

        boolean result = info.maybeCreateBugreportFile();

        assertTrue("maybeCreateBugreportFile should return true if a URI is provided",
                result);
        assertNull("info.mBugreportFile should be null", info.mBugreportFile);
    }

    @Test
    public void testGetBugreportPath_withUri() throws IOException {
        BugreportProgressService.BugreportLocationInfo info = getBugreportLocationInfoFromUri(
                BUGREPORT_TXT);

        assertEquals("getBugreportPath should return bugreport file name when a URI is "
                        + "provided", BUGREPORT_TXT, info.getBugreportPath());
    }

    @Test
    public void testIsFileEmpty_withUri() throws IOException {
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
        BugreportProgressService.BugreportLocationInfo info = getBugreportLocationInfoFromUri(
                BUGREPORT_TXT);

        assertTrue("isFileEmpty should return false when URI is provided",
                info.isFileEmpty(appContext));
    }

    @Test
    public void testGetBugreportFd_withUri() throws Exception {
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
        BugreportProgressService.BugreportLocationInfo info = getBugreportLocationInfoFromUri(
                BUGREPORT_TXT);

        ParcelFileDescriptor fd = info.getBugreportFd(appContext);

        assertNotNull("File descriptor should not be null for URI case", fd);
        fd.close();
    }

    @Test
    public void testIsPlainText_withUri() throws IOException {
        BugreportProgressService.BugreportLocationInfo info = getBugreportLocationInfoFromUri(
                BUGREPORT_TXT);

        assertFalse("isPlainText should return false when URI is used", info.isPlainText());
    }

    @Test
    public void testSetupFilesAndCreateBugreportInfo_withWearBugreport() throws IOException {
        BugreportProgressService service = new BugreportProgressService();

        File fileBugreport = mTempFolder.newFile(BUGREPORT_TXT);
        Uri bugreportUri=  Uri.fromFile(fileBugreport);
        File screenshotFile = mTempFolder.newFile(SCREENSHOT_PNG);
        Uri screenshotUri = Uri.fromFile(screenshotFile);
        Intent fakeIntent = new Intent();
        ArrayList<Uri> fakeUris = new ArrayList<>();
        fakeUris.add(bugreportUri);
        fakeUris.add(screenshotUri);
        fakeIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, fakeUris);

        long uniqueNonce = System.currentTimeMillis();
        List<Uri> additionalFiles = new ArrayList<>();

        BugreportProgressService.BugreportInfo bugreportInfo =
                service.setupFilesAndCreateBugreportInfo(fakeIntent,
                        BugreportParams.BUGREPORT_MODE_WEAR,
                        BASE_BUGREPORT,
                        REPORT_NAME,
                        BUGREPORT_TITLE,
                        BUGREPORT_DESCRIPTION,
                        uniqueNonce,
                        additionalFiles);

        Assert.assertNotNull("BugreportInfo should not be null", bugreportInfo);
        assertEquals("BugreportLocationInfo should use provided URI",
                fileBugreport.getName(),
                bugreportInfo.bugreportLocationInfo.getBugreportPath());
        assertEquals("ScreenshotLocationInfo should use provided URI",
                screenshotFile.getName(),
                bugreportInfo.screenshotLocationInfo.getScreenshotPath());
    }


    @Test
    public void testSetupFilesAndCreateBugreportInfo_withoutWearBugreport() throws IOException {
        BugreportProgressService service = new BugreportProgressService();

        File fileBugreport = mTempFolder.newFile(BUGREPORT_TXT);
        Uri bugreportUri=  Uri.fromFile(fileBugreport);
        File screenshotFile = mTempFolder.newFile(SCREENSHOT_PNG);
        Uri screenshotUri = Uri.fromFile(screenshotFile);
        Intent fakeIntent = new Intent();
        ArrayList<Uri> fakeUris = new ArrayList<>();
        fakeUris.add(bugreportUri);
        fakeUris.add(screenshotUri);
        fakeIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, fakeUris);

        long uniqueNonce = System.currentTimeMillis();
        List<Uri> additionalFiles = new ArrayList<>();

        BugreportProgressService.BugreportInfo bugreportInfo =
                service.setupFilesAndCreateBugreportInfo(fakeIntent,
                        BugreportParams.BUGREPORT_MODE_REMOTE,
                        BASE_BUGREPORT,
                        REPORT_NAME,
                        BUGREPORT_TITLE,
                        BUGREPORT_DESCRIPTION,
                        uniqueNonce,
                        additionalFiles);

        Assert.assertNotNull("BugreportInfo should not be null", bugreportInfo);
        assertEquals("BugreportLocationInfo should ignore provided URI",
                "/bugreport-my_report.zip",
                bugreportInfo.bugreportLocationInfo.getBugreportPath());
        assertEquals("ScreenshotLocationInfo should ignore provided URI",
                "/screenshot-my_report-default.png",
                bugreportInfo.screenshotLocationInfo.getScreenshotPath());
    }

    @NotNull
    private BugreportProgressService.BugreportLocationInfo getBugreportLocationInfoFromUri(
            String fileName) throws IOException {
        File file = mTempFolder.newFile(fileName);
        Uri uri = Uri.fromFile(file);

        return new BugreportProgressService.BugreportLocationInfo(uri, file.getParentFile(),
                BASE_NAME,
                NAME);
    }


    @NotNull
    private BugreportProgressService.ScreenshotLocationInfo getScreenshotLocationInfoFromUri(
            String fileName) throws IOException {
        File file = mTempFolder.newFile(fileName);
        Uri uri = Uri.fromFile(file);
        return new BugreportProgressService.ScreenshotLocationInfo(uri);
    }
}