chromium/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadUserInitiatedTaskManagerTest.java

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.download;

import android.app.Notification;
import android.content.Context;

import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;

import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.AdvancedMockContext;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.notifications.NotificationWrapperBuilderFactory;
import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.components.background_task_scheduler.BackgroundTask.TaskFinishedCallback;

/** Test for {@link DownloadUserInitiatedTaskManager}. */
@RunWith(ChromeJUnit4ClassRunner.class)
@Batch(Batch.UNIT_TESTS)
public final class DownloadUserInitiatedTaskManagerTest {
    private static final int FAKE_DOWNLOAD_1 = 111;
    private static final int FAKE_DOWNLOAD_2 = 222;

    private static final int TASK_ID_1 = 55;
    private static final int TASK_ID_2 = 56;

    private static final String FAKE_NOTIFICATION_CHANNEL = "DownloadUserInitiatedTaskManagerTest";

    private MockDownloadUserInitiatedTaskManager mDownloadUITaskManager;
    private Notification mNotification;
    private Context mContext;

    @Mock private TaskFinishedCallback mCallback1;
    @Mock private TaskFinishedCallback mCallback2;

    TaskFinishedCallback mCallback3 = Mockito.mock(TaskFinishedCallback.class);
    TaskFinishedCallback mCallback4 = Mockito.mock(TaskFinishedCallback.class);

    public static class MockDownloadUserInitiatedTaskManager
            extends DownloadUserInitiatedTaskManager {
        public MockDownloadUserInitiatedTaskManager() {}

        @Override
        boolean isEnabled() {
            return true;
        }

        public void assertPinnedNotificationId(int notificationId) {
            Assert.assertEquals(notificationId, mPinnedNotificationId);
        }
    }

    @Before
    public void setUp() {
        // MockitoAnnotations.initMocks(this);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mContext = new AdvancedMockContext(ApplicationProvider.getApplicationContext());
                    mDownloadUITaskManager = new MockDownloadUserInitiatedTaskManager();

                    mNotification =
                            NotificationWrapperBuilderFactory.createNotificationWrapperBuilder(
                                            ChromeChannelDefinitions.ChannelId.DOWNLOADS)
                                    .setSmallIcon(
                                            org.chromium.chrome.R.drawable
                                                    .ic_file_download_white_24dp)
                                    .setContentTitle(FAKE_NOTIFICATION_CHANNEL)
                                    .setContentText(FAKE_NOTIFICATION_CHANNEL)
                                    .build();
                });
    }

    @Test
    @SmallTest
    @Feature({"Download"})
    public void testCallbackNotInvokedForNonInProgressStates() {
        // Set task callbacks.
        mDownloadUITaskManager.setTaskNotificationCallback(TASK_ID_1, mCallback3);

        // Start a download.
        mDownloadUITaskManager.updateDownloadStatus(
                mContext,
                DownloadNotificationService.DownloadStatus.FAILED,
                FAKE_DOWNLOAD_1,
                mNotification);
        Mockito.verify(mCallback3, Mockito.times(0))
                .setNotification(FAKE_DOWNLOAD_1, mNotification);
        mDownloadUITaskManager.assertPinnedNotificationId(-1);
    }

    @Test
    @SmallTest
    @Feature({"Download"})
    public void testAddMultipleCallbacks() {
        // Set task callbacks.
        mDownloadUITaskManager.setTaskNotificationCallback(TASK_ID_1, mCallback3);
        mDownloadUITaskManager.setTaskNotificationCallback(TASK_ID_2, mCallback4);

        // Start a download.
        mDownloadUITaskManager.updateDownloadStatus(
                mContext,
                DownloadNotificationService.DownloadStatus.IN_PROGRESS,
                FAKE_DOWNLOAD_1,
                mNotification);
        mDownloadUITaskManager.assertPinnedNotificationId(FAKE_DOWNLOAD_1);
        Mockito.verify(mCallback3).setNotification(FAKE_DOWNLOAD_1, mNotification);
        Mockito.verify(mCallback4).setNotification(FAKE_DOWNLOAD_1, mNotification);
    }

    @Test
    @SmallTest
    @Feature({"Download"})
    public void testSetNotificationAfterFinishTask() {
        // Set task callbacks.
        mDownloadUITaskManager.setTaskNotificationCallback(TASK_ID_1, mCallback3);

        // Finish the job. Equivalently the callback should be set to null.
        mDownloadUITaskManager.setTaskNotificationCallback(TASK_ID_1, null);

        // Start a download.
        mDownloadUITaskManager.updateDownloadStatus(
                mContext,
                DownloadNotificationService.DownloadStatus.IN_PROGRESS,
                FAKE_DOWNLOAD_1,
                mNotification);
        Mockito.verify(mCallback3, Mockito.times(0))
                .setNotification(FAKE_DOWNLOAD_1, mNotification);
        mDownloadUITaskManager.assertPinnedNotificationId(-1);
    }

    @Test
    @SmallTest
    @UiThreadTest
    @Feature({"Download"})
    public void testStartDownloadAndCompleteAlongWithInactiveOtherDownloads() {
        mDownloadUITaskManager.setTaskNotificationCallback(TASK_ID_1, mCallback3);
        // Start a download and complete.
        mDownloadUITaskManager.updateDownloadStatus(
                mContext,
                DownloadNotificationService.DownloadStatus.IN_PROGRESS,
                FAKE_DOWNLOAD_1,
                mNotification);
        mDownloadUITaskManager.assertPinnedNotificationId(FAKE_DOWNLOAD_1);
        Mockito.verify(mCallback3).setNotification(FAKE_DOWNLOAD_1, mNotification);

        Mockito.clearInvocations(mCallback3);
        mDownloadUITaskManager.updateDownloadStatus(
                mContext,
                DownloadNotificationService.DownloadStatus.COMPLETED,
                FAKE_DOWNLOAD_1,
                mNotification);
        mDownloadUITaskManager.assertPinnedNotificationId(FAKE_DOWNLOAD_1);
        Mockito.verify(mCallback3, Mockito.times(0))
                .setNotification(FAKE_DOWNLOAD_1, mNotification);

        // Service does not get affected by addition of inactive download.
        Mockito.clearInvocations(mCallback3);
        mDownloadUITaskManager.updateDownloadStatus(
                mContext,
                DownloadNotificationService.DownloadStatus.CANCELLED,
                FAKE_DOWNLOAD_2,
                mNotification);
        mDownloadUITaskManager.assertPinnedNotificationId(FAKE_DOWNLOAD_1);
        Mockito.verify(mCallback3, Mockito.times(0))
                .setNotification(FAKE_DOWNLOAD_1, mNotification);
    }

    @Test
    @SmallTest
    @UiThreadTest
    @Feature({"Download"})
    public void testDownloadResumeAfterNetworkInterruption() {
        mDownloadUITaskManager.setTaskNotificationCallback(TASK_ID_1, mCallback3);
        // Start a download.
        mDownloadUITaskManager.updateDownloadStatus(
                mContext,
                DownloadNotificationService.DownloadStatus.IN_PROGRESS,
                FAKE_DOWNLOAD_1,
                mNotification);
        mDownloadUITaskManager.assertPinnedNotificationId(FAKE_DOWNLOAD_1);
        Mockito.verify(mCallback3).setNotification(FAKE_DOWNLOAD_1, mNotification);

        // Start another job (due to network interruption).
        mDownloadUITaskManager.setTaskNotificationCallback(TASK_ID_1, mCallback4);
        mDownloadUITaskManager.updateDownloadStatus(
                mContext,
                DownloadNotificationService.DownloadStatus.IN_PROGRESS,
                FAKE_DOWNLOAD_1,
                mNotification);
        mDownloadUITaskManager.assertPinnedNotificationId(FAKE_DOWNLOAD_1);
        Mockito.verify(mCallback4).setNotification(FAKE_DOWNLOAD_1, mNotification);
    }
}