From 6ebe298fa0a0e1ee58c0cdb4d3b101013632b422 Mon Sep 17 00:00:00 2001 From: Philip Whitehouse Date: Tue, 7 Feb 2017 21:25:35 +0000 Subject: [PATCH 1/2] Clear folder using the MessagingController instead of on the UI thread --- .../java/com/fsck/k9/activity/FolderList.java | 24 +-------------- .../k9/controller/MessagingController.java | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/k9mail/src/main/java/com/fsck/k9/activity/FolderList.java b/k9mail/src/main/java/com/fsck/k9/activity/FolderList.java index 4235018bf..203b6eb54 100644 --- a/k9mail/src/main/java/com/fsck/k9/activity/FolderList.java +++ b/k9mail/src/main/java/com/fsck/k9/activity/FolderList.java @@ -476,31 +476,9 @@ public class FolderList extends K9ListActivity { } private void onClearFolder(Account account, String folderName) { - // There has to be a cheaper way to get at the localFolder object than this - LocalFolder localFolder = null; - try { - if (account == null || folderName == null || !account.isAvailable(FolderList.this)) { - Log.i(K9.LOG_TAG, "not clear folder of unavailable account"); - return; - } - localFolder = account.getLocalStore().getFolder(folderName); - localFolder.open(Folder.OPEN_MODE_RW); - localFolder.clearAllMessages(); - } catch (Exception e) { - Log.e(K9.LOG_TAG, "Exception while clearing folder", e); - } finally { - if (localFolder != null) { - localFolder.close(); - } - } - - onRefresh(!REFRESH_REMOTE); + MessagingController.getInstance(getApplication()).clearFolder(account, folderName, mAdapter.mListener); } - - - - private void sendMail(Account account) { MessagingController.getInstance(getApplication()).sendPendingMessages(account, mAdapter.mListener); } diff --git a/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java b/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java index 3f0af1a22..c1f9afbc4 100644 --- a/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -53,6 +53,7 @@ import com.fsck.k9.K9; import com.fsck.k9.K9.Intents; import com.fsck.k9.Preferences; import com.fsck.k9.R; +import com.fsck.k9.activity.ActivityListener; import com.fsck.k9.activity.MessageReference; import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; import com.fsck.k9.cache.EmailProviderCache; @@ -3513,6 +3514,35 @@ public class MessagingController { }); } + public void clearFolder(final Account account, final String folderName, final ActivityListener listener) { + putBackground("clearFolder", listener, new Runnable() { + @Override + public void run() { + LocalFolder localFolder = null; + try { + Store localStore = account.getLocalStore(); + localFolder = (LocalFolder) localStore.getFolder(account.getTrashFolderName()); + localFolder.open(Folder.OPEN_MODE_RW); + + localFolder = account.getLocalStore().getFolder(folderName); + localFolder.open(Folder.OPEN_MODE_RW); + localFolder.clearAllMessages(); + } catch (UnavailableStorageException e) { + Log.i(K9.LOG_TAG, "Failed to clear folder because storage is not available - trying again later."); + throw new UnavailableAccountException(e); + } catch (Exception e) { + Log.e(K9.LOG_TAG, "clearFolder failed", e); + addErrorMessage(account, null, e); + } finally { + closeFolder(localFolder); + } + + listFoldersSynchronous(account, false, listener); + } + }); + } + + /** * Find out whether the account type only supports a local Trash folder. * From 4161b914415aef08ab645387893812d13356bda3 Mon Sep 17 00:00:00 2001 From: Philip Whitehouse Date: Sun, 12 Feb 2017 22:41:03 +0000 Subject: [PATCH 2/2] Tidy up and test clearFolder method --- .../k9/controller/MessagingController.java | 41 ++++++------ .../controller/MessagingControllerTest.java | 67 ++++++++++++++++++- 2 files changed, 87 insertions(+), 21 deletions(-) diff --git a/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java b/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java index c1f9afbc4..51d1d8a23 100644 --- a/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/k9mail/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -3518,30 +3518,31 @@ public class MessagingController { putBackground("clearFolder", listener, new Runnable() { @Override public void run() { - LocalFolder localFolder = null; - try { - Store localStore = account.getLocalStore(); - localFolder = (LocalFolder) localStore.getFolder(account.getTrashFolderName()); - localFolder.open(Folder.OPEN_MODE_RW); - - localFolder = account.getLocalStore().getFolder(folderName); - localFolder.open(Folder.OPEN_MODE_RW); - localFolder.clearAllMessages(); - } catch (UnavailableStorageException e) { - Log.i(K9.LOG_TAG, "Failed to clear folder because storage is not available - trying again later."); - throw new UnavailableAccountException(e); - } catch (Exception e) { - Log.e(K9.LOG_TAG, "clearFolder failed", e); - addErrorMessage(account, null, e); - } finally { - closeFolder(localFolder); - } - - listFoldersSynchronous(account, false, listener); + clearFolderSynchronous(account, folderName, listener); } }); } + @VisibleForTesting + protected void clearFolderSynchronous(Account account, String folderName, MessagingListener listener) { + LocalFolder localFolder = null; + try { + localFolder = account.getLocalStore().getFolder(folderName); + localFolder.open(Folder.OPEN_MODE_RW); + localFolder.clearAllMessages(); + } catch (UnavailableStorageException e) { + Log.i(K9.LOG_TAG, "Failed to clear folder because storage is not available - trying again later."); + throw new UnavailableAccountException(e); + } catch (Exception e) { + Log.e(K9.LOG_TAG, "clearFolder failed", e); + addErrorMessage(account, null, e); + } finally { + closeFolder(localFolder); + } + + listFoldersSynchronous(account, false, listener); + } + /** * Find out whether the account type only supports a local Trash folder. diff --git a/k9mail/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java b/k9mail/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java index e0254d7a1..8429a6cea 100644 --- a/k9mail/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java +++ b/k9mail/src/test/java/com/fsck/k9/controller/MessagingControllerTest.java @@ -13,6 +13,7 @@ import android.content.Context; import com.fsck.k9.Account; import com.fsck.k9.AccountStats; +import com.fsck.k9.K9; import com.fsck.k9.K9RobolectricTestRunner; import com.fsck.k9.Preferences; import com.fsck.k9.helper.Contacts; @@ -26,6 +27,7 @@ import com.fsck.k9.mail.Store; import com.fsck.k9.mailstore.LocalFolder; import com.fsck.k9.mailstore.LocalMessage; import com.fsck.k9.mailstore.LocalStore; +import com.fsck.k9.mailstore.UnavailableStorageException; import com.fsck.k9.notification.NotificationController; import com.fsck.k9.search.LocalSearch; import org.junit.After; @@ -51,6 +53,7 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -80,6 +83,8 @@ public class MessagingControllerTest { @Mock private LocalFolder localFolder; @Mock + private LocalFolder errorFolder; + @Mock private Folder remoteFolder; @Mock private LocalStore localStore; @@ -130,6 +135,62 @@ public class MessagingControllerTest { controller.stop(); } + @Test + public void clearFolderSynchronous_shouldOpenFolderForWriting() throws MessagingException { + controller.clearFolderSynchronous(account, FOLDER_NAME, listener); + + verify(localFolder).open(Folder.OPEN_MODE_RW); + } + + @Test + public void clearFolderSynchronous_shouldClearAllMessagesInTheFolder() throws MessagingException { + controller.clearFolderSynchronous(account, FOLDER_NAME, listener); + + verify(localFolder).clearAllMessages(); + } + + @Test + public void clearFolderSynchronous_shouldCloseTheFolder() throws MessagingException { + controller.clearFolderSynchronous(account, FOLDER_NAME, listener); + + verify(localFolder, atLeastOnce()).close(); + } + + @Test(expected = UnavailableAccountException.class) + public void clearFolderSynchronous_whenStorageUnavailable_shouldThrowUnavailableAccountException() throws MessagingException { + doThrow(new UnavailableStorageException("Test")).when(localFolder).open(Folder.OPEN_MODE_RW); + + controller.clearFolderSynchronous(account, FOLDER_NAME, listener); + } + + @Test() + public void clearFolderSynchronous_whenExceptionThrown_shouldAddErrorMessage() throws MessagingException { + doThrow(new RuntimeException("Test")).when(localFolder).open(Folder.OPEN_MODE_RW); + + controller.clearFolderSynchronous(account, FOLDER_NAME, listener); + + verify(errorFolder).appendMessages(any(List.class)); + } + + @Test() + public void clearFolderSynchronous_whenExceptionThrown_shouldStillCloseFolder() throws MessagingException { + doThrow(new RuntimeException("Test")).when(localFolder).open(Folder.OPEN_MODE_RW); + + try { + controller.clearFolderSynchronous(account, FOLDER_NAME, listener); + } catch (Exception ignored){ + } + + verify(localFolder, atLeastOnce()).close(); + } + + @Test() + public void clearFolderSynchronous_shouldListFolders() throws MessagingException { + controller.clearFolderSynchronous(account, FOLDER_NAME, listener); + + verify(listener, atLeastOnce()).listFoldersStarted(account); + } + @Test public void listFoldersSynchronous_shouldNotifyTheListenerListingStarted() throws MessagingException { List folders = Collections.singletonList(localFolder); @@ -758,11 +819,15 @@ public class MessagingControllerTest { when(account.getLocalStore()).thenReturn(localStore); when(account.getStats(any(Context.class))).thenReturn(accountStats); when(account.getMaximumAutoDownloadMessageSize()).thenReturn(MAXIMUM_SMALL_MESSAGE_SIZE); + when(account.getErrorFolderName()).thenReturn(K9.ERROR_FOLDER_NAME); + when(account.getEmail()).thenReturn("user@host.com"); } - private void configureLocalStore() { + private void configureLocalStore() throws MessagingException { when(localStore.getFolder(FOLDER_NAME)).thenReturn(localFolder); when(localFolder.getName()).thenReturn(FOLDER_NAME); + when(localStore.getFolder(K9.ERROR_FOLDER_NAME)).thenReturn(errorFolder); + when(localStore.getPersonalNamespaces(false)).thenReturn(Collections.singletonList(localFolder)); } private void configureRemoteStoreWithFolder() throws MessagingException {