package co.smartreceipts.android.sync.drive.rx; import android.os.Bundle; import com.google.android.gms.drive.DriveFile; import com.google.android.gms.drive.DriveFolder; import com.google.android.gms.drive.DriveId; import com.google.android.gms.drive.Metadata; import com.hadisatrio.optional.Optional; import com.shockwave.pdfium.PdfDocument; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import java.io.File; import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; import co.smartreceipts.android.sync.drive.error.DriveThrowableToSyncErrorTranslator; import co.smartreceipts.android.sync.errors.CriticalSyncError; import co.smartreceipts.android.sync.model.RemoteBackupMetadata; import co.smartreceipts.android.sync.model.SyncState; import co.smartreceipts.android.sync.model.impl.Identifier; import co.smartreceipts.android.sync.provider.SyncProvider; import io.reactivex.Observable; import io.reactivex.Single; import io.reactivex.observers.TestObserver; import io.reactivex.subjects.Subject; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) public class DriveStreamsManagerTest { // Class under test DriveStreamsManager driveStreamsManager; @Mock DriveDataStreams driveDataStreams; @Mock DriveStreamMappings driveStreamMappings; @Mock Subject<Optional<Throwable>> driveErrorStream; @Mock DriveThrowableToSyncErrorTranslator syncErrorTranslator; @Mock RemoteBackupMetadata remoteBackupMetadata; @Mock DriveId driveId; @Mock DriveFolder driveFolder; @Mock DriveFile driveFile; @Mock Identifier identifier; @Mock Metadata metadata; @Mock Throwable criticalSyncError; @Mock SyncState currentSyncState, newSyncState; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(syncErrorTranslator.get(any(Throwable.class))).thenReturn(criticalSyncError); driveStreamsManager = new DriveStreamsManager(driveDataStreams, driveStreamMappings, driveErrorStream, syncErrorTranslator); driveStreamsManager.onConnected(new Bundle()); } @Test public void getRemoteBackups() throws Exception { final List<RemoteBackupMetadata> remoteBackups = Collections.singletonList(remoteBackupMetadata); when(driveDataStreams.getSmartReceiptsFolders()).thenReturn(Single.just(remoteBackups)); final TestObserver<List<RemoteBackupMetadata>> testObserver = driveStreamsManager.getRemoteBackups().test(); testObserver.assertValue(remoteBackups); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void getRemoteBackupsErrorIsForwarded() throws Exception { final Exception exception = new Exception("test"); when(driveDataStreams.getSmartReceiptsFolders()).thenReturn(Single.error(exception)); final TestObserver<List<RemoteBackupMetadata>> testObserver = driveStreamsManager.getRemoteBackups().test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void getDriveId() throws Exception { when(driveDataStreams.getDriveId(identifier)).thenReturn(Single.just(driveId)); final TestObserver<DriveId> testObserver = driveStreamsManager.getDriveId(identifier).test(); testObserver.assertValue(driveId); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void getDriveIdErrorIsForwarded() throws Exception { final Exception exception = new Exception("test"); when(driveDataStreams.getDriveId(identifier)).thenReturn(Single.error(exception)); final TestObserver<DriveId> testObserver = driveStreamsManager.getDriveId(identifier).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void getFilesInFolder() throws Exception { when(driveDataStreams.getFilesInFolder(driveFolder)).thenReturn(Observable.just(driveId)); final TestObserver<DriveId> testObserver = driveStreamsManager.getFilesInFolder(driveFolder).test(); testObserver.assertValue(driveId); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void getFilesInFolderErrorIsForwarded() throws Exception { final Exception exception = new Exception("test"); when(driveDataStreams.getFilesInFolder(driveFolder)).thenReturn(Observable.error(exception)); final TestObserver<DriveId> testObserver = driveStreamsManager.getFilesInFolder(driveFolder).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void getFilesInFolderForName() throws Exception { final String filename = "filename"; when(driveDataStreams.getFilesInFolder(driveFolder, filename)).thenReturn(Observable.just(driveId)); final TestObserver<DriveId> testObserver = driveStreamsManager.getFilesInFolder(driveFolder, filename).test(); testObserver.assertValue(driveId); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void getFilesInFolderErrorIsForwardedForName() throws Exception { final String filename = "filename"; final Exception exception = new Exception("test"); when(driveDataStreams.getFilesInFolder(driveFolder, filename)).thenReturn(Observable.error(exception)); final TestObserver<DriveId> testObserver = driveStreamsManager.getFilesInFolder(driveFolder, filename).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void getMetadata() throws Exception { when(driveDataStreams.getMetadata(driveFile)).thenReturn(Single.just(metadata)); final TestObserver<Metadata> testObserver = driveStreamsManager.getMetadata(driveFile).test(); testObserver.assertValue(metadata); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void getMetadataErrorIsForwarded() throws Exception { final Exception exception = new Exception("test"); when(driveDataStreams.getMetadata(driveFile)).thenReturn(Single.error(exception)); final TestObserver<Metadata> testObserver = driveStreamsManager.getMetadata(driveFile).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void uploadFileToDriveWithSyncState() throws Exception { final File file = new File("/"); when(driveDataStreams.getSmartReceiptsFolder()).thenReturn(Observable.just(driveFolder)); when(driveDataStreams.createFileInFolder(driveFolder, file)).thenReturn(Single.just(driveFile)); when(driveStreamMappings.postInsertSyncState(currentSyncState, driveFile)).thenReturn(newSyncState); final TestObserver<SyncState> testObserver = driveStreamsManager.uploadFileToDrive(currentSyncState, file).test(); testObserver.assertValue(newSyncState); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void uploadFileToDriveWithSyncStateErrorIsForwarded() throws Exception { final File file = new File("/"); final Exception exception = new Exception("test"); when(driveDataStreams.getSmartReceiptsFolder()).thenReturn(Observable.error(exception)); final TestObserver<SyncState> testObserver = driveStreamsManager.uploadFileToDrive(currentSyncState, file).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void uploadFileToDrive() throws Exception { final String id = "id"; final File file = new File("/"); when(driveDataStreams.getSmartReceiptsFolder()).thenReturn(Observable.just(driveFolder)); when(driveDataStreams.createFileInFolder(driveFolder, file)).thenReturn(Single.just(driveFile)); when(driveFile.getDriveId()).thenReturn(driveId); when(driveId.getResourceId()).thenReturn(id); final TestObserver<Identifier> testObserver = driveStreamsManager.uploadFileToDrive(file).test(); testObserver.assertValue(new Identifier(id)); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void uploadFileToDriveErrorIsForwarded() throws Exception { final File file = new File("/"); final Exception exception = new Exception("test"); when(driveDataStreams.getSmartReceiptsFolder()).thenReturn(Observable.error(exception)); final TestObserver<Identifier> testObserver = driveStreamsManager.uploadFileToDrive(file).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void updateDriveFileWithSyncState() throws Exception { final File file = new File("/"); when(currentSyncState.getSyncId(SyncProvider.GoogleDrive)).thenReturn(identifier); when(driveDataStreams.updateFile(identifier, file)).thenReturn(Single.just(driveFile)); when(driveStreamMappings.postUpdateSyncState(currentSyncState, driveFile)).thenReturn(newSyncState); final TestObserver<SyncState> testObserver = driveStreamsManager.updateDriveFile(currentSyncState, file).test(); testObserver.assertValue(newSyncState); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void updateDriveFileWithSyncStateWithoutIdentifier() throws Exception { final File file = new File("/"); when(currentSyncState.getSyncId(SyncProvider.GoogleDrive)).thenReturn(null); final TestObserver<SyncState> testObserver = driveStreamsManager.updateDriveFile(currentSyncState, file).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void updateDriveFileWithIdentifier() throws Exception { final File file = new File("/"); final String id = "id"; when(driveDataStreams.updateFile(identifier, file)).thenReturn(Single.just(driveFile)); when(driveFile.getDriveId()).thenReturn(driveId); when(driveId.getResourceId()).thenReturn(id); final TestObserver<Identifier> testObserver = driveStreamsManager.updateDriveFile(identifier, file).test(); testObserver.assertValue(new Identifier(id)); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void updateDriveFileWithIdentifierErrorIsForwarded() throws Exception { final File file = new File("/"); final Exception exception = new Exception("test"); when(driveDataStreams.updateFile(identifier, file)).thenReturn(Single.error(exception)); final TestObserver<Identifier> testObserver = driveStreamsManager.updateDriveFile(identifier, file).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void deleteDriveFileWithIdentifierSuccessfully() throws Exception { when(currentSyncState.getSyncId(SyncProvider.GoogleDrive)).thenReturn(identifier); when(driveDataStreams.delete(identifier)).thenReturn(Single.just(true)); when(driveStreamMappings.postDeleteSyncState(currentSyncState, true)).thenReturn(newSyncState); final TestObserver<SyncState> testObserver = driveStreamsManager.deleteDriveFile(currentSyncState, true).test(); testObserver.assertValue(newSyncState); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void deleteDriveFileWithoutIdentifierSuccessfully() throws Exception { when(currentSyncState.getSyncId(SyncProvider.GoogleDrive)).thenReturn(identifier); when(driveDataStreams.delete(identifier)).thenReturn(Single.just(true)); when(driveStreamMappings.postDeleteSyncState(currentSyncState, true)).thenReturn(newSyncState); final TestObserver<SyncState> testObserver = driveStreamsManager.deleteDriveFile(currentSyncState, true).test(); testObserver.assertValue(newSyncState); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void deleteDriveFileWithIdentifierFailsSoWeReturnTheOriginalState() throws Exception { when(currentSyncState.getSyncId(SyncProvider.GoogleDrive)).thenReturn(identifier); when(driveDataStreams.delete(identifier)).thenReturn(Single.just(false)); when(driveStreamMappings.postDeleteSyncState(currentSyncState, true)).thenReturn(newSyncState); final TestObserver<SyncState> testObserver = driveStreamsManager.deleteDriveFile(currentSyncState, true).test(); testObserver.assertValue(currentSyncState); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void deleteDriveFileErrorIsForwarded() throws Exception { final Exception exception = new Exception("test"); when(currentSyncState.getSyncId(SyncProvider.GoogleDrive)).thenReturn(identifier); when(driveDataStreams.delete(identifier)).thenReturn(Single.error(exception)); final TestObserver<SyncState> testObserver = driveStreamsManager.deleteDriveFile(currentSyncState, true).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void delete() throws Exception { when(driveDataStreams.delete(identifier)).thenReturn(Single.just(true)); final TestObserver<Boolean> testObserver = driveStreamsManager.delete(identifier).test(); testObserver.assertValue(true); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void deleteErrorIsForwarded() throws Exception { final Exception exception = new Exception("test"); when(driveDataStreams.delete(identifier)).thenReturn(Single.error(exception)); final TestObserver<Boolean> testObserver = driveStreamsManager.delete(identifier).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } @Test public void clearCachedData() throws Exception { driveStreamsManager.clearCachedData(); verify(driveDataStreams).clear(); } @Test public void download() throws Exception { final File file = new File("/"); when(driveDataStreams.download(driveFile, file)).thenReturn(Single.just(file)); final TestObserver<File> testObserver = driveStreamsManager.download(driveFile, file).test(); testObserver.assertValue(file); testObserver.assertComplete(); testObserver.assertNoErrors(); } @Test public void downloadErrorIsForwarded() throws Exception { final Exception exception = new Exception("test"); final File file = new File("/"); when(driveDataStreams.download(driveFile, file)).thenReturn(Single.error(exception)); final TestObserver<File> testObserver = driveStreamsManager.download(driveFile, file).test(); testObserver.assertNoValues(); testObserver.assertNotComplete(); testObserver.assertError(Exception.class); verify(driveErrorStream).onNext(Optional.of(criticalSyncError)); } }