| /* |
| * Copyright 2009 Google Inc. |
| * |
| * 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.google.gwt.core.client.impl; |
| |
| import com.google.gwt.core.client.impl.AsyncFragmentLoader.LoadTerminatedHandler; |
| import com.google.gwt.core.client.impl.AsyncFragmentLoader.LoadingStrategy; |
| import com.google.gwt.core.client.impl.AsyncFragmentLoader.Logger; |
| |
| import junit.framework.TestCase; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Queue; |
| |
| /** |
| * Tests that the fragment loader requests the right fragments and logs the |
| * correct lightweight metrics under a variety of request patterns. |
| */ |
| public class AsyncFragmentLoaderTest extends TestCase { |
| private static class MockErrorHandler implements LoadTerminatedHandler { |
| private boolean wasCalled = false; |
| |
| public boolean getWasCalled() { |
| return wasCalled; |
| } |
| |
| @Override |
| public void loadTerminated(Throwable reason) { |
| wasCalled = true; |
| } |
| } |
| |
| private static class MockLoadStrategy implements LoadingStrategy { |
| public final Map<Integer, LoadTerminatedHandler> errorHandlers = new HashMap<Integer, LoadTerminatedHandler>(); |
| private List<Integer> loadRequests = new LinkedList<Integer>(); |
| |
| public void assertFragmentsRequested(int... expectedAry) { |
| List<Integer> actual = new ArrayList<Integer>(loadRequests); |
| loadRequests.clear(); |
| List<Integer> expected = toList(expectedAry); |
| |
| if (!sameContents(actual, expected)) { |
| fail("Expected= " + commaSeparated(expected) + "; actual=" |
| + commaSeparated(actual)); |
| } |
| } |
| |
| @Override |
| public void startLoadingFragment(int fragment, |
| LoadTerminatedHandler loadErrorHandler) { |
| errorHandlers.put(fragment, loadErrorHandler); |
| loadRequests.add(fragment); |
| } |
| |
| private String commaSeparated(List<Integer> ary) { |
| StringBuilder sb = new StringBuilder(); |
| boolean first = true; |
| for (Integer x : ary) { |
| if (first) { |
| first = false; |
| } else { |
| sb.append(","); |
| } |
| sb.append(x); |
| } |
| return sb.toString(); |
| } |
| |
| private boolean sameContents(List<Integer> actual, List<Integer> expected) { |
| if (actual.size() != expected.size()) { |
| return false; |
| } |
| for (int i = 0; i < actual.size(); i++) { |
| if (!actual.get(i).equals(expected.get(i))) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private List<Integer> toList(int[] ary) { |
| List<Integer> list = new ArrayList<Integer>(); |
| for (int i = 0; i < ary.length; i++) { |
| list.add(ary[i]); |
| } |
| return list; |
| } |
| } |
| |
| private static class MockProgressEvent { |
| public final String eventGroup; |
| public final int fragment; |
| public final String type; |
| |
| public MockProgressEvent(String eventGroup, String type, int fragment) { |
| this.eventGroup = eventGroup; |
| this.type = type; |
| this.fragment = fragment; |
| } |
| } |
| |
| private static class MockProgressLogger implements Logger { |
| private Queue<MockProgressEvent> events = new LinkedList<MockProgressEvent>(); |
| |
| public void assertEvent(String eventGroup, String type, int fragment) { |
| MockProgressEvent event = events.remove(); |
| assertEquals(eventGroup, event.eventGroup); |
| assertEquals(type, event.type); |
| assertEquals(fragment, event.fragment); |
| } |
| |
| public void assertNoEvents() { |
| assertTrue("Expected no more progress events, but there are " |
| + events.size(), events.size() == 0); |
| } |
| |
| @Override |
| public void logEventProgress(String eventGroup, String type, |
| int fragment, int size) { |
| events.add(new MockProgressEvent(eventGroup, type, fragment)); |
| } |
| } |
| |
| private static final String BEGIN = "begin"; |
| private static final String END = "end"; |
| private static final String LEFTOVERS_DOWNLOAD = "leftoversDownload"; |
| |
| private static final LoadTerminatedHandler NULL_ERROR_HANDLER = new LoadTerminatedHandler() { |
| @Override |
| public void loadTerminated(Throwable reason) { |
| } |
| }; |
| |
| private static Throwable makeLoadFailedException() { |
| return new RuntimeException("Load Failed"); |
| } |
| |
| public void testBasics() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 5; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, |
| new int[] {}, reqs, progress, null); |
| |
| loader.inject(1, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(numEntries); |
| progress.assertEvent(LEFTOVERS_DOWNLOAD, BEGIN, numEntries); |
| |
| loader.leftoversFragmentHasLoaded(); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent(LEFTOVERS_DOWNLOAD, END, numEntries); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| loader.fragmentHasLoaded(1); |
| progress.assertEvent("download1", END, 1); |
| |
| loader.inject(2, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| loader.fragmentHasLoaded(2); |
| progress.assertEvent("download2", END, 2); |
| |
| progress.assertNoEvents(); |
| } |
| |
| /** |
| * Check the behavior when there are download failures. |
| */ |
| public void testDownloadFailures() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 10; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, new int[] { |
| 1, 2, 3}, reqs, progress, null); |
| |
| // request fragment 1 |
| MockErrorHandler error1try1 = new MockErrorHandler(); |
| loader.inject(1, error1try1); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| // fragment 1 fails |
| loadFailed(reqs, 1); |
| assertTrue(error1try1.getWasCalled()); |
| |
| // try again on fragment 1 |
| MockErrorHandler error1try2 = new MockErrorHandler(); |
| loader.inject(1, error1try2); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| // this time fragment 1 succeeds |
| loader.fragmentHasLoaded(1); |
| reqs.assertFragmentsRequested(); |
| assertFalse(error1try2.getWasCalled()); |
| progress.assertEvent("download1", END, 1); |
| |
| // request a later initial fragment (3), and see what happens if an |
| // intermediate download fails |
| MockErrorHandler error3try1 = new MockErrorHandler(); |
| loader.inject(3, error3try1); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| loadFailed(reqs, 2); |
| assertTrue(error3try1.wasCalled); |
| |
| // request both 3 and 5, and see what happens if |
| // the leftovers download fails |
| MockErrorHandler error3try2 = new MockErrorHandler(); |
| MockErrorHandler error5try1 = new MockErrorHandler(); |
| loader.inject(3, error3try2); |
| loader.inject(5, error5try1); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| loader.fragmentHasLoaded(2); |
| reqs.assertFragmentsRequested(3); |
| progress.assertEvent("download2", END, 2); |
| progress.assertEvent("download3", BEGIN, 3); |
| |
| loader.fragmentHasLoaded(3); |
| reqs.assertFragmentsRequested(numEntries); |
| progress.assertEvent("download3", END, 3); |
| progress.assertEvent(LEFTOVERS_DOWNLOAD, BEGIN, numEntries); |
| |
| loadFailed(reqs, numEntries); // leftovers fails! |
| assertFalse(error3try2.getWasCalled()); // 3 should have succeeded |
| assertTrue(error5try1.getWasCalled()); // 5 failed |
| |
| // now try 5 again, and have everything succeed |
| MockErrorHandler error5try2 = new MockErrorHandler(); |
| loader.inject(5, error5try2); |
| reqs.assertFragmentsRequested(numEntries); |
| progress.assertEvent(LEFTOVERS_DOWNLOAD, BEGIN, numEntries); |
| |
| loader.leftoversFragmentHasLoaded(); |
| reqs.assertFragmentsRequested(5); |
| progress.assertEvent(LEFTOVERS_DOWNLOAD, END, numEntries); |
| progress.assertEvent("download5", BEGIN, 5); |
| |
| loader.fragmentHasLoaded(5); |
| reqs.assertFragmentsRequested(); |
| assertFalse(error5try2.getWasCalled()); |
| progress.assertEvent("download5", END, 5); |
| |
| // try 6 but have it fail |
| MockErrorHandler error6try1 = new MockErrorHandler(); |
| loader.inject(6, error6try1); |
| reqs.assertFragmentsRequested(6); |
| progress.assertEvent("download6", BEGIN, 6); |
| |
| loadFailed(reqs, 6); |
| assertTrue(error6try1.getWasCalled()); |
| |
| // try 7 and have it succeed |
| loader.inject(7, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(7); |
| progress.assertEvent("download7", BEGIN, 7); |
| |
| loader.fragmentHasLoaded(7); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download7", END, 7); |
| |
| // try 6 again and have it succeed this time |
| MockErrorHandler error6try2 = new MockErrorHandler(); |
| loader.inject(6, error6try2); |
| reqs.assertFragmentsRequested(6); |
| progress.assertEvent("download6", BEGIN, 6); |
| |
| loader.fragmentHasLoaded(6); |
| reqs.assertFragmentsRequested(); |
| assertFalse(error6try2.getWasCalled()); |
| progress.assertEvent("download6", END, 6); |
| |
| // a finish event should do nothing if the fragment has already succeeded |
| progress.assertNoEvents(); |
| loadFailed(reqs, 6); |
| assertFalse(error6try2.getWasCalled()); |
| progress.assertNoEvents(); |
| } |
| |
| public void testExclusivesLoadSequentially1() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 6; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, |
| new int[] {}, reqs, progress, null); |
| |
| // Load fragment 1 |
| loader.inject(1, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(numEntries); // leftovers |
| progress.assertEvent("leftoversDownload", BEGIN, numEntries); |
| loader.fragmentHasLoaded(numEntries); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("leftoversDownload", END, numEntries); |
| progress.assertEvent("download1", BEGIN, 1); |
| loader.fragmentHasLoaded(1); |
| progress.assertEvent("download1", END, 1); |
| progress.assertNoEvents(); |
| |
| // Request 2 and 3 immediately |
| loader.inject(2, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("download2", BEGIN, 2); |
| loader.inject(3, NULL_ERROR_HANDLER); |
| progress.assertNoEvents(); // waiting on 2 to finish |
| |
| // 2 loads, 3 should be requested |
| loader.fragmentHasLoaded(2); |
| reqs.assertFragmentsRequested(3); |
| progress.assertEvent("download2", END, 2); |
| progress.assertEvent("download3", BEGIN, 3); |
| progress.assertNoEvents(); |
| |
| // 3 loads |
| loader.fragmentHasLoaded(3); |
| progress.assertEvent("download3", END, 3); |
| progress.assertNoEvents(); |
| } |
| |
| public void testExclusivesLoadSequentially2() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 6; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, |
| new int[] {}, reqs, progress, null); |
| |
| // Request 1 |
| loader.inject(1, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(numEntries); |
| progress.assertEvent("leftoversDownload", BEGIN, numEntries); |
| |
| // Request 2, resulting in two fragments being queued behind the leftovers |
| // download |
| loader.inject(2, NULL_ERROR_HANDLER); |
| progress.assertNoEvents(); |
| |
| // Leftovers arrives, but only fragment 1 should initially be requested |
| loader.leftoversFragmentHasLoaded(); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("leftoversDownload", END, numEntries); |
| progress.assertEvent("download1", BEGIN, 1); |
| progress.assertNoEvents(); |
| |
| // fragment 1 arrives, 2 requested |
| loader.fragmentHasLoaded(1); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("download1", END, 1); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| // fragment 2 arrives, all done |
| loader.fragmentHasLoaded(2); |
| progress.assertEvent("download2", END, 2); |
| progress.assertNoEvents(); |
| } |
| |
| /** |
| * If only the first part of the initial load sequence is requested, then |
| * don't request more. |
| */ |
| public void testLoadingPartOfInitialSequence() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 6; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, new int[] { |
| 1, 2, 3}, reqs, progress, null); |
| |
| loader.inject(1, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| loader.fragmentHasLoaded(1); |
| reqs.assertFragmentsRequested(); // should stop |
| progress.assertEvent("download1", END, 1); |
| |
| loader.inject(2, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| loader.fragmentHasLoaded(2); |
| reqs.assertFragmentsRequested(); // again, should stop |
| progress.assertEvent("download2", END, 2); |
| |
| loader.inject(3, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(3); |
| progress.assertEvent("download3", BEGIN, 3); |
| |
| loader.fragmentHasLoaded(3); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download3", END, 3); |
| progress.assertNoEvents(); |
| |
| // check that exclusives now load |
| loader.inject(5, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(numEntries); |
| progress.assertEvent(LEFTOVERS_DOWNLOAD, BEGIN, numEntries); |
| |
| loader.fragmentHasLoaded(numEntries); |
| reqs.assertFragmentsRequested(5); |
| progress.assertEvent(LEFTOVERS_DOWNLOAD, END, numEntries); |
| progress.assertEvent("download5", BEGIN, 5); |
| |
| loader.fragmentHasLoaded(5); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download5", END, 5); |
| |
| progress.assertNoEvents(); |
| } |
| |
| /** |
| * This test catches a case in an earlier version of AsyncFragmentLoader where |
| * AsyncFragmentLoader.waitingForInitialFragments could exhaust its available |
| * space. |
| */ |
| public void testOverflowInWaitingForInitialFragments() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 6; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, new int[] { |
| 1, 2, 3}, reqs, progress, null); |
| |
| /* |
| * Repeatedly queue up extra downloads waiting on an initial and then fail. |
| */ |
| for (int i = 0; i < 10; i++) { |
| MockErrorHandler error = new MockErrorHandler(); |
| loader.inject(4, error); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| loadFailed(reqs, 1); |
| assertTrue(error.getWasCalled()); |
| progress.assertNoEvents(); |
| } |
| } |
| |
| public void testPrefetch() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 20; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, new int[] { |
| 1, 2, 3}, reqs, progress, null); |
| loader.startPrefetching(); |
| // request a prefetch of something in the initial load sequence |
| loader.setPrefetchQueue(2); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| loader.fragmentHasLoaded(1); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("download1", END, 1); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| loader.fragmentHasLoaded(2); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download2", END, 2); |
| progress.assertNoEvents(); |
| // request a prefetch of an exclusive |
| loader.setPrefetchQueue(4); |
| reqs.assertFragmentsRequested(3); |
| progress.assertEvent("download3", BEGIN, 3); |
| |
| loader.fragmentHasLoaded(3); |
| reqs.assertFragmentsRequested(numEntries); |
| progress.assertEvent("download3", END, 3); |
| progress.assertEvent("leftoversDownload", BEGIN, numEntries); |
| |
| loader.leftoversFragmentHasLoaded(); |
| reqs.assertFragmentsRequested(4); |
| progress.assertEvent("leftoversDownload", END, numEntries); |
| progress.assertEvent("download4", BEGIN, 4); |
| |
| loader.fragmentHasLoaded(4); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download4", END, 4); |
| progress.assertNoEvents(); |
| // request a prefetch, but check that an inject call takes priority |
| loader.setPrefetchQueue(5, 6); |
| reqs.assertFragmentsRequested(5); |
| progress.assertEvent("download5", BEGIN, 5); |
| |
| loader.inject(7, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(); |
| progress.assertNoEvents(); |
| |
| loader.fragmentHasLoaded(5); |
| reqs.assertFragmentsRequested(7); |
| progress.assertEvent("download5", END, 5); |
| progress.assertEvent("download7", BEGIN, 7); |
| |
| loader.fragmentHasLoaded(7); |
| reqs.assertFragmentsRequested(6); |
| progress.assertEvent("download7", END, 7); |
| progress.assertEvent("download6", BEGIN, 6); |
| |
| loader.fragmentHasLoaded(6); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download6", END, 6); |
| progress.assertNoEvents(); |
| // request prefetches, then request different prefetches |
| loader.setPrefetchQueue(8, 9); |
| reqs.assertFragmentsRequested(8); |
| progress.assertEvent("download8", BEGIN, 8); |
| loader.setPrefetchQueue(10); |
| reqs.assertFragmentsRequested(); |
| progress.assertNoEvents(); |
| |
| loader.fragmentHasLoaded(8); |
| reqs.assertFragmentsRequested(10); |
| progress.assertEvent("download8", END, 8); |
| progress.assertEvent("download10", BEGIN, 10); |
| |
| loader.fragmentHasLoaded(10); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download10", END, 10); |
| progress.assertNoEvents(); |
| // request prefetches that have already been loaded |
| loader.setPrefetchQueue(1, 3, 7, 10); |
| reqs.assertFragmentsRequested(); |
| progress.assertNoEvents(); |
| } |
| |
| /** |
| * Prefetch initial split points out of order. |
| */ |
| public void testPrefetchInitialsOutOfOrder() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 20; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, new int[] { |
| 1, 2, 3}, reqs, progress, null); |
| loader.startPrefetching(); |
| // request a prefetch of something in the initial load sequence |
| loader.setPrefetchQueue(3, 2, 1); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| loader.fragmentHasLoaded(1); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("download1", END, 1); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| loader.fragmentHasLoaded(2); |
| reqs.assertFragmentsRequested(3); |
| progress.assertEvent("download2", END, 2); |
| progress.assertEvent("download3", BEGIN, 3); |
| |
| loader.fragmentHasLoaded(3); |
| progress.assertEvent("download3", END, 3); |
| reqs.assertFragmentsRequested(); |
| progress.assertNoEvents(); |
| |
| // check that the loader is in a sane state by downloading an exclusive |
| loader.inject(5, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(numEntries); |
| progress.assertEvent("leftoversDownload", BEGIN, numEntries); |
| |
| loader.leftoversFragmentHasLoaded(); |
| reqs.assertFragmentsRequested(5); |
| progress.assertEvent("leftoversDownload", END, numEntries); |
| progress.assertEvent("download5", BEGIN, 5); |
| |
| loader.fragmentHasLoaded(5); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download5", END, 5); |
| progress.assertNoEvents(); |
| } |
| |
| /** |
| * Test that no prefetching happens if prefetching is turned off. |
| */ |
| public void testPrefetchingDisabled() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 20; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, |
| new int[] {}, reqs, progress, null); |
| loader.stopPrefetching(); |
| // Prefetch 1, but leave prefetching off |
| loader.setPrefetchQueue(1); |
| reqs.assertFragmentsRequested(); |
| progress.assertNoEvents(); |
| |
| // Inject 2, which should lead to leftovers and 2 loading |
| loader.inject(2, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(numEntries); |
| progress.assertEvent("leftoversDownload", BEGIN, numEntries); |
| |
| loader.leftoversFragmentHasLoaded(); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("leftoversDownload", END, numEntries); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| loader.fragmentHasLoaded(2); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download2", END, 2); |
| progress.assertNoEvents(); |
| |
| // Enable prefetching; now 1 should load |
| loader.startPrefetching(); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| loader.fragmentHasLoaded(1); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download1", END, 1); |
| progress.assertNoEvents(); |
| } |
| |
| /** |
| * Test prefetching an item and then injecting it while the prefetch is in |
| * progress. |
| */ |
| public void testPrefetchThenInjectOfSame() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 20; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, |
| new int[] {}, reqs, progress, null); |
| loader.startPrefetching(); |
| |
| // Load the leftovers and one fragment |
| loader.inject(1, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(numEntries); |
| progress.assertEvent("leftoversDownload", BEGIN, numEntries); |
| |
| loader.leftoversFragmentHasLoaded(); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("leftoversDownload", END, numEntries); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| loader.fragmentHasLoaded(1); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download1", END, 1); |
| progress.assertNoEvents(); |
| // Start prefetching a fragment |
| loader.setPrefetchQueue(2); |
| reqs.assertFragmentsRequested(2); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| // Inject the same fragment and another one |
| loader.inject(2, NULL_ERROR_HANDLER); |
| loader.inject(3, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(); |
| progress.assertNoEvents(); |
| |
| // Finish the fragment loads |
| loader.fragmentHasLoaded(2); |
| reqs.assertFragmentsRequested(3); |
| progress.assertEvent("download2", END, 2); |
| progress.assertEvent("download3", BEGIN, 3); |
| |
| loader.fragmentHasLoaded(3); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download3", END, 3); |
| progress.assertNoEvents(); |
| } |
| |
| /** |
| * A thorough exercise of loading with an initial load sequence specified. |
| */ |
| public void testWithInitialLoadSequence() { |
| MockLoadStrategy reqs = new MockLoadStrategy(); |
| MockProgressLogger progress = new MockProgressLogger(); |
| int numEntries = 6; |
| AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, new int[] { |
| 1, 2, 3}, reqs, progress, null); |
| |
| loader.inject(1, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(1); |
| progress.assertEvent("download1", BEGIN, 1); |
| |
| loader.inject(3, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(); // still waiting on fragment 1 |
| progress.assertNoEvents(); |
| |
| loader.inject(5, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(); // still waiting on fragment 1 |
| progress.assertNoEvents(); |
| |
| // say that 1 loads, which should trigger a chain of backlogged downloads |
| loader.fragmentHasLoaded(1); |
| reqs.assertFragmentsRequested(2); // next initial |
| progress.assertEvent("download1", END, 1); |
| progress.assertEvent("download2", BEGIN, 2); |
| |
| loader.fragmentHasLoaded(2); |
| reqs.assertFragmentsRequested(3); // next initial |
| progress.assertEvent("download2", END, 2); |
| progress.assertEvent("download3", BEGIN, 3); |
| |
| loader.fragmentHasLoaded(3); |
| reqs.assertFragmentsRequested(numEntries); // leftovers |
| progress.assertEvent("download3", END, 3); |
| progress.assertEvent("leftoversDownload", BEGIN, numEntries); |
| |
| loader.leftoversFragmentHasLoaded(); |
| reqs.assertFragmentsRequested(5); |
| progress.assertEvent("leftoversDownload", END, numEntries); |
| progress.assertEvent("download5", BEGIN, 5); |
| |
| loader.fragmentHasLoaded(5); |
| reqs.assertFragmentsRequested(); // quiescent |
| progress.assertEvent("download5", END, 5); |
| progress.assertNoEvents(); |
| |
| // check that new exclusive fragment requests work |
| loader.inject(4, NULL_ERROR_HANDLER); |
| reqs.assertFragmentsRequested(4); |
| progress.assertEvent("download4", BEGIN, 4); |
| |
| loader.fragmentHasLoaded(4); |
| reqs.assertFragmentsRequested(); |
| progress.assertEvent("download4", END, 4); |
| progress.assertNoEvents(); |
| } |
| |
| private void loadFailed(MockLoadStrategy reqs, int fragment) { |
| reqs.errorHandlers.get(fragment).loadTerminated(makeLoadFailedException()); |
| } |
| } |