RxJava Schedulers.immediate() behavior while Unit Testing - java

I am trying to write test for my DAO object that uses reactive interface. I have a table with recipes and I want to test that when I insert data to this table, the subscriber receives list with recipes.
I am using TestSubscriber class and performing asserts on that class. My simple test look like this:
#Test
fun testSubscriber() {
insertItem()
val testSubscriber = TestSubscriber.create<List<Recipe>>()
recipeDao
.getRecipes()
.subscribeOn(Schedulers.immediate())
.subscribe(testSubscriber)
testSubscriber.assertNoErrors()
testSubscriber.assertNoTerminalEvent()
testSubscriber.assertNotCompleted()
testSubscriber.assertValueCount(1)
assertEquals(1, testSubscriber.onNextEvents[0].size)
}
The problem is that assertion testSubscriber.assertValueCount(1) fails because no item was emitted. But when I insert this line above
testSubscriber.awaitTerminalEvent(500, TimeUnit.MILLISECONDS), the test is successful. My observable does not emit terminal event and therefore the timeout is performed, but in the meantime of waiting, the onNext was called with list of recipes.
My getRecipes method:
fun getRecipes(): Observable<List<Recipe>> {
return query(SELECT("*")
.FROM(Recipe.TABLE_NAME)
.ORDER_BY(Recipe.COL_NAME))
.run()
.mapToList(RecipeMapper.MAPPER)
}
How is that possible? I thought that when I use Schedulers.immediate(), the operation will be performed on the same thread and my TestSubscriber receives the events. If not, how should I write this test so it succeeds? I want to test that onNext is called and I don't want to insert artificial sleep commands between.

The problem was that I was using library SqlBrite with additional framework SqlBrite-Dao. SqlBrite is observing a query on specific Scheduler and when none was provided to DaoManager of SqlBrite-Dao, Schedulers.io() was used. The solution is to provide scheduler to DaoManager.Builder or apply RxJavaPlugins and return Schedulers.immediate() as all Schedulers.

Related

How to manipulate the order of the Before-/AfterScenarios in JBehave?

In our project we are currently encountering multiple Before-/AfterScenarios, which all by definition get executed before/after every Scenario. However some of the methods are dependent on the execution of the others.
More precisely: A third party framework uses BeforeScenario in their code, that should always be executed before our BeforeScenario. JBehave has a way of prioritizing steps when it comes to chosing the correct step for execution.
#Then(value="the value returned is empty", priority=1)
public void theValueIsEmpty()
#Then("the value returned is $value")
public void theValueIs(String value)
Is there something similar for the Before-/AfterScenario annotation?
There is no way to order execution of #BeforeScenario/#AfterScenrio in JBehave. But you can try using new Lifecycle functionality:
Lifecycle:
Before:
Scope: SCENARIO
[steps to be executed before each scenario]
After:
Scope: SCENARIO
[steps to be executed after each scenario]
More details can be found in the official documentation: Lifecycle
Alternative approach: file a new JIRA ticket for Before/After prioritizing and implement it or wait for implementation from JBehave contributors.

How can I run a concurrent queue of tasks using Rx?

I've found a lot of examples about it and doesn't know what's the 'right' implementation right there.
Basically I've got a object (let's call it NBAManager) and there's a method public Completable generateGame() for this object. The idea is that generateGame method gets called a lot of times and I want to generate games in a sequential way: I was thinking about concurrent queue. I came up with the following design: I'd create a singleton instance of NBAService: service for NBAManager and the body of generateGame() will look like this:
public Completable generateGame(RequestInfo info)
return service.generateGame(info);
So basically I'll pass up that Completable result. And inside of that NBAService object I'll have a queue (a concurrent one, because I want to have an opportunity to poll() and add(request) if there's a call of generateGame() while NBAManager was processing one of the earlier requests) of requests. I got stuck with this:
What's the right way to write such a job queue in Rx way? There're so many examples of it. Could you send me a link of a good implementation?
How do I handle the logic of queue execution? I believe we've to execute if there's one job only and if there're many then we just have to add it and that's it. How can I control it without runnable? I was thinking about using subjects.
Thanks!
There are multiple ways to implement this, you can choose how much RxJava should be invoked. The least involvement can use a single threaded ExecutorService as the "queue" and CompletableSubject for the delayed completion:
class NBAService {
static ExecutorService exec = Executors.newSingleThreadedExecutor();
public static Completable generateGame(RequestInfo info) {
CompletableSubject result = CompletableSubject.create();
exec.submit(() -> {
// do something with the RequestInfo instance
f(info).subscribe(result);
});
return result;
}
}
A more involved solution would be if you wanted to trigger the execution when the Completable is subscribed to. In this case, you can go with create() and subscribeOn():
class NBAService {
public static Completable generateGame(RequestInfo info) {
return Completable.create(emitter -> {
// do something with the RequestInfo instance
emitter.setDisposable(
f(info).subscribe(emitter::onComplete, emitter::onError)
);
})
.subscribeOn(Schedulers.single());
}
}

Wrapping blocking I/O in project reactor

I have a spring-webflux API which, at a service layer, needs to read from an existing repository which uses JDBC.
Having done some reading on the subject, I would like to keep the execution of the blocking database call separate from the rest of my non-blocking async code.
I have defined a dedicated jdbcScheduler:
#Bean
public Scheduler jdbcScheduler() {
return Schedulers.fromExecutor(Executors.newFixedThreadPool(maxPoolSize));
}
And an AsyncWrapper utility to use it:
#Component
public class AsyncJdbcWrapper {
private final Scheduler jdbcScheduler;
#Autowired
public AsyncJdbcWrapper(Scheduler jdbcScheduler) {
this.jdbcScheduler = jdbcScheduler;
}
public <T> Mono<T> async(Callable<T> callable) {
return Mono.fromCallable(callable)
.subscribeOn(jdbcScheduler)
.publishOn(Schedulers.parallel());
}
}
Which is then used to wrap jdbc calls like so:
Mono<Integer> userIdMono = asyncWrapper.async(() -> userDao.getUserByUUID(request.getUserId()))
.map(userOption -> userOption.map(u -> u.getId())
.orElseThrow(() -> new IllegalArgumentException("Unable to find user with ID " + request.getUserId())));
I've got two questions:
1) Am I correctly pushing the execution of blocking calls to another set of threads? Being fairly new to this stuff I'm struggling with the intricacies of subscribeOn()/publishOn().
2) Say I want to make use of the resulting mono, e.g call an API with the result of the userIdMono, on which scheduler will that be executed? The one specifically created for the jdbc calls, or the main(?) thread that reactor usually operates within? e.g.
userIdMono.map(id -> someApiClient.call(id));
1) Use of subscribeOn is correctly putting the JDBC work on the jdbcScheduler
2) Neither, the results of the Callable - while computed on the jdbcScheduler, are publishOn the parallel Scheduler, so your map will be executed on a thread from the Schedulers.parallel() pool (rather than hogging the jdbcScheduler).

RxJava Multithreading with Realm - Realm access from incorrect thread

Background
I am using Realm within my app. When data is loaded it then undergoes intense processing therefore the processing occurs on a background thread.
The coding pattern in use is the Unit of Work pattern and Realm only exists within a repository under a DataManager. The idea here is that each repository can have a different database/file storage solution.
What I have tried
Below is an example of some similar code to what I have in my FooRespository class.
The idea here is that an instance of Realm is obtained, used to query the realm for objects of interest, return them and close the realm instance. Note that this is synchronous and at the end copies the objects from Realm to an unmanaged state.
public Observable<List<Foo>> getFoosById(List<String> fooIds) {
Realm realm = Realm.getInstance(fooRealmConfiguration);
RealmQuery<Foo> findFoosByIdQuery = realm.where(Foo.class);
for(String id : fooIds) {
findFoosByIdQuery.equalTo(Foo.FOO_ID_FIELD_NAME, id);
findFoosByIdQuery.or();
}
return findFoosByIdQuery
.findAll()
.asObservable()
.doOnUnsubscribe(realm::close)
.filter(RealmResults::isLoaded)
.flatMap(foos -> Observable.just(new ArrayList<>(realm.copyFromRealm(foos))));
}
This code is later used in conjunction with the heavy processing code via RxJava:
dataManager.getFoosById(foo)
.flatMap(this::processtheFoosInALongRunningProcess)
.subscribeOn(Schedulers.io()) //could be Schedulers.computation() etc
.subscribe(tileChannelSubscriber);
After reading the docs, my belief is that the above should work, as it is NOT asynchronous and therefore does not need a looper thread. I obtain the instance of realm within the same thread therefore it is not being passed between threads and neither are the objects.
The problem
When the above is executed I get
Realm access from incorrect thread. Realm objects can only be accessed
on the thread they were created.
This doesn't seem right. The only thing I can think of is that the pool of Realm instances is getting me an existing instance created from another process using the main thread.
Kay so
return findFoosByIdQuery
.findAll()
.asObservable()
This happens on UI thread, because that's where you're calling it from initially
.subscribeOn(Schedulers.io())
Aaaaand then you're tinkering with them on Schedulers.io().
Nope, that's not the same thread!
As much as I dislike the approach of copying from a zero-copy database, your current approach is riddled with issues due to misuse of realmResults.asObservable(), so here's a spoiler for what your code should be:
public Observable<List<Foo>> getFoosById(List<String> fooIds) {
return Observable.defer(() -> {
try(Realm realm = Realm.getInstance(fooRealmConfiguration)) { //try-finally also works
RealmQuery<Foo> findFoosByIdQuery = realm.where(Foo.class);
for(String id : fooIds) {
findFoosByIdQuery.equalTo(FooFields.ID, id);
findFoosByIdQuery.or(); // please guarantee this works?
}
RealmResults<Foo> results = findFoosByIdQuery.findAll();
return Observable.just(realm.copyFromRealm(results));
}
}).subscribeOn(Schedulers.io());
}
Note that you are creating the instance outside of all your RxJava processing pipeline. Thus on the main thread (or whichever thread you are on, when calling getFoosById().
Just because the method returns an Observable doesn't mean that it runs on another thread. Only the processing pipeline of the Observable created by the last statement of your getFoosById() method runs on the correct thread (the filter(), the flatMap() and all the processing done by the caller).
You thus have to ensure that the call of getFoosById()is already done on the thread used by Schedulers.io().
One way to achieve this is by using Observable.defer():
Observable.defer(() -> dataManager.getFoosById(foo))
.flatMap(this::processtheFoosInALongRunningProcess)
.subscribeOn(Schedulers.io()) //could be Schedulers.computation() etc
.subscribe(tileChannelSubscriber);

how to catch astyanax failures in asynchronous executions

The project I work on uses astyanax driver to access Cassandra. I want to implement an asynchronous operation:
MutationBatch m;
//…
ListenableFuture<OperationResult<Void>> lf = m.executeAsync();
lf.addListener(myRunnableCallback, myExecutor);
Question: assuming the exception was not thrown right away within executeAsync() call, how do I distinguish between successful and failed executions?
The only way I can think of is that when the completion callback is invoked lf.get() throws an exception in case of failure. If this is the right way, is there a document or lines in astyanax sources confirming that?
I found a workaround: instead of ListenableFuture's addListener method taking Runnable parameter I can use Futures.addCallback(ListenableFuture<V>, FutureCallback<V>, Executor). FutureCallback has 2 methods: onSuccess and onFailure. That solves my problem.
https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained

Categories