Bug 1232984 - Add basic set of tests for downloadable content. r=rnewman

--HG--
extra : commitid : 98BvL0dXkuv
extra : rebase_source : 3ddf99f5979e3a05ff5b1049d5be6ae4569c22ae
This commit is contained in:
Sebastian Kaspari 2015-12-16 13:16:23 +01:00
Родитель 8e726581e9
Коммит 8699452fa5
9 изменённых файлов: 713 добавлений и 9 удалений

Просмотреть файл

@ -123,6 +123,7 @@ dependencies {
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.0'
testCompile 'org.simpleframework:simple-http:4.1.13'
testCompile 'org.mockito:mockito-core:1.10.19'
}
apply plugin: 'idea'

Просмотреть файл

@ -73,6 +73,7 @@ public class DownloadAction extends BaseAction {
File destinationFile = getDestinationFile(context, content);
if (destinationFile.exists() && verify(destinationFile, content.getChecksum())) {
Log.d(LOGTAG, "Content already exists and is up-to-date.");
catalog.markAsDownloaded(content);
continue;
}

Просмотреть файл

@ -93,6 +93,10 @@ public class DownloadContent {
return location;
}
public long getLastModified() {
return lastModified;
}
public String getFilename() {
return filename;
}

Просмотреть файл

@ -5,8 +5,6 @@
package org.mozilla.gecko.dlc.catalog;
import org.mozilla.gecko.dlc.catalog.DownloadContentBootstrap;
import android.content.Context;
import android.support.v4.util.AtomicFile;
import android.util.Log;
@ -39,12 +37,17 @@ public class DownloadContentCatalog {
private boolean hasCatalogChanged; // Guarded by 'this'
public DownloadContentCatalog(Context context) {
content = Collections.emptyList();
file = new AtomicFile(new File(context.getApplicationInfo().dataDir, FILE_NAME));
this(new AtomicFile(new File(context.getApplicationInfo().dataDir, FILE_NAME)));
startLoadFromDisk();
}
// For injecting mocked AtomicFile objects during test
protected DownloadContentCatalog(AtomicFile file) {
this.content = Collections.emptyList();
this.file = file;
}
public synchronized List<DownloadContent> getContentWithoutState() {
awaitLoadingCatalogLocked();
@ -145,14 +148,18 @@ public class DownloadContentCatalog {
}
}
private synchronized void loadFromDisk() {
protected synchronized boolean hasCatalogChanged() {
return hasCatalogChanged;
}
protected synchronized void loadFromDisk() {
Log.d(LOGTAG, "Loading from disk");
if (hasLoadedCatalog) {
return;
}
List<DownloadContent> content = new ArrayList<DownloadContent>();
List<DownloadContent> content = new ArrayList<>();
try {
JSONArray array;
@ -180,15 +187,19 @@ public class DownloadContentCatalog {
Log.d(LOGTAG, "Can't read catalog due to IOException", e);
}
this.content = content;
this.hasLoadedCatalog = true;
onCatalogLoaded(content);
notifyAll();
Log.d(LOGTAG, "Loaded " + content.size() + " elements");
}
private synchronized void writeToDisk() {
protected void onCatalogLoaded(List<DownloadContent> content) {
this.content = content;
this.hasLoadedCatalog = true;
}
protected synchronized void writeToDisk() {
if (!hasCatalogChanged) {
Log.v(LOGTAG, "Not persisting: Catalog has not changed");
return;

Просмотреть файл

@ -0,0 +1,169 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.dlc;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mozilla.gecko.background.testhelpers.TestRunner;
import org.mozilla.gecko.dlc.catalog.DownloadContent;
import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog;
import org.robolectric.RuntimeEnvironment;
import java.io.File;
import java.util.Collections;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.StatusLine;
import ch.boye.httpclientandroidlib.client.HttpClient;
import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/**
* DownloadAction: Download content that has been scheduled during "study" or "verify".
*/
@RunWith(TestRunner.class)
public class TestDownloadAction {
private static final String TEST_URL = "http://example.org";
/**
* Scenario: The current network is metered.
*
* Verify that:
* * No download is performed on a metered network
*/
@Test
public void testNothingIsDoneOnMeteredNetwork() throws Exception {
DownloadAction action = spy(new DownloadAction(null));
doReturn(true).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
action.perform(RuntimeEnvironment.application, null);
verify(action, never()).buildHttpClient();
verify(action, never()).download(any(HttpClient.class), anyString(), any(File.class));
}
/**
* Scenario: Content is scheduled for download but already exists locally (with correct checksum).
*
* Verify that:
* * No download is performed for existing file
* * Content is marked as downloaded in the catalog
*/
@Test
public void testExistingAndVerifiedFilesAreNotDownloadedAgain() throws Exception {
DownloadContent content = new DownloadContent.Builder().build();
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
doReturn(Collections.singletonList(content)).when(catalog).getScheduledDownloads();
DownloadAction action = spy(new DownloadAction(null));
doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
File file = mock(File.class);
doReturn(true).when(file).exists();
doReturn(file).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
doReturn(true).when(action).verify(eq(file), anyString());
action.perform(RuntimeEnvironment.application, catalog);
verify(action, never()).download(any(HttpClient.class), anyString(), any(File.class));
verify(catalog).markAsDownloaded(content);
}
/**
* Scenario: Server returns a server error (HTTP 500).
*
* Verify that:
* * Situation is treated as recoverable (RecoverableDownloadContentException)
*/
@Test(expected=BaseAction.RecoverableDownloadContentException.class)
public void testServerErrorsAreRecoverable() throws Exception {
StatusLine status = mock(StatusLine.class);
doReturn(500).when(status).getStatusCode();
HttpResponse response = mock(HttpResponse.class);
doReturn(status).when(response).getStatusLine();
HttpClient client = mock(HttpClient.class);
doReturn(response).when(client).execute(any(HttpUriRequest.class));
DownloadAction action = spy(new DownloadAction(null));
action.download(client, TEST_URL, null);
verify(client).execute(any(HttpUriRequest.class));
}
/**
* Scenario: Server returns a client error (HTTP 404).
*
* Verify that:
* * Situation is treated as unrecoverable (UnrecoverableDownloadContentException)
*/
@Test(expected=BaseAction.UnrecoverableDownloadContentException.class)
public void testClientErrorsAreUnrecoverable() throws Exception {
StatusLine status = mock(StatusLine.class);
doReturn(404).when(status).getStatusCode();
HttpResponse response = mock(HttpResponse.class);
doReturn(status).when(response).getStatusLine();
HttpClient client = mock(HttpClient.class);
doReturn(response).when(client).execute(any(HttpUriRequest.class));
DownloadAction action = spy(new DownloadAction(null));
action.download(client, TEST_URL, null);
verify(client).execute(any(HttpUriRequest.class));
}
/**
* Scenario: A successful download has been performed.
*
* Verify that:
* * The content will be extracted to the destination
* * The content is marked as downloaded in the catalog
*/
@Test
public void testSuccessfulDownloadsAreMarkedAsDownloaded() throws Exception {
DownloadContent content = new DownloadContent.Builder()
.setKind(DownloadContent.KIND_FONT)
.setType(DownloadContent.TYPE_ASSET_ARCHIVE)
.build();
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
doReturn(Collections.singletonList(content)).when(catalog).getScheduledDownloads();
DownloadAction action = spy(new DownloadAction(null));
doReturn(false).when(action).isActiveNetworkMetered(RuntimeEnvironment.application);
File file = mock(File.class);
doReturn(false).when(file).exists();
doReturn(file).when(action).createTemporaryFile(RuntimeEnvironment.application, content);
doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
doReturn(false).when(action).verify(eq(file), anyString());
doNothing().when(action).download(any(HttpClient.class), anyString(), eq(file));
doReturn(true).when(action).verify(eq(file), anyString());
doNothing().when(action).extract(eq(file), eq(file), anyString());
action.perform(RuntimeEnvironment.application, catalog);
verify(action).buildHttpClient();
verify(action).download(any(HttpClient.class), anyString(), eq(file));
verify(action).extract(eq(file), eq(file), anyString());
verify(catalog).markAsDownloaded(content);
}
}

Просмотреть файл

@ -0,0 +1,118 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.dlc;
import android.content.Context;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mozilla.gecko.background.testhelpers.TestRunner;
import org.mozilla.gecko.dlc.catalog.DownloadContent;
import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* StudyAction: Scan the catalog for "new" content available for download.
*/
@RunWith(TestRunner.class)
public class TestStudyAction {
/**
* Scenario: Catalog is empty.
*
* Verify that:
* * No download is scheduled
* * Download action is not started
*/
@Test
public void testPerformWithEmptyCatalog() {
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
when(catalog.getContentWithoutState()).thenReturn(new ArrayList<DownloadContent>());
StudyAction action = spy(new StudyAction());
action.perform(RuntimeEnvironment.application, catalog);
verify(catalog).getContentWithoutState();
verify(catalog, never()).markAsDownloaded(any(DownloadContent.class));
verify(action, never()).startDownloads(any(Context.class));
}
/**
* Scenario: Catalog contains two items that have not been downloaded yet.
*
* Verify that:
* * Both items are scheduled to be downloaded
*/
@Test
public void testPerformWithNewContent() {
DownloadContent content1 = new DownloadContent.Builder()
.setType(DownloadContent.TYPE_ASSET_ARCHIVE)
.setKind(DownloadContent.KIND_FONT)
.build();
DownloadContent content2 = new DownloadContent.Builder()
.setType(DownloadContent.TYPE_ASSET_ARCHIVE)
.setKind(DownloadContent.KIND_FONT)
.build();
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
when(catalog.getContentWithoutState()).thenReturn(Arrays.asList(content1, content2));
StudyAction action = spy(new StudyAction());
action.perform(RuntimeEnvironment.application, catalog);
verify(catalog).scheduleDownload(content1);
verify(catalog).scheduleDownload(content2);
}
/**
* Scenario: Catalog contains item that are scheduled for download.
*
* Verify that:
* * Download action is started
*/
@Test
public void testStartingDownloadsAfterScheduling() {
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
when(catalog.hasScheduledDownloads()).thenReturn(true);
StudyAction action = spy(new StudyAction());
action.perform(RuntimeEnvironment.application, catalog);
verify(action).startDownloads(any(Context.class));
}
/**
* Scenario: Catalog contains unknown content.
*
* Verify that:
* * Unknown content is not scheduled for download.
*/
@Test
public void testPerformWithUnknownContent() {
DownloadContent content = new DownloadContent.Builder()
.setType("Unknown-Type")
.setKind("Unknown-Kind")
.build();
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
when(catalog.getContentWithoutState()).thenReturn(Collections.singletonList(content));
StudyAction action = spy(new StudyAction());
action.perform(RuntimeEnvironment.application, catalog);
verify(catalog, never()).scheduleDownload(content);
}
}

Просмотреть файл

@ -0,0 +1,122 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.dlc;
import android.content.Context;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mozilla.gecko.background.testhelpers.TestRunner;
import org.mozilla.gecko.dlc.catalog.DownloadContent;
import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog;
import org.robolectric.RuntimeEnvironment;
import java.io.File;
import java.util.Collections;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* VerifyAction: Validate downloaded content. Does it still exist and does it have the correct checksum?
*/
@RunWith(TestRunner.class)
public class TestVerifyAction {
/**
* Scenario: Downloaded file does not exist anymore.
*
* Verify that:
* * Content is re-scheduled for download.
*/
@Test
public void testReschedulingIfFileDoesNotExist() throws Exception {
DownloadContent content = new DownloadContent.Builder().build();
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
when(catalog.getDownloadedContent()).thenReturn(Collections.singletonList(content));
File file = mock(File.class);
when(file.exists()).thenReturn(false);
VerifyAction action = spy(new VerifyAction());
doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
action.perform(RuntimeEnvironment.application, catalog);
verify(catalog).scheduleDownload(content);
}
/**
* Scenario: Content has been scheduled for download.
*
* Verify that:
* * Download action is started
*/
@Test
public void testStartingDownloadsAfterScheduling() {
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
when(catalog.hasScheduledDownloads()).thenReturn(true);
VerifyAction action = spy(new VerifyAction());
action.perform(RuntimeEnvironment.application, catalog);
verify(action).startDownloads(any(Context.class));
}
/**
* Scenario: Checksum of existing file does not match expectation.
*
* Verify that:
* * Content is re-scheduled for download.
*/
@Test
public void testReschedulingIfVerificationFailed() throws Exception {
DownloadContent content = new DownloadContent.Builder().build();
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
when(catalog.getDownloadedContent()).thenReturn(Collections.singletonList(content));
File file = mock(File.class);
when(file.exists()).thenReturn(true);
VerifyAction action = spy(new VerifyAction());
doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
doReturn(false).when(action).verify(eq(file), anyString());
action.perform(RuntimeEnvironment.application, catalog);
verify(catalog).scheduleDownload(content);
}
/**
* Scenario: Downloaded file exists and has the correct checksum.
*
* Verify that:
* * No download is scheduled
* * Download action is not started
*/
@Test
public void testSuccessfulVerification() throws Exception {
DownloadContent content = new DownloadContent.Builder().build();
DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
when(catalog.getDownloadedContent()).thenReturn(Collections.singletonList(content));
File file = mock(File.class);
when(file.exists()).thenReturn(true);
VerifyAction action = spy(new VerifyAction());
doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
doReturn(true).when(action).verify(eq(file), anyString());
verify(catalog, never()).scheduleDownload(content);
verify(action, never()).startDownloads(RuntimeEnvironment.application);
}
}

Просмотреть файл

@ -0,0 +1,69 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.dlc.catalog;
import org.json.JSONException;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mozilla.gecko.background.testhelpers.TestRunner;
@RunWith(TestRunner.class)
public class TestDownloadContent {
/**
* Verify that the values passed to the builder are all set on the DownloadContent object.
*/
@Test
public void testBuilder() {
DownloadContent content = createTestContent();
Assert.assertEquals("Some-ID", content.getId());
Assert.assertEquals("/somewhere/something", content.getLocation());
Assert.assertEquals("some.file", content.getFilename());
Assert.assertEquals("Some-checksum", content.getChecksum());
Assert.assertEquals("Some-download-checksum", content.getDownloadChecksum());
Assert.assertEquals(4223, content.getLastModified());
Assert.assertEquals("Some-type", content.getType());
Assert.assertEquals("Some-kind", content.getKind());
Assert.assertEquals(27, content.getSize());
Assert.assertEquals(DownloadContent.STATE_SCHEDULED, content.getState());
}
/**
* Verify that a DownloadContent object exported to JSON and re-imported from JSON does not change.
*/
public void testJSONSerializationAndDeserialization() throws JSONException {
DownloadContent content = DownloadContent.fromJSON(createTestContent().toJSON());
Assert.assertEquals("Some-ID", content.getId());
Assert.assertEquals("/somewhere/something", content.getLocation());
Assert.assertEquals("some.file", content.getFilename());
Assert.assertEquals("Some-checksum", content.getChecksum());
Assert.assertEquals("Some-download-checksum", content.getDownloadChecksum());
Assert.assertEquals(4223, content.getLastModified());
Assert.assertEquals("Some-type", content.getType());
Assert.assertEquals("Some-kind", content.getKind());
Assert.assertEquals(27, content.getSize());
Assert.assertEquals(DownloadContent.STATE_SCHEDULED, content.getState());
}
/**
* Create a DownloadContent object with arbitrary data.
*/
private DownloadContent createTestContent() {
return new DownloadContent.Builder()
.setId("Some-ID")
.setLocation("/somewhere/something")
.setFilename("some.file")
.setChecksum("Some-checksum")
.setDownloadChecksum("Some-download-checksum")
.setLastModified(4223)
.setType("Some-type")
.setKind("Some-kind")
.setSize(27)
.setState(DownloadContent.STATE_SCHEDULED)
.build();
}
}

Просмотреть файл

@ -0,0 +1,209 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.dlc.catalog;
import android.support.v4.util.AtomicFile;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mozilla.gecko.background.testhelpers.TestRunner;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Arrays;
import java.util.Collections;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@RunWith(TestRunner.class)
public class TestDownloadContentCatalog {
/**
* Scenario: Create a new, fresh catalog.
*
* Verify that:
* * Catalog has not changed
* * Unchanged catalog will not be saved to disk
*/
@Test
public void testUntouchedCatalogHasNotChangedAndWillNotBePersisted() throws Exception {
AtomicFile file = mock(AtomicFile.class);
doReturn("[]".getBytes("UTF-8")).when(file).readFully();
DownloadContentCatalog catalog = spy(new DownloadContentCatalog(file));
catalog.loadFromDisk();
Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
catalog.writeToDisk();
Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
verify(file, never()).startWrite();
}
/**
* Scenario: Create a new, fresh catalog.
*
* Verify that:
* * Catalog is bootstrapped with items.
*/
@Test
public void testCatalogIsBootstrapedIfFileDoesNotExist() throws Exception {
AtomicFile file = mock(AtomicFile.class);
doThrow(FileNotFoundException.class).when(file).readFully();
DownloadContentCatalog catalog = spy(new DownloadContentCatalog(file));
catalog.loadFromDisk();
Assert.assertTrue("Catalog is not empty", catalog.getContentWithoutState().size() > 0);
}
/**
* Scenario: Schedule downloading an item from the catalog.
*
* Verify that:
* * Catalog has changed
*/
@Test
public void testCatalogHasChangedWhenDownloadIsScheduled() throws Exception {
DownloadContentCatalog catalog = spy(new DownloadContentCatalog(mock(AtomicFile.class)));
DownloadContent content = new DownloadContent.Builder().build();
catalog.onCatalogLoaded(Collections.singletonList(content));
Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
catalog.scheduleDownload(content);
Assert.assertTrue("Catalog has changed", catalog.hasCatalogChanged());
}
/**
* Scenario: Mark an item in the catalog as downloaded.
*
* Verify that:
* * Catalog has changed
*/
@Test
public void testCatalogHasChangedWhenContentIsDownloaded() throws Exception {
DownloadContentCatalog catalog = spy(new DownloadContentCatalog(mock(AtomicFile.class)));
DownloadContent content = new DownloadContent.Builder().build();
catalog.onCatalogLoaded(Collections.singletonList(content));
Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
catalog.markAsDownloaded(content);
Assert.assertTrue("Catalog has changed", catalog.hasCatalogChanged());
}
/**
* Scenario: Mark an item in the catalog as permanently failed.
*
* Verify that:
* * Catalog has changed
*/
@Test
public void testCatalogHasChangedIfDownloadHasFailedPermanently() throws Exception {
DownloadContentCatalog catalog = spy(new DownloadContentCatalog(mock(AtomicFile.class)));
DownloadContent content = new DownloadContent.Builder().build();
catalog.onCatalogLoaded(Collections.singletonList(content));
Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
catalog.markAsPermanentlyFailed(content);
Assert.assertTrue("Catalog has changed", catalog.hasCatalogChanged());
}
/**
* Scenario: Mark an item in the catalog as ignored.
*
* Verify that:
* * Catalog has changed
*/
@Test
public void testCatalogHasChangedIfContentIsIgnored() throws Exception {
DownloadContentCatalog catalog = spy(new DownloadContentCatalog(mock(AtomicFile.class)));
DownloadContent content = new DownloadContent.Builder().build();
catalog.onCatalogLoaded(Collections.singletonList(content));
Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
catalog.markAsIgnored(content);
Assert.assertTrue("Catalog has changed", catalog.hasCatalogChanged());
}
/**
* Scenario: A changed catalog is written to disk.
*
* Verify that:
* * Before write: Catalog has changed
* * After write: Catalog has not changed.
*/
@Test
public void testCatalogHasNotChangedAfterWritingToDisk() throws Exception {
AtomicFile file = mock(AtomicFile.class);
doReturn(mock(FileOutputStream.class)).when(file).startWrite();
DownloadContentCatalog catalog = spy(new DownloadContentCatalog(file));
DownloadContent content = new DownloadContent.Builder().build();
catalog.onCatalogLoaded(Collections.singletonList(content));
catalog.scheduleDownload(content);
Assert.assertTrue("Catalog has changed", catalog.hasCatalogChanged());
catalog.writeToDisk();
Assert.assertFalse("Catalog has not changed", catalog.hasCatalogChanged());
}
/**
* Scenario: A catalog with multiple items in different states.
*
* Verify that:
* * getContentWithoutState(), getDownloadedContent() and getScheduledDownloads() returns
* the correct items depenending on their state.
*/
@Test
public void testContentClassification() {
DownloadContentCatalog catalog = spy(new DownloadContentCatalog(mock(AtomicFile.class)));
DownloadContent content1 = new DownloadContent.Builder().setState(DownloadContent.STATE_NONE).build();
DownloadContent content2 = new DownloadContent.Builder().setState(DownloadContent.STATE_NONE).build();
DownloadContent content3 = new DownloadContent.Builder().setState(DownloadContent.STATE_SCHEDULED).build();
DownloadContent content4 = new DownloadContent.Builder().setState(DownloadContent.STATE_SCHEDULED).build();
DownloadContent content5 = new DownloadContent.Builder().setState(DownloadContent.STATE_SCHEDULED).build();
DownloadContent content6 = new DownloadContent.Builder().setState(DownloadContent.STATE_DOWNLOADED).build();
DownloadContent content7 = new DownloadContent.Builder().setState(DownloadContent.STATE_FAILED).build();
DownloadContent content8 = new DownloadContent.Builder().setState(DownloadContent.STATE_IGNORED).build();
DownloadContent content9 = new DownloadContent.Builder().setState(DownloadContent.STATE_IGNORED).build();
catalog.onCatalogLoaded(Arrays.asList(content1, content2, content3, content4, content5, content6,
content7, content8, content9));
Assert.assertEquals(2, catalog.getContentWithoutState().size());
Assert.assertEquals(1, catalog.getDownloadedContent().size());
Assert.assertEquals(3, catalog.getScheduledDownloads().size());
Assert.assertTrue(catalog.getContentWithoutState().contains(content1));
Assert.assertTrue(catalog.getContentWithoutState().contains(content2));
Assert.assertTrue(catalog.getDownloadedContent().contains(content6));
Assert.assertTrue(catalog.getScheduledDownloads().contains(content3));
Assert.assertTrue(catalog.getScheduledDownloads().contains(content4));
Assert.assertTrue(catalog.getScheduledDownloads().contains(content5));
}
}