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

// Copyright 2018 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.os.Looper;

import androidx.test.filters.SmallTest;

import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.chromium.base.ThreadUtils;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
import org.chromium.components.browser_ui.notifications.ThrottlingNotificationScheduler;
import org.chromium.components.offline_items_collection.ContentId;

import java.util.UUID;

/** Tests of {@link SystemDownloadNotifier}. */
@RunWith(BaseJUnit4ClassRunner.class)
@Batch(Batch.PER_CLASS)
@DisabledTest(message = "https://crbug.com/349630317")
public class SystemDownloadNotifierTest {
    private final SystemDownloadNotifier mSystemDownloadNotifier = new SystemDownloadNotifier();
    private MockDownloadNotificationService mMockDownloadNotificationService;

    @Mock DownloadManagerService mDownloadManagerService;

    @BeforeClass
    public static void beforeClass() {
        Looper.prepare();
    }

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

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    DownloadManagerService.setDownloadManagerService(mDownloadManagerService);
                    mMockDownloadNotificationService = new MockDownloadNotificationService();
                    mSystemDownloadNotifier.setDownloadNotificationService(
                            mMockDownloadNotificationService);
                });
    }

    @After
    public void tearDown() {
        ThrottlingNotificationScheduler.getInstance().clear();
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    DownloadManagerService.setDownloadManagerService(null);
                });
    }

    private DownloadInfo getDownloadInfo(ContentId id) {
        return getDownloadInfoBuilder(id).build();
    }

    private DownloadInfo.Builder getDownloadInfoBuilder(ContentId id) {
        return new DownloadInfo.Builder()
                .setFileName("foo")
                .setBytesReceived(100)
                .setDownloadGuid(UUID.randomUUID().toString())
                .setContentId(id);
    }

    private void waitForNotifications(int numberOfNotifications) {
        CriteriaHelper.pollUiThread(
                () -> {
                    Criteria.checkThat(
                            mMockDownloadNotificationService.getNumberOfNotifications(),
                            Matchers.is(numberOfNotifications));
                });
    }

    /** Tests that a single notification update will be immediately processed */
    @Test
    @SmallTest
    @Feature({"Download"})
    public void testSingleNotification() {
        mSystemDownloadNotifier.notifyDownloadProgress(
                getDownloadInfo(new ContentId("download", "1")),
                100,
                /* canDownloadWhileMetered= */ true);
        Assert.assertEquals(1, mMockDownloadNotificationService.getNumberOfNotifications());
    }

    /**
     * Tests that consecutive progress notifications can be merged together, and will be handled in
     * order.
     */
    @Test
    @SmallTest
    @Feature({"Download"})
    public void testConsecutiveProgressNotifications() {
        DownloadInfo info = getDownloadInfo(new ContentId("download", "1"));
        mSystemDownloadNotifier.notifyDownloadProgress(
                info, 100, /* canDownloadWhileMetered= */ true);
        // Create 2 more progress updates on the same download and one of them will be skipped.
        mSystemDownloadNotifier.notifyDownloadProgress(
                info, 100, /* canDownloadWhileMetered= */ true);
        mSystemDownloadNotifier.notifyDownloadProgress(
                info, 100, /* canDownloadWhileMetered= */ true);
        // Create a progress update from a new download, this should create a new notification.
        mSystemDownloadNotifier.notifyDownloadProgress(
                getDownloadInfo(new ContentId("download", "2")),
                100,
                /* canDownloadWhileMetered= */ true);
        Assert.assertEquals(1, mMockDownloadNotificationService.getNumberOfNotifications());
        int notificationId = mMockDownloadNotificationService.getLastNotificationId();
        waitForNotifications(2);
        Assert.assertEquals(
                notificationId, mMockDownloadNotificationService.getLastNotificationId());
        waitForNotifications(3);
        Assert.assertNotEquals(
                notificationId, mMockDownloadNotificationService.getLastNotificationId());
    }

    /** Tests that higher priority notification will be handled before progress notification. */
    @Test
    @SmallTest
    @Feature({"Download"})
    public void testNotificationWithDifferentPriorities() {
        DownloadInfo info = getDownloadInfo(new ContentId("download", "1"));
        mSystemDownloadNotifier.notifyDownloadProgress(
                info, 100, /* canDownloadWhileMetered= */ true);
        mSystemDownloadNotifier.notifyDownloadProgress(
                info, 100, /* canDownloadWhileMetered= */ true);
        mSystemDownloadNotifier.notifyDownloadSuccessful(
                getDownloadInfo(new ContentId("download", "2")),
                1,
                /* canResolve= */ true,
                /* isSupportedMimeType= */ true);
        Assert.assertEquals(1, mMockDownloadNotificationService.getNumberOfNotifications());
        int notificationId = mMockDownloadNotificationService.getLastNotificationId();

        // The second notification should come from the 2nd download, as it has higher priority.
        waitForNotifications(2);
        Assert.assertNotEquals(
                notificationId, mMockDownloadNotificationService.getLastNotificationId());

        waitForNotifications(3);
        Assert.assertEquals(
                notificationId, mMockDownloadNotificationService.getLastNotificationId());
    }
}