Chromium Code Reviews| Index: chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotifierBridgeUiTest.java |
| diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotifierBridgeUiTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotifierBridgeUiTest.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1e2123974589a1be7d9531c4bf19f6ec896bfcae |
| --- /dev/null |
| +++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotifierBridgeUiTest.java |
| @@ -0,0 +1,310 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// 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.items; |
| + |
| +import static org.mockito.Mockito.inOrder; |
| +import static org.mockito.Mockito.never; |
| +import static org.mockito.Mockito.times; |
| +import static org.mockito.Mockito.verify; |
| + |
| +import android.graphics.Bitmap; |
| + |
| +import org.chromium.chrome.browser.download.DownloadInfo; |
| +import org.chromium.chrome.browser.download.DownloadNotifier; |
| +import org.chromium.components.offline_items_collection.ContentId; |
| +import org.chromium.components.offline_items_collection.OfflineContentProvider; |
| +import org.chromium.components.offline_items_collection.OfflineItem; |
| +import org.chromium.components.offline_items_collection.OfflineItemState; |
| +import org.chromium.components.offline_items_collection.OfflineItemVisuals; |
| +import org.chromium.testing.local.LocalRobolectricTestRunner; |
| +import org.junit.Assert; |
| +import org.junit.Rule; |
| +import org.junit.Test; |
| +import org.junit.runner.RunWith; |
| +import org.mockito.ArgumentCaptor; |
| +import org.mockito.ArgumentMatchers; |
| +import org.mockito.InOrder; |
| +import org.mockito.Mock; |
| +import org.mockito.junit.MockitoJUnit; |
| +import org.mockito.junit.MockitoRule; |
| +import org.robolectric.annotation.Config; |
| + |
| +import java.util.ArrayList; |
| +import java.util.List; |
| + |
| +/** |
| + * Unit tests for {@link OfflineContentAggregatorNotifierBridgeUi}. Validate that it interacts with |
| + * both the {@link DownloadNotifier} and the {@link OfflineContentProvider} in expected ways. |
| + */ |
| +@RunWith(LocalRobolectricTestRunner.class) |
| +@Config(manifest = Config.NONE) |
| +public class OfflineContentAggregatorNotifierBridgeUiTest { |
| + @Mock |
| + private OfflineContentProvider mProvider; |
| + |
| + @Mock |
| + private DownloadNotifier mNotifier; |
| + |
| + @Rule |
| + public MockitoRule mMockitoRule = MockitoJUnit.rule(); |
| + |
| + private static OfflineItem buildOfflineItem(ContentId id, @OfflineItemState int state) { |
| + OfflineItem item = new OfflineItem(); |
| + item.id = id; |
| + item.state = state; |
| + return item; |
| + } |
| + |
| + @Test |
| + public void testOnlyInterestingNewItemsGetSentToTheUi() { |
| + OfflineContentAggregatorNotificationBridgeUi bridge = |
|
nyquist
2017/04/13 05:08:24
Should this and the verify-line below be part of a
|
| + new OfflineContentAggregatorNotificationBridgeUi(mProvider, mNotifier); |
| + verify(mProvider, times(1)).addObserver(bridge); |
| + |
| + ArrayList<OfflineItem> items = new ArrayList<OfflineItem>() { |
| + { |
| + add(buildOfflineItem(new ContentId("1", "A"), OfflineItemState.IN_PROGRESS)); |
| + add(buildOfflineItem(new ContentId("2", "B"), OfflineItemState.PENDING)); |
| + add(buildOfflineItem(new ContentId("3", "C"), OfflineItemState.COMPLETE)); |
| + add(buildOfflineItem(new ContentId("4", "D"), OfflineItemState.CANCELLED)); |
| + add(buildOfflineItem(new ContentId("5", "E"), OfflineItemState.INTERRUPTED)); |
| + add(buildOfflineItem(new ContentId("6", "F"), OfflineItemState.FAILED)); |
| + add(buildOfflineItem(new ContentId("7", "G"), OfflineItemState.PAUSED)); |
| + } |
| + }; |
| + |
| + bridge.onItemsAvailable(); |
| + bridge.onItemsAdded(items); |
| + |
| + InOrder order = inOrder(mProvider); |
| + order.verify(mProvider, times(1)) |
| + .getVisualsForItem(items.get(0).id /* OfflineItemState.IN_PROGRESS */, bridge); |
| + order.verify(mProvider, never()) |
| + .getVisualsForItem(ArgumentMatchers.any(), ArgumentMatchers.any()); |
| + |
| + bridge.onVisualsAvailable(items.get(0).id, new OfflineItemVisuals()); |
| + |
| + // TODO(dtrainor): Flesh out these validations. |
|
nyquist
2017/04/13 05:08:24
Was this meant as a TODO-before-submit? Or just a
|
| + verify(mNotifier, times(1)) |
| + .notifyDownloadProgress(ArgumentMatchers.any(), ArgumentMatchers.anyLong(), |
| + ArgumentMatchers.anyBoolean()); |
| + |
| + bridge.destroy(); |
| + verify(mProvider, times(1)).removeObserver(bridge); |
| + } |
| + |
| + @Test |
| + public void testItemUpdatesGetSentToTheUi() { |
| + OfflineContentAggregatorNotificationBridgeUi bridge = |
| + new OfflineContentAggregatorNotificationBridgeUi(mProvider, mNotifier); |
| + verify(mProvider, times(1)).addObserver(bridge); |
| + |
| + ArrayList<OfflineItem> items = new ArrayList<OfflineItem>() { |
| + { |
| + add(buildOfflineItem(new ContentId("1", "A"), OfflineItemState.IN_PROGRESS)); |
| + add(buildOfflineItem(new ContentId("2", "B"), OfflineItemState.PENDING)); |
| + add(buildOfflineItem(new ContentId("3", "C"), OfflineItemState.COMPLETE)); |
| + add(buildOfflineItem(new ContentId("4", "D"), OfflineItemState.CANCELLED)); |
| + add(buildOfflineItem(new ContentId("5", "E"), OfflineItemState.INTERRUPTED)); |
| + add(buildOfflineItem(new ContentId("6", "F"), OfflineItemState.FAILED)); |
| + add(buildOfflineItem(new ContentId("7", "G"), OfflineItemState.PAUSED)); |
| + } |
| + }; |
| + |
| + bridge.onItemsAvailable(); |
| + for (int i = 0; i < items.size(); i++) bridge.onItemUpdated(items.get(i)); |
| + |
| + verify(mProvider, times(1)).getVisualsForItem(items.get(0).id, bridge); |
| + verify(mProvider, times(1)).getVisualsForItem(items.get(1).id, bridge); |
| + verify(mProvider, times(1)).getVisualsForItem(items.get(2).id, bridge); |
| + verify(mProvider, never()).getVisualsForItem(items.get(3).id, bridge); |
| + verify(mProvider, times(1)).getVisualsForItem(items.get(4).id, bridge); |
| + verify(mProvider, times(1)).getVisualsForItem(items.get(5).id, bridge); |
| + verify(mProvider, times(1)).getVisualsForItem(items.get(6).id, bridge); |
| + |
| + for (int i = 0; i < items.size(); i++) { |
| + bridge.onVisualsAvailable(items.get(i).id, new OfflineItemVisuals()); |
| + } |
| + |
| + // TODO(dtrainor): Flesh out these validations. |
| + verify(mNotifier, times(1)) |
| + .notifyDownloadProgress(ArgumentMatchers.any(), ArgumentMatchers.anyLong(), |
| + ArgumentMatchers.anyBoolean()); |
| + verify(mNotifier, times(1)) |
| + .notifyDownloadSuccessful(ArgumentMatchers.any(), ArgumentMatchers.anyLong(), |
| + ArgumentMatchers.anyBoolean(), ArgumentMatchers.anyBoolean()); |
| + verify(mNotifier, times(1)) |
| + .notifyDownloadCanceled(items.get(3).id /* OfflineItemState.CANCELLED */); |
| + verify(mNotifier, times(1)) |
| + .notifyDownloadInterrupted(ArgumentMatchers.any(), ArgumentMatchers.anyBoolean()); |
| + verify(mNotifier, times(1)).notifyDownloadFailed(ArgumentMatchers.any()); |
| + verify(mNotifier, times(1)).notifyDownloadPaused(ArgumentMatchers.any()); |
| + |
| + bridge.destroy(); |
| + verify(mProvider, times(1)).removeObserver(bridge); |
| + } |
| + |
| + @Test |
| + public void testNullVisuals() { |
| + OfflineContentAggregatorNotificationBridgeUi bridge = |
| + new OfflineContentAggregatorNotificationBridgeUi(mProvider, mNotifier); |
| + verify(mProvider, times(1)).addObserver(bridge); |
| + |
| + OfflineItem item1 = buildOfflineItem(new ContentId("1", "A"), OfflineItemState.IN_PROGRESS); |
| + OfflineItem item2 = buildOfflineItem(new ContentId("2", "B"), OfflineItemState.IN_PROGRESS); |
| + |
| + OfflineItemVisuals visuals1 = new OfflineItemVisuals(); |
| + visuals1.icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); |
| + |
| + bridge.onItemsAvailable(); |
| + bridge.onItemUpdated(item1); |
| + bridge.onItemUpdated(item2); |
| + |
| + verify(mProvider, times(1)).getVisualsForItem(item1.id, bridge); |
| + verify(mProvider, times(1)).getVisualsForItem(item2.id, bridge); |
| + |
| + ArgumentCaptor<DownloadInfo> captor = ArgumentCaptor.forClass(DownloadInfo.class); |
| + |
| + bridge.onVisualsAvailable(item1.id, visuals1); |
| + bridge.onVisualsAvailable(item2.id, null); |
| + verify(mNotifier, times(2)) |
| + .notifyDownloadProgress(captor.capture(), ArgumentMatchers.anyLong(), |
| + ArgumentMatchers.anyBoolean()); |
| + |
| + List<DownloadInfo> capturedInfo = captor.getAllValues(); |
| + Assert.assertEquals(item1.id, capturedInfo.get(0).getContentId()); |
| + Assert.assertEquals(visuals1.icon, capturedInfo.get(0).getIcon()); |
| + Assert.assertEquals(item2.id, capturedInfo.get(1).getContentId()); |
| + Assert.assertEquals(null, capturedInfo.get(1).getIcon()); |
| + |
| + bridge.destroy(); |
| + verify(mProvider, times(1)).removeObserver(bridge); |
| + } |
| + |
| + @Test |
| + public void testRemovedItemsGetRemovedFromTheUi() { |
| + OfflineContentAggregatorNotificationBridgeUi bridge = |
| + new OfflineContentAggregatorNotificationBridgeUi(mProvider, mNotifier); |
| + verify(mProvider, times(1)).addObserver(bridge); |
| + |
| + ContentId id = new ContentId("1", "A"); |
| + |
| + bridge.onItemsAvailable(); |
| + bridge.onItemRemoved(id); |
| + verify(mNotifier, times(1)).notifyDownloadCanceled(id); |
| + |
| + bridge.destroy(); |
| + verify(mProvider, times(1)).removeObserver(bridge); |
| + } |
| + |
| + @Test |
| + public void testRemovedItemsIgnoreVisualsCallback() { |
| + OfflineContentAggregatorNotificationBridgeUi bridge = |
| + new OfflineContentAggregatorNotificationBridgeUi(mProvider, mNotifier); |
| + verify(mProvider, times(1)).addObserver(bridge); |
| + |
| + OfflineItem item = buildOfflineItem(new ContentId("1", "A"), OfflineItemState.IN_PROGRESS); |
| + |
| + bridge.onItemsAvailable(); |
| + bridge.onItemUpdated(item); |
| + verify(mProvider, times(1)).getVisualsForItem(item.id, bridge); |
| + |
| + bridge.onItemRemoved(item.id); |
| + bridge.onVisualsAvailable(item.id, new OfflineItemVisuals()); |
| + InOrder order = inOrder(mNotifier); |
| + order.verify(mNotifier, times(1)).notifyDownloadCanceled(item.id); |
| + order.verifyNoMoreInteractions(); |
| + |
| + bridge.destroy(); |
| + verify(mProvider, times(1)).removeObserver(bridge); |
| + } |
| + |
| + @Test |
| + public void testOnlyRequestsVisualsOnceForMultipleUpdates() { |
| + OfflineContentAggregatorNotificationBridgeUi bridge = |
| + new OfflineContentAggregatorNotificationBridgeUi(mProvider, mNotifier); |
| + verify(mProvider, times(1)).addObserver(bridge); |
| + |
| + OfflineItem item = buildOfflineItem(new ContentId("1", "A"), OfflineItemState.IN_PROGRESS); |
| + |
| + bridge.onItemsAvailable(); |
| + bridge.onItemUpdated(item); |
| + bridge.onItemUpdated(item); |
| + verify(mProvider, times(1)).getVisualsForItem(item.id, bridge); |
| + |
| + bridge.destroy(); |
| + verify(mProvider, times(1)).removeObserver(bridge); |
| + } |
| + |
| + @Test |
| + public void testVisualsAreCachedForInterestingItems() { |
| + OfflineContentAggregatorNotificationBridgeUi bridge = |
| + new OfflineContentAggregatorNotificationBridgeUi(mProvider, mNotifier); |
| + verify(mProvider, times(1)).addObserver(bridge); |
| + |
| + ArrayList<OfflineItem> interestingItems = new ArrayList<OfflineItem>() { |
| + { |
| + add(buildOfflineItem(new ContentId("1", "A"), OfflineItemState.IN_PROGRESS)); |
| + add(buildOfflineItem(new ContentId("2", "B"), OfflineItemState.PENDING)); |
| + add(buildOfflineItem(new ContentId("5", "E"), OfflineItemState.INTERRUPTED)); |
| + add(buildOfflineItem(new ContentId("7", "G"), OfflineItemState.PAUSED)); |
| + } |
| + }; |
| + |
| + ArrayList<OfflineItem> uninterestingItems = new ArrayList<OfflineItem>() { |
| + { |
| + add(buildOfflineItem(new ContentId("3", "C"), OfflineItemState.COMPLETE)); |
| + add(buildOfflineItem(new ContentId("6", "F"), OfflineItemState.FAILED)); |
| + } |
| + }; |
| + |
| + bridge.onItemsAvailable(); |
| + |
| + for (int i = 0; i < interestingItems.size(); i++) { |
| + OfflineItem item = interestingItems.get(i); |
| + bridge.onItemUpdated(item); |
| + bridge.onVisualsAvailable(item.id, null); |
| + bridge.onItemUpdated(item); |
| + verify(mProvider, times(1)).getVisualsForItem(item.id, bridge); |
| + verify(mNotifier, times(2)) |
| + .notifyDownloadProgress(ArgumentMatchers.any(), ArgumentMatchers.anyLong(), |
| + ArgumentMatchers.anyBoolean()); |
| + } |
| + |
| + for (int i = 0; i < uninterestingItems.size(); i++) { |
| + OfflineItem item = uninterestingItems.get(i); |
| + bridge.onItemUpdated(item); |
| + bridge.onVisualsAvailable(item.id, null); |
| + bridge.onItemUpdated(item); |
| + verify(mProvider, times(2)).getVisualsForItem(item.id, bridge); |
| + } |
| + |
| + bridge.destroy(); |
| + verify(mProvider, times(1)).removeObserver(bridge); |
| + } |
| + |
| + @Test |
| + public void testVisualsGetClearedForUninterestingItems() { |
| + OfflineContentAggregatorNotificationBridgeUi bridge = |
| + new OfflineContentAggregatorNotificationBridgeUi(mProvider, mNotifier); |
| + verify(mProvider, times(1)).addObserver(bridge); |
| + |
| + ContentId id = new ContentId("1", "A"); |
| + OfflineItem item1 = buildOfflineItem(id, OfflineItemState.IN_PROGRESS); |
| + OfflineItem item2 = buildOfflineItem(id, OfflineItemState.FAILED); |
| + OfflineItem item3 = buildOfflineItem(id, OfflineItemState.IN_PROGRESS); |
| + |
| + bridge.onItemsAvailable(); |
| + bridge.onItemUpdated(item1); |
| + bridge.onVisualsAvailable(item1.id, new OfflineItemVisuals()); |
| + bridge.onItemUpdated(item2); |
| + bridge.onItemUpdated(item3); |
| + bridge.onVisualsAvailable(item1.id, new OfflineItemVisuals()); |
| + verify(mProvider, times(2)).getVisualsForItem(id, bridge); |
| + |
| + bridge.destroy(); |
| + verify(mProvider, times(1)).removeObserver(bridge); |
| + } |
| +} |