protected BackupTask getBackupTask() { return new BackupTask(this); }
@Override protected BackupState doInBackground(BackupConfig... params) { if (params == null || params.length == 0) { throw new IllegalArgumentException("No config passed"); } final BackupConfig config = params[0]; if (config.backupType == SKIP) { return skip(config.typesToBackup); } else { return acquireLocksAndBackup(config); } }
appLog(R.string.app_log_backup_messages, cursors.count(SMS), cursors.count(MMS), cursors.count(CALLLOG)); if (config.debug) { appLog(R.string.app_log_backup_messages_with_config, config); return backupCursors(cursors, config.imapStore, config.backupType, itemsToSync); } else { appLog(R.string.app_log_skip_backup_no_items); return transition(FINISHED_BACKUP, null); return handleAuthError(config, e); } catch (AuthenticationFailedException e) { return transition(ERROR, e); } catch (MessagingException e) { return transition(ERROR, e); } catch (SecurityException e) { return transition(ERROR, e); } finally { if (cursors != null) {
private BackupState handleAuthError(BackupConfig config, XOAuth2AuthenticationFailedException e) { if (e.getStatus() == 400) { appLogDebug("need to perform xoauth2 token refresh"); if (config.currentTry < 1) { try { tokenRefresher.refreshOAuth2Token(); // we got a new token, let's handleAuthError one more time - we need to pass in a new store object // since the auth params on it are immutable appLogDebug("token refreshed, retrying"); return fetchAndBackupItems(config.retryWithStore(service.getBackupImapStore())); } catch (MessagingException ignored) { Log.w(TAG, ignored); } catch (TokenRefreshException refreshException) { appLogDebug("error refreshing token: "+refreshException+", cause="+refreshException.getCause()); } } else { appLogDebug("no new token obtained, giving up"); } } else { appLogDebug("unexpected xoauth status code " + e.getStatus()); } return transition(ERROR, e); }
@Test public void shouldTriggerBackupWithManualIntent() throws Exception { Intent intent = new Intent(MANUAL.name()); service.handleIntent(intent); verify(backupTask).execute(any(BackupConfig.class)); }
@Test public void shouldCreateNoFoldersIfNoItemsToBackup() throws Exception { mockFetch(SMS, 0); task.doInBackground(config); verifyZeroInteractions(store); }
@Subscribe public void canceled(CancelEvent cancelEvent) { if (LOCAL_LOGV) { Log.v(TAG, "canceled("+cancelEvent+")"); } cancel(cancelEvent.mayInterruptIfRunning()); }
private BackupState acquireLocksAndBackup(BackupConfig config) { try { service.acquireLocks(); return fetchAndBackupItems(config); } finally { service.releaseLocks(); } }
private BackupState skip(Iterable<DataType> types) { appLog(R.string.app_log_skip_backup_skip_messages); for (DataType type : types) { try { preferences.getDataTypePreferences().setMaxSyncedDate(type, fetcher.getMostRecentTimestamp(type)); } catch (SecurityException e ) { return new BackupState(ERROR, 0, 0, MANUAL, type, e); } } Log.i(TAG, "All messages skipped."); return new BackupState(FINISHED_BACKUP, 0, 0, MANUAL, null, null); }
@Test public void shouldPassInCorrectBackupConfig() throws Exception { Intent intent = new Intent(MANUAL.name()); ArgumentCaptor<BackupConfig> config = ArgumentCaptor.forClass(BackupConfig.class); service.handleIntent(intent); verify(backupTask).execute(config.capture()); BackupConfig backupConfig = config.getValue(); assertThat(backupConfig.backupType).isEqualTo(MANUAL); assertThat(backupConfig.currentTry).isEqualTo(0); }
@Test public void shouldVerifyStoreSettings() throws Exception { mockFetch(SMS, 1); when(converter.convertMessages(any(Cursor.class), eq(SMS))).thenReturn(result(SMS, 1)); when(store.getFolder(SMS, dataTypePreferences)).thenReturn(folder); task.doInBackground(config); verify(store).checkSettings(); }
@Test public void shouldNotCheckForConnectivityBeforeBackingUpWithNewScheduler() throws Exception { when(preferences.isUseOldScheduler()).thenReturn(false); Intent intent = new Intent(REGULAR.name()); shadowConnectivityManager.setActiveNetworkInfo(null); shadowConnectivityManager.setBackgroundDataSetting(true); service.handleIntent(intent); verify(backupTask).execute(any(BackupConfig.class)); }
@Test public void shouldCreateFoldersLazilyOnlyForNeededTypes() throws Exception { mockFetch(SMS, 1); when(converter.convertMessages(any(Cursor.class), eq(SMS))).thenReturn(result(SMS, 1)); when(store.getFolder(notNull(DataType.class), same(dataTypePreferences))).thenReturn(folder); task.doInBackground(config); verify(store).getFolder(SMS, dataTypePreferences); verify(store, never()).getFolder(MMS, dataTypePreferences); verify(store, never()).getFolder(CALLLOG, dataTypePreferences); }
@Before public void before() { initMocks(this); config = getBackupConfig(EnumSet.of(SMS)); when(service.getApplicationContext()).thenReturn(RuntimeEnvironment.application); when(service.getState()).thenReturn(state); when(preferences.getDataTypePreferences()).thenReturn(dataTypePreferences); task = new BackupTask(service, fetcher, converter, syncer, authPreferences, preferences, accessor, tokenRefresher); context = RuntimeEnvironment.application; }
@Test public void shouldScheduleNextRegularBackupAfterFinished() throws Exception { shadowConnectivityManager.setBackgroundDataSetting(true); Intent intent = new Intent(REGULAR.name()); service.handleIntent(intent); verify(backupTask).execute(any(BackupConfig.class)); service.backupStateChanged(service.transition(SmsSyncState.FINISHED_BACKUP, null)); verify(backupJobs).scheduleRegular(); assertThat(shadowOf(service).isStoppedBySelf()).isTrue(); assertThat(shadowOf(service).isForegroundStopped()).isTrue(); }
@Test public void shouldSkipItems() throws Exception { when(fetcher.getMostRecentTimestamp(any(DataType.class))).thenReturn(-23L); BackupState finalState = task.doInBackground(new BackupConfig( store, 0, 100, new ContactGroup(-1), BackupType.SKIP, EnumSet.of(SMS), false ) ); verify(dataTypePreferences).setMaxSyncedDate(DataType.SMS, -23); verifyZeroInteractions(dataTypePreferences); assertThat(finalState).isNotNull(); assertThat(finalState.isFinished()).isTrue(); }
private void backup(BackupType backupType) { getNotifier().cancel(NOTIFICATION_ID_WARNING); try { // set initial state state = new BackupState(INITIAL, 0, 0, backupType, null, null); EnumSet<DataType> enabledTypes = getEnabledBackupTypes(); checkPermissions(enabledTypes); if (backupType != SKIP) { checkCredentials(); if (getPreferences().isUseOldScheduler()) { legacyCheckConnectivity(); } } appLog(R.string.app_log_start_backup, backupType); getBackupTask().execute(getBackupConfig(backupType, enabledTypes, getBackupImapStore())); } catch (MessagingException e) { Log.w(TAG, e); moveToState(state.transition(ERROR, e)); } catch (ConnectivityException e) { moveToState(state.transition(ERROR, e)); } catch (RequiresLoginException e) { appLog(R.string.app_log_missing_credentials); moveToState(state.transition(ERROR, e)); } catch (BackupDisabledException e) { moveToState(state.transition(FINISHED_BACKUP, e)); } catch (MissingPermissionException e) { moveToState(state.transition(ERROR, e)); } }
@Test public void shouldCloseImapFolderAfterBackup() throws Exception { mockFetch(SMS, 1); when(converter.convertMessages(any(Cursor.class), eq(SMS))).thenReturn(result(SMS, 1)); when(store.getFolder(notNull(DataType.class), same(dataTypePreferences))).thenReturn(folder); task.doInBackground(config); verify(store).closeFolders(); }
@Test public void shouldAcquireAndReleaseLocksDuringBackup() throws Exception { mockAllFetchEmpty(); task.doInBackground(config); verify(service).acquireLocks(); verify(service).releaseLocks(); verify(service).transition(SmsSyncState.FINISHED_BACKUP, null); }
@Test public void shouldBackupMultipleTypes() throws Exception { mockFetch(SMS, 1); mockFetch(MMS, 2); when(store.getFolder(notNull(DataType.class), same(dataTypePreferences))).thenReturn(folder); when(converter.convertMessages(any(Cursor.class), any(DataType.class))).thenReturn(result(SMS, 1)); BackupState finalState = task.doInBackground(getBackupConfig(EnumSet.of(SMS, MMS))); assertThat(finalState.currentSyncedItems).isEqualTo(3); verify(folder, times(3)).appendMessages(anyListOf(Message.class)); }