TasksRepository implements TasksDataSource { @Override public Flowable<List<Task>> getTasks() { if (mCachedTasks != null && !mCacheIsDirty) { return Flowable.fromIterable(mCachedTasks.values()).toList().toFlowable(); } else if (mCachedTasks == null) { mCachedTasks = new LinkedHashMap<>(); } Flowable<List<Task>> remoteTasks = getAndSaveRemoteTasks(); if (mCacheIsDirty) { return remoteTasks; } else { Flowable<List<Task>> localTasks = getAndCacheLocalTasks(); return Flowable.concat(localTasks, remoteTasks) .filter(tasks -> !tasks.isEmpty()) .firstOrError() .toFlowable(); } } private  TasksRepository(@NonNull TasksDataSource tasksRemoteDataSource,
                            @NonNull TasksDataSource tasksLocalDataSource); static TasksRepository getInstance(@NonNull TasksDataSource tasksRemoteDataSource,
                                              @NonNull TasksDataSource tasksLocalDataSource); static void destroyInstance(); @Override Flowable<List<Task>> getTasks(); @Override void saveTask(@NonNull Task task); @Override void completeTask(@NonNull Task task); @Override void completeTask(@NonNull String taskId); @Override void activateTask(@NonNull Task task); @Override void activateTask(@NonNull String taskId); @Override void clearCompletedTasks(); @Override Flowable<Optional<Task>> getTask(@NonNull final String taskId); @Override void refreshTasks(); @Override void deleteAllTasks(); @Override void deleteTask(@NonNull String taskId);  }
@Test public void getTasks_repositoryCachesAfterFirstSubscription_whenTasksAvailableInLocalStorage() { setTasksAvailable(mTasksLocalDataSource, TASKS); setTasksNotAvailable(mTasksRemoteDataSource); TestSubscriber<List<Task>> testSubscriber1 = new TestSubscriber<>(); mTasksRepository.getTasks().subscribe(testSubscriber1); TestSubscriber<List<Task>> testSubscriber2 = new TestSubscriber<>(); mTasksRepository.getTasks().subscribe(testSubscriber2); Mockito.verify(mTasksRemoteDataSource).getTasks(); Mockito.verify(mTasksLocalDataSource).getTasks(); assertFalse(mTasksRepository.mCacheIsDirty); testSubscriber1.assertValue(TASKS); testSubscriber2.assertValue(TASKS); }
@Test public void getTasks_repositoryCachesAfterFirstSubscription_whenTasksAvailableInRemoteStorage() { setTasksAvailable(mTasksRemoteDataSource, TASKS); setTasksNotAvailable(mTasksLocalDataSource); TestSubscriber<List<Task>> testSubscriber1 = new TestSubscriber<>(); mTasksRepository.getTasks().subscribe(testSubscriber1); TestSubscriber<List<Task>> testSubscriber2 = new TestSubscriber<>(); mTasksRepository.getTasks().subscribe(testSubscriber2); Mockito.verify(mTasksRemoteDataSource).getTasks(); Mockito.verify(mTasksLocalDataSource).getTasks(); assertFalse(mTasksRepository.mCacheIsDirty); testSubscriber1.assertValue(TASKS); testSubscriber2.assertValue(TASKS); }
@Test public void getTasks_requestsAllTasksFromLocalDataSource() { setTasksAvailable(mTasksLocalDataSource, TASKS); setTasksNotAvailable(mTasksRemoteDataSource); mTasksRepository.getTasks().subscribe(mTasksTestSubscriber); Mockito.verify(mTasksLocalDataSource).getTasks(); mTasksTestSubscriber.assertValue(TASKS); }
@Test public void getTasksWithLocalDataSourceUnavailable_tasksAreRetrievedFromRemote() { setTasksNotAvailable(mTasksLocalDataSource); setTasksAvailable(mTasksRemoteDataSource, TASKS); mTasksRepository.getTasks().subscribe(mTasksTestSubscriber); Mockito.verify(mTasksRemoteDataSource).getTasks(); mTasksTestSubscriber.assertValue(TASKS); }