Wait for a *specific* (single) XCTestExpectation with a completion handler? - swift

Has anyone managed to wait for a specific, single, XCTestExpectation with completion handler (XCWaitCompletionHandler or equivalent) similar to that of (waitForExpectations:timeout:handler)[https://developer.apple.com/documentation/xctest/xctestcase/1500748-waitforexpectations].
I want to wait for just one specific expectation, but I would like to know if it timed out. The XCWaitCompletionHandler gives me that information. But there are no properties on the expectation itself flagging whether it timed out or not.
(yes this is a rather advanced use case...)

Create an XCTWaiter and use wait(for:timeout:), which returns a XCTWaiter.Result, which you can then assert is/is not .timedOut if you wish, or otherwise act on the result. By using XCTWaiter, you can have an expectation time out without the test automatically failing.
let result = XCTWaiter().wait(for: [expectation], timeout: 5)
if result == .timedOut { ... }

Related

Webflux: OnErrorResume after repeats are exhausted is not being triggered

I am trying to execute the code after repeat exhaustion using onErrorResume but onErrorResume is not being trigger.
Here is the code sample
Mono.just(request)
.filter(this::isConditionSatified)
.map(aBoolean -> performSomeOperationIfConditionIsSatified(request))
.repeatWhenEmpty(Repeat.onlyIf(i -> true)
.exponentialBackoff(Duration.ofSeconds(5)), Duration.ofSeconds(10))
.timeout(Duration.ofSeconds(30)))
.delaySubscription(Duration.ofSeconds(10)))
.onErrorResume(throwable -> {
log.warn("Max timeout reached", throwable);
return Mono.just(false);
});
onErrorResume is never trigged. I am trying to use it as a fallback. My goal is if the repeat exhaustion is hit, return the false value.
My unit test complains of
expectation "expectNext(false)" failed (expected: onNext(false); actual: onComplete())
Any help or suggestion would be helpful.
since an empty source is valid by itself, repeatWhenEmpty doesn't necessarily propagate an exception after exhausting its attempts. The Repeat util from addons doesn't, even when the "timeout" triggers (as hinted in the timeout parameter's javadoc: "timeout after which no new repeats are initiated", ok that could be clearer).
since you're using repeatWhenEMPTY, I'm guessing that the empty case is always "irrelevant" to you and thus defaultIfEmpty(false) should be the acceptable solution.

How to trigger handle_info due to timeout in erlang?

I am using a gen_server behaviour and trying to understand how can handle_info/2 be triggered from a timeout occurring in a handle_call for example:
-module(server).
-export([init/1,handle_call/3,handle_info/2,terminate/2).
-export([start/0,stop/0]).
init(Data)->
{ok,33}.
start()->
gen_server:start_link(?MODULE,?MODULE,[]).
stop(Pid)->
gen_server:stop(Pid).
handle_call(Request,From,State)->
Return={reply,State,State,5000},
Return.
handle_info(Request,State)->
{stop,Reason,State}.
terminate(Reason,State)->
{ok,S}=file:file_open("D:/Erlang/Supervisor/err.txt",[read,write]),
io:format(S,"~s~n",[Reason]),
ok.
What i want to do:
I was expecting that if I launch the server and would not use gen_server:call/2 for 5 seconds (in my case) then handle_info would be called, which would in turn issue the stop thus calling terminate.
I see it does not happen this way, in fact handle_info is not called at all.
In examples such as this i see the timeout is set in the return of init/1.What I can deduce is that it handle_info gets triggered only if I initialize the server and issue nothing (nor cast nor call for N seconds).If so why I can provide Timeout in the return of both handle_cast/2 and handle_call/3 ?
Update:
I was trying to get the following functionality:
If no call is issued in X seconds trigger handle_info/2
If no cast is issued in Y seconds trigger handle_info/2
I thought this timeouts can be set in the return of handle_call and handle_cast:
{reply,Reply,State,X} //for call
{noreply,State,Y} //for cast
If not, when are those timeouts triggered since they are returns?
To initiate timeout handling from gen_server:handle_call/3 callback, this callback has to be called in the first place. Your Return={reply,State,State,5000}, is not executed at all.
Instead, if you want to “launch the server and would not use gen_server:call/2 for 5 seconds then handle_info/2 would be called”, you might return {ok,State,Timeout} tuple from gen_server:init/1 callback.
init(Data)->
{ok,33,5000}.
You cannot set the different timeouts for different calls and casts. As stated by Alexey Romanov in comments,
Having different timeouts for different types of messages just isn’t something any gen_* behavior does and would have to be simulated by maintaining them inside state.
If one returns {reply,State,Timeout} tuple from any handle_call/3/handle_cast/2, the timeout will be triggered if the mailbox of this process is empty after Timeout.
i suggest you read source code:gen_server.erl
% gen_server.erl
% line 400
loop(Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug) ->
Msg = receive
Input ->
Input
after Time ->
timeout
end,
decode_msg(Msg, Parent, Name, State, Mod, Time, HibernateAfterTimeout, Debug, false).
it helps you to understand the parameter Timeout

Anyway to stop a sequence of actions?

I sort of like the idea of sequences, but I would like to be able to have an action basically stop the sequence. The idea is to have an action which filters the incoming message, and if it doesn't meet certain criteria it would return false or something and essentially stop the processing of the sequence.
I could probably incorporate a convention myself, but wondered if there was a mechanism.
You can fail the filtering action by returning a rejected Promise instead of a resolved one. That will fail the action and thus break the sequence at that point.
Here's a short example that might help:
function main(args) {
if(args.myValue == "myValue") {
return Promise.resolve({...});
} else
return Promise.reject({...});
}
}

Swift2 UITest - Wait for element to appear without treating test as Failed in case element won't appear

I try to create UI test on the application where sometimes AD popup appears and if so I need to click on close button. I tried to use:
waitForExpectationsWithTimeout(timeout: NSTimeInterval, handler: XCWaitCompletionHandler?)
with
let existsPredicate = NSPredicate(format: "exists == true")
But the problem is that the method treats test as failed which is not acceptable for my case.
I tried to use .exists after custom sleep but from my observations it just always returns false even though element does appear on the screen.
Also plaid around with .hittable and it seems to be true even though the element didn't appear on the screen yet.
From my understanding it would be great if Apple gives control of whether waitForExpectationsWithTimeout treats test as fail or not, but I was not able to find anything.
Any advice would be greatly appreciated!
i can suggest you not to use handler XCWaitCompletionHandler in this case.
expectationForPredicate(predicate, evaluatedWithObject: evaluatedWithObject, handler: nil)
waitForExpectationsWithTimeout(TIMEOUT, handler: nil)
if (evaluatedWithObject.exist) {
//dosmth
}
so it is soft assert that smth appears. If element not found it just will wait time and go further
Unfortunately the only solution I've found is to do it manually: use a while loop and check for object.exists for a waiting period to prevent the expectation wait failure.

Rx Extensions - Proper way to use delay to avoid unnecessary observables from executing?

I'm trying to use delay and amb to execute a sequence of the same task separated by time.
All I want is for a download attempt to execute some time in the future only if the same task failed before in the past. Here's how I have things set up, but unlike what I'd expect, all three downloads seem to execute without delay.
Observable.amb([
Observable.catch(redditPageStream, Observable.empty()).delay(0 * 1000),
Observable.catch(redditPageStream, Observable.empty()).delay(30 * 1000),
Observable.catch(redditPageStream, Observable.empty()).delay(90 * 1000),
# Observable.throw(new Error('Failed to retrieve reddit page content')).delay(10000)
# Observable.create(
# (observer) ->
# throw new Error('Failed to retrieve reddit page content')
# )
]).defaultIfEmpty(Observable.throw(new Error('Failed to retrieve reddit page content')))
full code can be found here. src
I was hoping that the first successful observable would cancel out the ones still in delay.
Thanks for any help.
delay doesn't actually stop the execution of what ever you are doing it just delays when the events are propagated. If you want to delay execution you would need to do something like:
redditPageStream.delaySubscription(1000)
Since your source is producing immediately the above will delay the actual subscription to the underlying stream to effectively delay when it begins producing.
I would suggest though that you use one of the retry operators to handle your retry logic though rather than rolling your own through the amb operator.
redditPageStream.delaySubscription(1000).retry(3);
will give you a constant retry delay however if you want to implement the linear backoff approach you can use the retryWhen() operator instead which will let you apply whatever logic you want to the backoff.
redditPageStream.retryWhen(errors => {
return errors
//Only take 3 errors
.take(3)
//Use timer to implement a linear back off and flatten it
.flatMap((e, i) => Rx.Observable.timer(i * 30 * 1000));
});
Essentially retryWhen will create an Observable of errors, each event that makes it through is treated as a retry attempt. If you error or complete the stream then it will stop retrying.