Bug 1363520 - Run CleanupAction from DownloadContentService. r=Grisha
☠☠ backed out by b4f0bdb54c69 ☠ ☠
authorSebastian Kaspari <s.kaspari@gmail.com>
Wed, 10 May 2017 09:59:31 -0700
changeset 422356 4ecb1be113cb437ebf56e872faf0913f81352b0b
parent 422355 514cf1f55c6fa80deb7490d80a59313577d625cc
child 422357 b4f0bdb54c69d98dafc0ad2f7ad2f73de86a91e5
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGrisha
bugs1363520
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1363520 - Run CleanupAction from DownloadContentService. r=Grisha MozReview-Commit-ID: FvnIYStD25u
mobile/android/base/java/org/mozilla/gecko/dlc/CleanupAction.java
mobile/android/base/java/org/mozilla/gecko/dlc/DownloadContentService.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/dlc/TestCleanupAction.java
--- 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();
     }
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);
+    }
+}