GWT Timer fires immediately, when running gwt-test-utils unit tests - unit-testing

I wrote an unit test using the gwt-test-utils framework, as described here.
The tested class internally uses a com.google.gwt.user.client.Timer (not the Java default Timer).
Only when tested, though, the Timer instance doesn't behave correctly, as it fires as soon as it is scheduled.
When I run this test
public class TimerTest extends GwtTest {
#Override
public String getModuleName() {
return "com.whatevs";
}
#Test
public void testTimer() {
final int[] counter = { 0 };
com.google.gwt.user.client.Timer t = new Timer() {
#Override
public void run() {
Log.info("firing timer");
counter[0]++; // just increase the counter
}
};
Log.info("scheduling timer");
t.schedule(1000000); // this should return immediately
Log.info("scheduling returns");
assertEquals(0, counter[0]); // the counter shouldn't yet be incremented
}
}
I get a failure
testTimer(com.whatevs.TimerTest): expected:<0> but was:<1>
And the debug output
22:37:44,075 INFO gwt-log:81 - scheduling timer
22:37:44,075 INFO gwt-log:81 - firing timer
22:37:44,075 INFO gwt-log:81 - scheduling returns
Please note that the test is run as a JUnit test, without being compiled to JavaScript first.
Am I doing something wrong, or did I just hit a bug?
Is there any other way to test such classes?
Update:
I just found out that if in the above example i call scheduleRepeating, or I reschedule the timer using schedule inside the run method, the timer fires exactly 5 times before returning control to the caller.
Something weird is going on, I just opened a bug report on gwt-test-utils.

Related

Missing capabilities for unit test

I've implemented a C++ Class that will execute something in a timed cycle using a thread. The thread is set to be scheduled with the SCHED_DEADLINE scheduler of the Linux kernel. To setup the Scheduler the process running this must have certain Linux capabilities.
My question is, how to test this?
I can of course make a unit test and create the threat, do some counting an exit the test after a time to validate the cycle counter but that only works if the unit test is allowed to apply the right scheduler. If not, the default scheduler applies and the timing of the cyclic loops will be immediate and therefore executes a different behaviour.
How would you test this scenario?
Some Code Example:
void thread_handler() {
// setup SCHED_DEADLINE Parameters
while (running) {
// execute application logic
sched_yield();
}
}
There two separate units to test here. First the cyclic execution of code and second the strategy with the os interface. The first unit would look like this:
class CyclicThread : public std::thread {
public:
CyclicThread(Strategy& strategy) :
std::thread(bind(&CyclicThread::worker, this)),
strategy(strategy) { }
add_task(std::function<void()> handler) {
...
}
private:
Strategy& strategy;
void worker() {
while (running) {
execute_handler()
strategy.yield();
}
}
}
This is fairly easy to test with a mock object of the strategy.
The Deadline scheduling strategy looks like this:
class DeadlineStrategy {
public:
void yield() {
sched_yield();
}
}
This class can also be tested fairly easy by mocking the sched_yield() system call.

Kotlin runTest with delay() is not working

I am testing a coroutine that blocks. Here is my production code:
interface Incrementer {
fun inc()
}
class MyViewModel : Incrementer, CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO
private val _number = MutableStateFlow(0)
fun getNumber(): StateFlow<Int> = _number.asStateFlow()
override fun inc() {
launch(coroutineContext) {
delay(100)
_number.tryEmit(1)
}
}
}
And my test:
class IncTest {
#BeforeEach
fun setup() {
Dispatchers.setMain(StandardTestDispatcher())
}
#AfterEach
fun teardown() {
Dispatchers.resetMain()
}
#Test
fun incrementOnce() = runTest {
val viewModel = MyViewModel()
val results = mutableListOf<Int>()
val resultJob = viewModel.getNumber()
.onEach(results::add)
.launchIn(CoroutineScope(UnconfinedTestDispatcher(testScheduler)))
launch(StandardTestDispatcher(testScheduler)) {
viewModel.inc()
}.join()
assertEquals(listOf(0, 1), results)
resultJob.cancel()
}
}
How would I go about testing my inc() function? (The interface is carved in stone, so I can't turn inc() into a suspend function.)
There are two problems here:
You want to wait for the work done in the coroutine that viewModel.inc() launches internally.
Ideally, the 100ms delay should be fast-forwarded during tests so that it doesn't actually take 100ms to execute.
Let's start with problem #2 first: for this, you need to be able to modify MyViewModel (but not inc), and change the class so that instead of using a hardcoded Dispatchers.IO, it receives a CoroutineContext as a parameter. With this, you could pass in a TestDispatcher in tests, which would use virtual time to fast-forward the delay. You can see this pattern described in the Injecting TestDispatchers section of the Android docs.
class MyViewModel(coroutineContext: CoroutineContext) : Incrementer {
private val scope = CoroutineScope(coroutineContext)
private val _number = MutableStateFlow(0)
fun getNumber(): StateFlow<Int> = _number.asStateFlow()
override fun inc() {
scope.launch {
delay(100)
_number.tryEmit(1)
}
}
}
Here, I've also done some minor cleanup:
Made MyViewModel contain a CoroutineScope instead of implementing the interface, which is an officially recommended practice
Removed the coroutineContext parameter passed to launch, as it doesn't do anything in this case - the same context is in the scope anyway, so it'll already be used
For problem #1, waiting for work to complete, you have a few options:
If you've passed in a TestDispatcher, you can manually advance the coroutine created inside inc using testing methods like advanceUntilIdle. This is not ideal, because you're relying on implementation details a lot, and it's something you couldn't do in production. But it'll work if you can't use the nicer solution below.
viewModel.inc()
advanceUntilIdle() // Returns when all pending coroutines are done
The proper solution would be for inc to let its callers know when it's done performing its work. You could make it a suspending method instead of launching a new coroutine internally, but you stated that you can't modify the method to make it suspending. An alternative - if you're able to make this change - would be to create the new coroutine in inc using the async builder, returning the Deferred object that that creates, and then await()-ing at the call site.
override fun inc(): Deferred<Unit> {
scope.async {
delay(100)
_number.tryEmit(1)
}
}
// In the test...
viewModel.inc().await()
If you're not able to modify either the method or the class, there's no way to avoid the delay() call causing a real 100ms delay. In this case, you can force your test to wait for that amount of time before proceeding. A regular delay() within runTest would be fast-forwarded thanks to it using a TestDispatcher for the coroutine it creates, but you can get away with one of these solutions:
// delay() on a different dispatcher
viewModel.inc()
withContext(Dispatchers.Default) { delay(100) }
// Use blocking sleep
viewModel.inc()
Thread.sleep(100)
For some final notes about the test code:
Since you're doing Dispatchers.setMain, you don't need to pass in testScheduler into the TestDispatchers you create. They'll grab the scheduler from Main automatically if they find a TestDispatcher there, as described in its docs.
Instead of creating a new scope to pass in to launchIn, you could simply pass in this, the receiver of runTest, which points to a TestScope.

Waiting for an external event before continue in unit test

Context:
I'm writing unit test for a gRPC service. I want to verify that the method of the mock on the server side is called. I'm using easy mock. To be sure we get the response of gRPC (whatever it is) I need to suspend the thread before easy mock verify the calls.
So I tried something like this using LockSupport:
#Test
public void alphaMethodTest() throws Exception
{
Dummy dummy = createNiceMock(Dummy.class);
dummy.alphaMethod(anyBoolean());
expectLastCall().once();
EasyMock.replay(dummy);
DummyServiceGrpcImpl dummyServiceGrpc = new DummyServiceGrpcImpl();
bcreuServiceGrpc.setDummy(dummy);
DummyServiceGrpc.DummyServiceStub stub = setupDummyServiceStub();
Thread thread = Thread.currentThread();
stub.alphaMethod(emptyRequest, new StreamObserver<X>(){
#Override
public void onNext(X value) {
LockSupport.unpark(thread);
}
}
Instant expirationTime = Instant.now().plus(pDuration);
LockSupport.parkUntil(expirationTime.toEpochMilli());
verify(dummy);
}
But I have many tests like this one (around 40) and I suspect threading issue. I usually get one or two failing the verify step, sometime all of them pass. I try to use a ReentrantLock with Condition instead. But again some are failing (IllegalMonitorStateException on the signalAll):
#Test
public void alphaMethodTest() throws Exception
{
Dummy dummy = createNiceMock(Dummy.class);
dummy.alphaMethod(anyBoolean());
expectLastCall().once();
EasyMock.replay(dummy);
DummyServiceGrpcImpl dummyServiceGrpc = new DummyServiceGrpcImpl();
bcreuServiceGrpc.setDummy(dummy);
DummyServiceGrpc.DummyServiceStub stub = setupDummyServiceStub();
ReentrantLock lock = new ReentrantLock();
Condition conditionPromiseTerminated = lock.newCondition();
stub.alphaMethod(emptyRequest, new StreamObserver<X>(){
#Override
public void onNext(X value) {
conditionPromiseTerminated.signalAll();
}
}
Instant expirationTime = Instant.now().plus(pDuration);
conditionPromiseTerminated.awaitUntil(new Date(expirationTime.toEpochMilli()));
verify(dummy);
}
I'm sorry not providing runnable example for you, my current code is using a private API :/.
Do you think LockSupport may cause trouble because of the multiple tests running? Am I missing something using lock support or reentrant lock. Do you think of any other class of the concurrent API that would suit better my needs?
LockSupport is a bit dangerous, you will need to read the documentation closely and find out that:
The call spuriously (that is, for no reason) returns.
So when you think your code will do some "waiting", it might simply return immediately. The simplest reason for that would be this for example, but there could be other reasons too.
When using ReentrantLock, all of them should fail with IllegalMonitorStateException, because you never acquire the lock via ReentrantLock::lock. And stop using new Date(...), it is deprecated for a reason.
I think you are over-complicating things, you could do the same signaling with a plain lock, a simplified example:
public static void main(String[] args) {
Object lock = new Object();
Thread first = new Thread(() -> {
synchronized (lock) {
System.out.println("Locked");
try {
System.out.println("Sleeping");
lock.wait();
System.out.println("Waked up");
} catch (InterruptedException e) {
// these are your tests, no one should interrupt
// unless it's yourself
throw new RuntimeException(e);
}
}
});
first.start();
sleepOneSecond();
Thread second = new Thread(() -> {
synchronized (lock) {
System.out.println("notifying waiting threads");
lock.notify();
}
});
second.start();
}
private static void sleepOneSecond() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Notice the output:
Locked
Sleeping
notifying waiting threads
Waked up
It should be obvious how the "communication" (signaling) between threads happens.

Subactor (worker) still works after Main actor Timeout in Java Akka

I have implemented an application in Akka framework using Java. I have a main actor which calls sub-actor by using 'Ask' method and timeout after 60 seconds, the worker calls another java class method once it receives the message from Main Actor.
Now the problem is though my Main actor timed-out after 60 seconds still the worker is able to talk to the java class method and in-turn the method is performing the operations which is not required as the main actor cannot receive the response though the sub-actor returns that due to the timeout.
Is there anyway I can kill the worker or stop it from further processing if my Main actor timeout?
I checked the methods like RecieveTimeOut(), context.stop() and poisonpill but still no use.
Appreciate your support
Code Below
public class MainActor extends UntypedActor {
ActorRef subActorRef;
final Timeout timeout = new Timeout(Duration.create(60, TimeUnit.SECONDS));
#Override
public void preStart() {
subActorRef = getContext().actorOf(
SpringExtProvider.get(actorSystem).props(
"SubActor"), "subActor");
}
#Override
public void onReceive(Object message) throws Exception {
if (message instanceof BusinessRequestVO) {
BusinessRequestVO requestVo = (BusinessRequestVO) message;
ArrayList<Future<Object>> responseFutures = new ArrayList<Future<Object>>();
// This part of code timeout after 60seconds
responseFutures.add(ask(subActorRef,requestVo, timeout));
}
}
}
SubActor class
public class SubActor extends UntypedActor {
#Resource
#Inject
ServiceAdapter serviceAdapter;
#Override
public void onReceive(Object message) throws Exception {
try{
if (message instanceof BusinessRequestVO) {
BusinessRequestVO requestVo = (BusinessRequestVO)message
// There is no time out here so it waits synchronously
// though Main actor timeouts
ServiceResponse response = serviceAdapter.getWorkOrder(requestVo);
getSender().tell(response, ActorRef.noSender());
} catch (Exception e) {
getSender().tell(new akka.actor.Status.Failure(e), getSelf());
throw e;
}
}
}
}
Adapter Class
public class ServiceAdapterImpl implements ServiceAdapter{
public ServiceResponse getWorkOrder(BusinessRequestVO request){
// Some code here along with webservice calls
}
}
You can't as your child actor is blocking, thus cannot process any "stop" messages that the parent sends him (actors process messages one at a time before reading the next one in the mailbox).
Your best bet is to wrap the "slow" part of the child's execution inside a future that you can pipeTo the parent (see here for details).
In this way, if your timeout expires, you can have the parent send a custom "stop computing" message, and the child actor can terminate the future. See here about how to terminate a future.
But this could introduce "dirty" states in your application logic according to the specific computation that gets terminated midway through execution.
On an related note: why are you sending all n requests to the same child actor (which you made blocking)? This is equivalent to sequential execution. You should either make the child actor non-blocking or (better) create a blocking actor for each request.
EDIT: as requested by OP, added snippet. It's a pseudo code mixing scala and java, as I'm not super expert with Java syntax for futures, I mainly use it in Scala, so please adapt it a little:
if (message instanceof BusinessRequestVO) {
new Future (
BusinessRequestVO requestVo = (BusinessRequestVO)message
try {
ServiceResponse response = serviceAdapter.getWorkOrder(requestVo);
getSender().tell(response, ActorRef.noSender());
}
catch (Exception e) {
getSender().tell(new akka.actor.Status.Failure(e), getSelf());
throw e;
}
) pipeTo sender
}
And in main (see here for java's future.cancel)
if (timeout) future.cancel(true)

GWT rpc callback does not call after calling in GWTTestCase

I have written a GWTTestCase like this:
public void testClickButton() {
SampleView view = new SampleView();
RootPanel.get().add(view);
view.textBox.setText("Saeed Zarinfam");
assertEquals("", view.label.getText());
// ButtonElement.as(view.button.getElement()).click();
view.button.getElement().<ButtonElement>cast().click();
assertEquals("Bean \"OCTO\" has been created", view.label.getText());
}
When i run this test it connect to my servlet (i added some log on my servlet) but the RPC callback does not call in my SampleView, junit say:
expected: <Bean "OCTO" has been created>, actual: <>
This is my callback in button click handler:
#UiHandler("button")
void onClick(ClickEvent e) {
labelTest.setText("click button");
AsyncCallback<FooBean> callback = new AsyncCallback<FooBean>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
labelTest.setText("call fail");
label.setText("Failure : " + caught.getMessage());
}
public void onSuccess(FooBean result) {
labelTest.setText("call success");
label.setText("Bean \"" + result.getName() + "\" has been created");
}
};
// Make the call. Control flow will continue immediately and later
// 'callback' will be invoked when the RPC completes.
service.createBean("OCTO", callback);
}
Why GWT rpc callback does not call in this case?
RPC calls are asynchronous even in GWTTestCase. You have to call delayTestFinish() to tell the runner that the test is asynchronous, and call finish() "at some point in the future" to tell it it's finished and OK (otherwise you'll have a timeout).
In your case, because the calling code has no way to know when the RPC call is finished, you can only do a wild guess at how many time it'll take, and use Timer.
Better refactor your code to make it more testable if you ask me (note: a Selenium would work roughly the same: check a condition every second until a timeout, http://seleniumhq.org/docs/02_selenium_ide.jsp#the-waitfor-commands-in-ajax-applications, just like a Timer that you'd re-schedule up to N times if the condition is not met)
See https://developers.google.com/web-toolkit/doc/latest/DevGuideTesting#DevGuideAsynchronousTesting