I want to use StepVerifier in integration testing save operations in Mongo repository.
I prepared a method for inserting multiple UserItems for further verification:
Flux<UserItems> saveMultiple(int numberOfItems) {
return Flux.range(0, numberOfItems)
.flatMap { userItemsRepository.save(new UserItem(it)) }
}
userItemsRepository.save returns Mono<UserItem>
I prepared a test method:
def "Should save all UserItems"() {
given:
def numberOfItems = 3
when:
def saveResult = saveMultiple(numberOfItems)
then:
StepVerifier.create(saveResult)
.expectNextMatches {it.itemNo == 0 }
.expectNextMatches {it.itemNo == 1 }
.expectNextMatches {it.itemNo == 2 }
.expectComplete()
.verify()
}
And I expect that next items will emerge in the order {0,1,2}. Unfortunately, the test fails because of java.lang.AssertionError in non deterministic way, on various step. I cannot figure out how to do it properly. It's my first approach to test Reactor flow. Anyone has an idea, how to handle such situations?
The flatMap operator doesn't preserve order of the source and lets values from different inners interleave.
So depending on userItemsRepository.save you can have something like:
1--2--3--4
flatMap
UserItem2--UserItem4--UserItem1--UserItem3
if interleaving doesn't bother you but want to keep the original order you can use flatMapSequencial or if you don't want any interleave concatMap
Related
I notice this problem during the following test:
verify(mockedObject).functionCall(argThat(inputStream -> {
final String content = ... // read the inputStream
assertEquals(expectedContent, content);
return true;
}));
It will actually fail although the assertEquals assertion is true. I debug the test, find that the lambda function is reached twice, and at the second time, the cursor of the stream is at the end of the stream. That's why it fails.
So I have to reset the stream first:
verify(mockedObject).functionCall(argThat(inputStream -> {
inputStream.reset();
final String content = ... // read the inputStream
assertEquals(expectedContent, content);
return true;
}));
The question is, why the lambda is triggered twice? Is this by design? Does it have a document?
Mockito version: 2.22
Junit version: 5.6.0
Java version: 1.8
Update
The method is called exactly once, and the inputs of two lambda calls are exactly the same input. Actually, they are the same object. The only thing I have to do is to reset the stream, as it has been exhausted by the first lambda call.
I wouldn't say it's "by design", rather that it's what the current implementation does. The Mockito Times class which performs your assertions has the following method (I'm on a pretty recent version so YMMV):
public void verify(VerificationData data) {
List<Invocation> invocations = data.getAllInvocations();
MatchableInvocation wanted = data.getTarget();
if (wantedCount > 0) {
checkMissingInvocation(data.getAllInvocations(), data.getTarget());
}
checkNumberOfInvocations(invocations, wanted, wantedCount);
}
Both checkMissingInvocation and checkNumberOfInvocations perform independent filtering on the list of all invocations to retain the relevant ones, so any matcher you declare ends up being executed twice for each invocation. It's actually exactly the same call:
List<Invocation> actualInvocations = findInvocations(invocations, wanted);
Maybe the filtered list could be cached, but the point is that unless otherwise specified in the documentation, you cannot assume that the function you supply will be executed only once. Also, predicate functions are generally expected to be free of side-effects.
I'm quite newbie in webflux and I want to do the following thing:
I want to make parallel http requests to the same url with different parameter values and to stop when I get the first non null (and non exceptional) result.
I'm following the example from here https://www.baeldung.com/spring-webclient-simultaneous-calls
but I have no idea how to stop when I got the result. Can anybody help me?
Currently I have something like this:
RetrySpec retrySpec = Retry.max(3);
return webClient.get().uri("/getMyObject/{id}", id)
.retrieve()
.bodyToMono(MyObject.class)
.retryWhen(retrySpec);
}
public Flux<> getMyObjs(List<String> ids) {
return Flux.fromIterable(ids)
.parallel(Runtime.getRuntime().availableProcessors())
.runOn()
.flatMap(this::getMyObject)
.;//// Stop when I get first non exceptional value
}
Try the next() operator in Flux.
public Mono<MyObject> getMyObjs(List<String> ids) {
return Flux.fromIterable(ids)
.parallel(Runtime.getRuntime().availableProcessors())
.runOn()
.flatMap(this::getMyObject)
.next();// Emit only the first item emitted by this Flux, into a new Mono. If called on an empty Flux, emits an empty Mono.
}
Reference: https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#next--
However check the firstWithSignal & firstWithValue operator as well.
https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#firstWithSignal-java.lang.Iterable-
https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#firstWithValue-java.lang.Iterable-
When I get a problem like this, normally I check the documentation to find a proper operator from Flux API.
I'm trying to add the RX Android pack library on a previous MVC project, wherein I'm trying to handle values from API responses to the Activity controller, passing by some controller that would do some additional operations on it.
The possibilities are that the value may be empty/optional/null by the API, in that case the controller would try to get the value from a cache storage, that also may be in the same condition, and finally pass it to the controller, where, depending the value, it would do some initing operation, or trying to make another API call with same mechanism, check that response, and then choose how to init the activity.
Example code (signatures are wrong)
In API:
Maybe<User> getUser(){
//...
}
In Controller:
Single<User> getUser(){
return API.getUser().switchIfEmpty(() -> Cache.getUser());
}
In Activity:
Disposable d = getUser().subscribe(user -> { if(user != null) init(user); else checkGuest(); } );
//...
void checkGuest(){
Disposable d = getGuest().subscribe(guest -> { init(guest) } );
}
All of this would be incredibly cool and smooth, except for a consideration, RX Java cannot handle null values. We may say that since Java 8 where are trying to get over null values in favor of Optional values (really?!?!?), so the Empty/Maybe pattern would be appropriate.
So, let's try this...
In API:
Maybe<User> getUser(){
//...
}
In Controller:
Single<User> getUser(){
return API.getUser().switchIfEmpty(() -> Cache.getUser()).switchIfEmpty(() -> ???);
}
In Activity:
Disposable d = getUser().subscribe(user -> { if(user != ???) init(user); else checkGuest(); } );
//...
void checkGuest(){
Disposable d = getGuest().subscribe(guest -> { init(guest) } );
}
I want to say that I hate and cannot accept at all to modify my models to add kind of additional attribute that would signs the instance as a Rx nulled instance, also because, this is an absolute violation of integrity, as of in any other method would be mandatory to check for that attribute, with a looooot of boilerplate.
Solutions:
1 I'm trying to handle this just by using single, and custom exception conditional checking in subscribe's error callable to decide where to proceed to next method in chain propagation, mixing functional and reactive programming.
2 I would have to modify my models, and use the RX Nulled instances in place of our beloved null values, but of course, also because I'm using Realm, and I can't even use polymorphism, and also, it violates integrity as said before.
3 Ideally, I would like to preserve the chain pattern and by using Maybe be able to execute a chain path if a previous value is Empty or another chain path if the value is not.
I would be happy if someone would feel like to front on the option 3, that would be the one that made me say "WOW" on the first time I seen a ReactiveX example.
After some searching, I found that eventually the best solution is in fact to... hold fast... to use Java 8 Optional!
First, this allows to keep the good old universal null like check pattern as always, so that we can't really need to forget about it, but also, to go on with the new technologies developments and so to conform to the new standard as we like to, and so to follow the new Java specifications as they come out.
This is also a "not" backward compatibility break, as in Android we can rely on some backporting dependencies to enable this before API level 24.
// support for optionals
compile "net.sourceforge.streamsupport:streamsupport:1.5.1"
And moreover, this permits to use chained operations, conditionality, ReactiveX and a Single value as we coders prefer to.
public Single<Optional<Model>> getMyModel(boolean offlineFallback) {
return apiInterface.getModel()
.map( model -> {
if( model.isPresent() ){
MyModel serverMyModel = model.get();
MyModel savedMyModel = databaseRepository.getMyModel();
if( serverMyModel != savedMyModel ){
serverMyModel.setMyAttribute(true);
databaseRepository.saveMyModel( serverMyModel );
}
return java8.util.Optional.ofNullable( serverMyModel );
}else{
if(offlineFallback){
MyModel MyModel = databaseRepository.getMyModel();
if(MyModel != null){
return java8.util.Optional.ofNullable(MyModel);
}
}
return Optional.empty();
}
});
}
Isn't this nice?
Since I´m using Vertx 3.1 in my stack, I was thinking to use the Future feature that the tools brings, but after read the API seems pretty limited to me. I cannot even find the way to make the the future wait for an Observable.
Here my code
public Observable<CommitToOrderCommand> validateProductRestrictions(CommitToOrderCommand cmd) {
Future<Observable<CommitToOrderCommand>> future = Future.future();
orderRepository.getOrder(cmd, cmd.orderId)
.flatMap(order -> validateOrderProducts(cmd, order))
.subscribe(map -> checkMapValues(map, future, cmd));
Observable<CommitToOrderCommand> result = future.result();
if(errorFound){
throw MAX_QUANTITY_PRODUCT_EXCEED.create("Fail"/*restrictions.getBulkBuyLimit().getDescription())*/);
}
return result;
}
private void checkMapValues(Multimap<String, BigDecimal> totalUnitByRestrictions, Future<Observable<CommitToOrderCommand>> future,
CommitToOrderCommand cmd) {
for (String restrictionName : totalUnitByRestrictions.keySet()) {
Restrictions restrictions = Restrictions.valueOf(restrictionName);
if (totalUnitByRestrictions.get(restrictionName)
.stream()
.reduce(BigDecimal.ZERO, BigDecimal::add)
.compareTo(restrictions.getBulkBuyLimit()
.getMaxQuantity()) == 1) {
errorFound = true;
}
}
future.complete(Observable.just(cmd));
}
In the onComplete of my first Observable I´m checking the results, and after finish is when I finish the future to unblock the operation.
But I´m looking that future.result is not block until future.complete is invoke as I was expecting. Instead is just returning null.
Any idea what´s wrong here?
Regards.
The vertx future doesn't block but rather work with a handler that is invoked when a result has been injected (see setHandler and isComplete).
If the outer layer of code requires an Observable, you don't need to wrap it in a Future, just return Observable<T>. Future<Observable<T>> doesn't make much sense, you're mixing two ways of doing async results.
Note that there are ways to collapse an Observable into a Future, but the difficulty is that an Observable may emit several items whereas a Future can hold only a single item. You already took care of that by collecting your results into a single emission of map.
Since this Observable only ever emits one item, if you want a Future out of it you should subscribe to it and call future.complete(yourMap) in the onNext method. Also define a onError handler that will call future.fail.
I have one unit test in which I am writing and reading from cassandra multiple times.
future = function(Cassandra update with value x) - async //write and read updated value
value = future.get(); //reading
print value;
assert value == x;
//doing the above operation multiple times with different values of x;
Running the same code multiple times is showing different results i.e printing different result for 'value' attribute.
I am using cassandra on local host with
replication = {
'class': 'SimpleStrategy',
'replication_factor': '1'
};
It's worth noting that I am writing and reading at a same row in the table (in all read and write, primary key is same).
And though I am modifying the same object multiple times, but they are supposed to run sequentially as I am running blocking function future.get() after every update statement.
I am using Cassandra 2.0.14 with datastax driver and jdk 1.8.
Any ideas why I must be facing such behaviour?
Figured out the reason.
In my code (not the test code), I wasn't actually writing and reading sequentially. Read wasn't waiting for the write to be completed.
What I was doing:
`CompletionStage<Void> Function() {
someOperation
.thenAccept(variable -> AsyncWriteInDb(variable));
}
// AsyncWriteInDb returns CompletionStage<Void> when write is completed.
// I was reading just after execution of this function.
`
What I should be doing:
` CompletionStage<Void> Function() {
someOperation
.thenCompose(variable -> AsyncWriteInDb(variable));
}
//AsyncWriteInDb returns CompletionStage<Void> when write is completed.
`
It's easier to understand if I write earlier (wrong) code part as below:
`CompletionStage<Void> Function() {
someOperation
.thenAccept(variable -> {
AsyncWriteInDb(variable);
return;
});
}
// thenAccept's lamda was returning after initiating an asyncDbWrite.
// Reading just after this doesnt ensure sequential reading after writing.
`