Bug 1363520 - Run CleanupAction from DownloadContentService. r?grisha
MozReview-Commit-ID: FvnIYStD25u
--- a/mobile/android/base/java/org/mozilla/gecko/dlc/CleanupAction.java
+++ b/mobile/android/base/java/org/mozilla/gecko/dlc/CleanupAction.java
@@ -1,16 +1,17 @@
/* -*- 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 android.support.annotation.VisibleForTesting;
import org.mozilla.gecko.dlc.catalog.DownloadContent;
import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog;
import java.io.File;
/**
* CleanupAction: Remove content that is no longer needed.
@@ -19,31 +20,35 @@ public class CleanupAction extends BaseA
@Override
public void perform(Context context, DownloadContentCatalog catalog) {
for (DownloadContent content : catalog.getContentToDelete()) {
if (!content.isAssetArchive()) {
continue; // We do not know how to clean up this content. But this means we didn't
// download it anyways.
}
- try {
- File file = getDestinationFile(context, content);
+ cleanupContent(context, catalog, content);
+ }
+ }
- if (!file.exists()) {
- // File does not exist. As good as deleting.
- catalog.remove(content);
- return;
- }
+ @VisibleForTesting void cleanupContent(Context context, DownloadContentCatalog catalog, DownloadContent content) {
+ try {
+ final File file = getDestinationFile(context, content);
- if (file.delete()) {
- // File has been deleted. Now remove it from the catalog.
- catalog.remove(content);
- }
- } catch (UnrecoverableDownloadContentException e) {
- // We can't recover. Pretend the content is removed. It probably never existed in
- // the first place.
+ if (!file.exists()) {
+ // File does not exist. As good as deleting.
catalog.remove(content);
- } catch (RecoverableDownloadContentException e) {
- // Try again next time.
+ return;
+ }
+
+ if (file.delete()) {
+ // File has been deleted. Now remove it from the catalog.
+ catalog.remove(content);
}
+ } catch (UnrecoverableDownloadContentException e) {
+ // We can't recover. Pretend the content is removed. It probably never existed in
+ // the first place.
+ catalog.remove(content);
+ } catch (RecoverableDownloadContentException e) {
+ // Try again next time.
}
}
}
--- a/mobile/android/base/java/org/mozilla/gecko/dlc/DownloadContentService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/dlc/DownloadContentService.java
@@ -128,16 +128,20 @@ public class DownloadContentService exte
case ACTION_VERIFY_CONTENT:
action = new VerifyAction();
break;
case ACTION_SYNCHRONIZE_CATALOG:
action = new SyncAction();
break;
+ case ACTION_CLEANUP_FILES:
+ action = new CleanupAction();
+ break;
+
default:
Log.e(LOGTAG, "Unknown action: " + intent.getAction());
return;
}
action.perform(this, catalog);
catalog.persistChanges();
}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -600,16 +600,17 @@ gbjar.sources += ['java/org/mozilla/geck
'distribution/PartnerBookmarksProviderProxy.java',
'distribution/PartnerBrowserCustomizationsClient.java',
'distribution/ReferrerDescriptor.java',
'distribution/ReferrerReceiver.java',
'dlc/BaseAction.java',
'dlc/catalog/DownloadContent.java',
'dlc/catalog/DownloadContentBuilder.java',
'dlc/catalog/DownloadContentCatalog.java',
+ 'dlc/CleanupAction.java',
'dlc/DownloadAction.java',
'dlc/DownloadContentService.java',
'dlc/DownloadContentTelemetry.java',
'dlc/StudyAction.java',
'dlc/SyncAction.java',
'dlc/VerifyAction.java',
'DoorHangerPopup.java',
'DownloadsIntegration.java',
new file mode 100644
--- /dev/null
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestCleanupAction.java
@@ -0,0 +1,134 @@
+/* -*- 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.dlc.catalog.DownloadContent;
+import org.mozilla.gecko.dlc.catalog.DownloadContentBuilder;
+import org.mozilla.gecko.dlc.catalog.DownloadContentCatalog;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.io.File;
+
+import dalvik.annotation.TestTarget;
+import edu.emory.mathcs.backport.java.util.Collections;
+
+import static org.mockito.Matchers.any;
+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;
+
+@RunWith(RobolectricTestRunner.class)
+public class TestCleanupAction {
+ @Test
+ public void testEmptyCatalog() {
+ final DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
+ doReturn(Collections.emptyList()).when(catalog).getContentToDelete();
+
+ final CleanupAction action = spy(new CleanupAction());
+ action.perform(RuntimeEnvironment.application, catalog);
+
+ verify(catalog).getContentToDelete();
+ verify(action, never()).cleanupContent(any(Context.class), any(DownloadContentCatalog.class), any(DownloadContent.class));
+ }
+
+ @Test
+ public void testWithUnknownType() {
+ final DownloadContent content = new DownloadContentBuilder()
+ .setType("RandomType")
+ .build();
+
+ final DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
+ doReturn(Collections.singletonList(content)).when(catalog).getContentToDelete();
+
+ final CleanupAction action = spy(new CleanupAction());
+ action.perform(RuntimeEnvironment.application, catalog);
+
+ verify(catalog).getContentToDelete();
+ verify(action, never()).cleanupContent(any(Context.class), any(DownloadContentCatalog.class), any(DownloadContent.class));
+ }
+
+ @SuppressWarnings("ResultOfMethodCallIgnored")
+ @Test
+ public void testWithContentThatDoesNotExistAnymore() throws Exception {
+ final DownloadContent content = new DownloadContentBuilder()
+ .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
+ .build();
+
+ final DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
+ doReturn(Collections.singletonList(content)).when(catalog).getContentToDelete();
+
+ final File file = mock(File.class);
+ doReturn(false).when(file).exists();
+
+ final CleanupAction action = spy(new CleanupAction());
+ doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
+
+ action.perform(RuntimeEnvironment.application, catalog);
+
+ verify(catalog).getContentToDelete();
+ verify(action).cleanupContent(RuntimeEnvironment.application, catalog, content);
+ verify(file).exists();
+ verify(file, never()).delete();
+ verify(catalog).remove(content);
+ }
+
+ @Test
+ public void testWithDeletableContent() throws Exception {
+ final DownloadContent content = new DownloadContentBuilder()
+ .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
+ .build();
+
+ final DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
+ doReturn(Collections.singletonList(content)).when(catalog).getContentToDelete();
+
+ final File file = mock(File.class);
+ doReturn(true).when(file).exists();
+ doReturn(true).when(file).delete();
+
+ final CleanupAction action = spy(new CleanupAction());
+ doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
+
+ action.perform(RuntimeEnvironment.application, catalog);
+
+ verify(catalog).getContentToDelete();
+ verify(action).cleanupContent(RuntimeEnvironment.application, catalog, content);
+ verify(file).exists();
+ verify(file).delete();
+ verify(catalog).remove(content);
+ }
+
+ @Test
+ public void testWithFileThatCannotBeDeleted() throws Exception {
+ final DownloadContent content = new DownloadContentBuilder()
+ .setType(DownloadContent.TYPE_ASSET_ARCHIVE)
+ .build();
+
+ final DownloadContentCatalog catalog = mock(DownloadContentCatalog.class);
+ doReturn(Collections.singletonList(content)).when(catalog).getContentToDelete();
+
+ final File file = mock(File.class);
+ doReturn(true).when(file).exists();
+ doReturn(false).when(file).delete();
+
+ final CleanupAction action = spy(new CleanupAction());
+ doReturn(file).when(action).getDestinationFile(RuntimeEnvironment.application, content);
+
+ action.perform(RuntimeEnvironment.application, catalog);
+
+ verify(catalog).getContentToDelete();
+ verify(action).cleanupContent(RuntimeEnvironment.application, catalog, content);
+ verify(file).exists();
+ verify(file).delete();
+ verify(catalog, never()).remove(content);
+ }
+}