Using Java 8 and Netty 4.1.1.Final, I would've expected the following test case to succeed, but it times out. What is it that I don't understand w.r.t. nettys event loop and scheduling of tasks?
public class SchedulerTest {
CountDownLatch latch;
TimerHandler handler;
static class TimerHandler extends ChannelInboundHandlerAdapter {
ChannelHandlerContext ctx;
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
this.ctx = ctx;
}
private void timeout(final long ms) {
ctx.executor().schedule(() -> {
ctx.fireUserEventTriggered(ms);
}, ms, TimeUnit.MILLISECONDS);
}
}
static class TimeoutReactor extends ChannelInboundHandlerAdapter {
CountDownLatch latch;
public TimeoutReactor(CountDownLatch latch) {
super();
this.latch = latch;
}
#Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
System.out.println("userEventTriggered");
latch.countDown();
super.userEventTriggered(ctx, evt);
}
}
#Before
public void setUp() throws Exception {
latch = new CountDownLatch(2);
handler = new TimerHandler();
TimeoutReactor reactor = new TimeoutReactor(latch);
new EmbeddedChannel(handler, reactor);
}
#Test(timeout = 1000)
public void test() throws InterruptedException {
handler.timeout(30);
handler.timeout(20);
latch.await();
}
}
Its because EmbeddedChannel is no "real" Channel implementation and mainly use-able for testing and embedded ChannelHandlers. You will need to call "runPendingTasks()" after the given timeframe to have it run. If you use a "real" Channel implementation it will work without any extra method calls.
Related
Below is the class I want to test :
SomeClass.java
public void SomeClass {
final CountDownLatch latch = new CountDownLatch(1);
int result;
registerCallbackWithService(new MyCallback());
public int callToExternalService(){
//Do some stuff and make service call
latch.await();
return result;
}
class MyCallback implements ServiceCallback {
#Override
public void onResult(final int res) {
//do something
result = res;
latch.countdown();
}
}
}
The callback MyCallback was registered earlier before invoking callToExternalService().
If I write a simple test to just mock the service call made in callToExternalService(), the test keeps on running infinitely because of latch.await().
How can I test the logic in callToExternalService() as well as in onResult() ?
I modified by code to expose the callback that I am registering using a package-protected function as below :
public void SomeClass {
private final CountDownLatch latch = new CountDownLatch(1);
private int result;
registerCallback(new MyCallback());
public int callToExternalService(){
//Do some stuff and make service call
latch.await();
return result;
}
private class MyCallback implements ServiceCallback {
#Override
public void onResult(final int res) {
//do something
result = res;
latch.countdown();
}
}
protected registerCallback(ServiceCallback callback) {
registerCallbackWithService(callback);
}
}
Now, for testing I do my testing by creating a new class SomeClassTest extends SomeClass and do my testing using an instance of this class. In SomeClassTest all I do is override registerCallback() to access the callback instance that is being registered.
public class ServiceTest {
private ServiceCallback mServiceCallback;
class SomeClassTest extends SomeClass {
#Override
registerCallback(ServiceCallback callback) {
mServiceCallback = callback;
super.registerCallback(callback);
}
}
}
Now all I have to do it using doAnswer, invoke the callback upon service request which results in the execution of latch.countdown() on the same latch reference that is put on await just after making the service request.
SomeClassTest someClassInstance = new SomeClassTest();
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
mServiceVCallback.onResult(int_I_want_to_test_for)
return null;
}
}).when(someClassInstance).service_request_before_latch_await();
int response = someClassInstance.callToExternalService();
assertEquals(response, expected_response);
I am using the following code as scheduler in java web deployment
public class ReportScheduler implements ServletContextListener {
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent sce) {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new ReportLoader(sce.getServletContext()), 0, 10, TimeUnit.SECONDS);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
scheduler.shutdownNow();
}
The ReportLoader class which implements runnable is as follows:
public class ReportLoader implements Runnable {
ServletContext context;
public ReportLoader(ServletContext context) {
System.out.println("1");
this.context = context;
StartUp();
}
private void StartUp() {
System.out.println("start");
(new Thread(this)).start();
}
#Override
public void run() {
System.out.println("scheduled");
try {
//Files.delete(path);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
But my Scheduler does not seem to be working as nothing is getting printed on the tomcat (which is my server) log, as one would expect to.
Is there any mistake that i am making, or something more that i need to ensure so that the scheduler works properly ?
The intention of the scheduler is to delete folders at regular intervals on the local PC.
why use threadpool to run a Thread
your codeļ¼
private void StartUp() {
System.out.println("start");
(new Thread(this)).start();
}
What is the preferred mechanism for verifying the effects of a callback in Jmockit?
For example, assume I have this class.
class ResultGenerator {
AsyncLauncher asyncLauncher = new AsyncLauncher();
public void getResultAsync(final ResultSignal resultSignal) {
asyncLauncher.getResult(new FutureCallback<Result>() {
#Override
public void onSuccess(#Nullable Result result) {
resultSignal.success(result);
}
#Override
public void onFailure(Throwable t) {
resultSignal.failure();
}
});
}
}
How do I verify resultSignal.success(result) when writing a test for ResultGenerator#getResultAsync?
For example
#RunWith(JMockit.class)
public class ResultGeneratorTest {
// Synchronous invocation, mocked AsyncLauncher
#Test
public void testGetResultAsync(#Mocked final ResultSignal resultSignal, #Mocked final Result result) throws Exception {
new MockUp<AsyncLauncher>() {
#Mock
void getResult(FutureCallback<Result> futureCallback) {
futureCallback.onSuccess(result);
}
};
ResultGenerator resultGenerator = new ResultGenerator();
resultGenerator.getResultAsync(resultSignal);
new Verifications() {{
resultSignal.success((Result) any); times = 1;
resultSignal.failure(); times = 0;
}};
}
// Asynchronous invocation, real AsyncLauncher in use
#Test
public void testGetResultAsyncDelayed(#Mocked final Result result) throws Exception {
final AtomicBoolean latch = new AtomicBoolean(false);
MockUp<ResultSignal> resultSignalMockUp = new MockUp<ResultSignal>() {
#Mock(invocations = 1)
public void success(Result result) {
latch.set(true);
}
#Mock(invocations = 0)
public void failure() {
latch.set(true);
}
};
ResultGenerator resultGenerator = new ResultGenerator();
final ResultSignal resultSignal = resultSignalMockUp.getMockInstance();
resultGenerator.getResultAsync(resultSignal);
Awaitility.await().untilTrue(latch);
}
}
Couple of notes:
ResultGenerator is your SUT (System Under Test) and you should not mock internals
ResultSignal is a test collaborator, so it is natural to mock it out
because you can verify the functionality as such, the only "correct" solution from unit testing theory is to mock out the collaborator
You have to be sure that you handle timeout correctly, otherwise the test might never end
so one possible solution is:
#Test
public void getResultAsync_ShouldNotifyResultSignal() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
ResultGenerator generator = new ResultGenerator();
generator.getResultAsync(new MyResultSignal(latch));
assertTrue(latch.await(1, SECONDS));
}
private static final class MyResultSignal implements ResultSignal {
private final CountDownLatch latch;
private MyResultSignal(CountDownLatch latch) {
this.latch = latch;
}
#Override
public void success(Result result) {
latch.countDown();
}
#Override
public void failure() {}
}
I have following method for test:
public class classToTest{
#Autowired
private Alternator alternator;
public void methodToTest(){
Thread t = new Thread(new Runnable() {
public void run() {
while(true) {
if(alternator.get()) {
System.out.print("Hello");
alternator.set(false);
}
}
}
};
t.start()
}
}
I need to check that was invoked method
alternator.set(false);
How can I do it?
Instead of starting a thread directly, can you pass in an "Executor" instance?
For example...
public class ClassToTest{
#Autowired
private Alternator alternator;
#Autowired #Qualifier("myExecutor")
private java.util.concurrent.Executor executor;
public void methodToTest() {
Runnable runnable = new Runnable() {
public void run() {
while(true) {
if(alternator.get()) {
System.out.print("Hello");
alternator.set(false);
}
}
};
executor.execute(runnable);
}
}
Now you can test this easier...
public class ClassToTestTest {
...
#Before
public void setup() {
alternator = mock(Alternator.class);
executor = mock(Executor.class);
obj = new ClassToTest();
ReflectionTestUtils.setField(obj, "alternator", alternator);
ReflectionTestUtils.setField(obj, "executor", executor);
}
#Test
public void shouldStartRunnable() {
obj.methodToTest();
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
verify(executor).execute(runnableCaptor.capture());
Runnable runnable = runnableCaptor.getValue();
// Now test your actual "runnable"...
when(alternator.get()).thenReturn(true);
runnable.run();
verify(alternator).set(false);
}
}
(Have not tried to compile this, so I apologise if there are any mistakes!!)
Though Bret's post of passing in an executor is very much recommended, you can use the timeout() mock verification setting to test for asynchronous conditions.
verify(alternator, timeout(500)).set(false);
Note that this will necessarily increase the flakiness of your test (i.e. the likelihood that the test fails when the code passes). With a sensible timeout value, that flakiness should be negligible, but if you're making this a part of your core test infrastructure you may consider refactoring to allow for synchronous execution in the test.
I'm using ScheduledThreadPoolExecutor and I don't know hot to deal with something.
I'm scheduling some tasks this way:
scheduledExecService = new ExtendedScheduledExecutor(numThreads, myThreadFactory);
TareaActualizacion act = new TareaActualizacion(inst);
ScheduledFuture<?> handle = scheduledExecService.scheduleWithFixedDelay(act, retrasoInicial, segundosRefresco, TimeUnit.SECONDS);
act is a Runnable class that recive some data by parameter:
public class TareaActualizacion implements Runnable {
private Instalacion instalacion;
public TareaActualizacion(Instalacion instalacion) {
this.instalacion = instalacion;
}
#Override
public void run() {
//Do something
}
public Instalacion getInstalacion() {
return instalacion;
}
}
Now in the afterExecute method of the ExtendedSecheduledExecutor I want to get the object Instalacion of the task TareaActualizacion but I don't know how to do it.
My ExtendedScheduledExecutor class looks like this:
public class ExtendedScheduledExecutor extends ScheduledThreadPoolExecutor{
public ExtendedScheduledExecutor(int arg0) {
super(arg0);
}
public ExtendedScheduledExecutor(int arg0, ThreadFactory arg1) {
super(arg0, arg1);
}
#Override
protected void afterExecute(Runnable r, Throwable t)
{
super.afterExecute(r, t);
System.out.println("Executing afterExecute. Throwable is " + t);
if (t != null)
t.printStackTrace();
//I need to get the Instalacion attribute from TareaActualizacion task. How can I do it??
}
}
Any idea of how can I solve it??
Thank you!
Neus
As Stephan already pointed out in https://stackoverflow.com/a/22145530 , you should try to decouple the scheduling and execution from the notification.
One approach for this could be to wrap the actual task (TareaActualizacion) into another implementation of the Runnable interface that only executes the actual task, and afterwards notifies a callback about the task that has been executed.
Depending on your precise requirements, there may be several degrees of freedom for the implementation, but a general approach could roughly look like this:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledTaskNotification
{
public static void main(String[] args) throws Exception
{
ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
int n = 3;
for (int i = 0; i < n; i++)
{
UpdateTask updateTask = new UpdateTask(i);
RunnableCallback<UpdateTask> callback = new RunnableCallback<UpdateTask>()
{
#Override
public void runnableFinished(UpdateTask updateTask)
{
System.out.println("Finished "+updateTask+", id "+updateTask.getID());
}
};
Runnable runnableWithCallback =
createRunnableWithCallback(updateTask, callback);
executor.scheduleWithFixedDelay(
runnableWithCallback, 1000, 200+i*200,
TimeUnit.MILLISECONDS);
}
}
static interface RunnableCallback<T extends Runnable>
{
void runnableFinished(T runnable);
}
private static <T extends Runnable> Runnable createRunnableWithCallback(
final T runnable, final RunnableCallback<T> callback)
{
return new Runnable()
{
#Override
public void run()
{
runnable.run();
callback.runnableFinished(runnable);
}
};
}
private static class UpdateTask implements Runnable
{
private final int id;
UpdateTask(int id)
{
this.id = id;
}
#Override
public void run()
{
System.out.println("Run "+this);
}
int getID()
{
return id;
}
#Override
public String toString()
{
return "UpdateTask "+id;
}
}
}
This is a bay way. You should not trying to get the result out of the Executor, because it is only responsible for scheduling and executing tasks, not whats happening inside of them.
Your TareaActualizacion runnable should post the result to another piece of code, where you need it. This can be achieved using a queue or in the easiest case SwingUtilities.invokeLater().