class TasksRepository implements TasksDataSource {

    @Override
    public Flowable<List<Task>> getTasks() {
        // Respond immediately with cache if available and not dirty
        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 {
            // Query the local storage if available. If not, query the network.
            Flowable<List<Task>> localTasks = getAndCacheLocalTasks();
            return Flowable.concat(localTasks, remoteTasks)
                    .filter(tasks -> !tasks.isEmpty())
                    .firstOrError()
                    .toFlowable();
        }
    }

}

class TasksRepositoryTest {

    private final static String TASK_TITLE;
    private final static String TASK_TITLE2;
    private final static String TASK_TITLE3;
    private static List<Task> TASKS;
    private TasksRepository mTasksRepository;
    private TestSubscriber<List<Task>> mTasksTestSubscriber;
    @Mock
    private TasksDataSource mTasksRemoteDataSource;
    @Mock
    private TasksDataSource mTasksLocalDataSource;
    @Mock
    private Context mContext;

    @Test
    public void getTasks_requestsAllTasksFromLocalDataSource() {

        // Given that the local data source has data available
        setTasksAvailable(mTasksLocalDataSource, TASKS);
        // And the remote data source does not have any data available
        setTasksNotAvailable(mTasksRemoteDataSource);

        // When tasks are requested from the tasks repository
        mTasksRepository.getTasks().subscribe(mTasksTestSubscriber);

        // Then tasks are loaded from the local data source
        Mockito.verify(mTasksLocalDataSource).getTasks();
        mTasksTestSubscriber.assertValue(TASKS);
    }

}