0

Based on guava-libraries example, I am using ListenableFuture.

I am using:
java 1.6
JDeveloper 11.1.1.6.0
guava-13.0.1.jar
junit-4.5.jar
easymock-3.1.jar
powermock-easymock-1.4.12-full.jar

I am trying to ensure that method under test is called in async mode.

My Manager.java code is:

    ...

    public synchronized void   refreshAsync(final String id) {
    m_Log.entry(id);

    ListeningExecutorService service =
        MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

    ListenableFuture<Details> getDetailsTask =
        service.submit(new Callable<Details>() {
            @Override
            public Details call() {
                System.out.println(Thread.currentThread().toString());
                return MyCacheManager.getDetails(id);
            }
        });

    Futures.addCallback(getDetailsTask ,
                        new FutureCallback<Details>() {
            // we want this handler to run immediately after we push the big red button!

            public void onSuccess(Details details) {
                System.out.println("Success");
                //TODO: publish event
            }

            public void onFailure(Throwable thrown) {
                System.out.println("Failed");
                //TODO: log
            }
        });

    service.shutdown();

    m_Log.exit("done async");
}

...

My test is:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest( { Manager.class,  MyCacheManager.class, TWResourceManager.class, Logger.class })
    public class DetailsTests {
    {

        ...

        @Test (timeout = 4000) 
        public void refreshAsync_RequestedInAsyncMode_NoWaitForComplete() throws Exception {

            // Creating nice mock - because we are not caring about methods call order
            mockStatic(MyCacheManager.class);

            // Setup
            final int operationTimeMilis = 5000;
            expect(MyCacheManager.getDetails(anyObject(String.class))).andStubAnswer(new IAnswer<Details>() {
                    public Details answer() {
                        try {
                            System.out.println("start waiting 5 sec");
                            System.out.println(Thread.currentThread().toString());
                            Thread.sleep(operationTimeMilis);
                            System.out.println("finished waiting 5 sec");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        return Details.getEmpty();
                    }
                });

            replay(MyCacheManager.class);

            replayAll();

            ISchemaActionsContract controller = new TWManager();
            controller.refreshSchemaDetailsAsync("schema_id");

            // We need not to verify mocks, since all we are testing is timeout
            // verifyAll();
        }
    }

When I am running / debugging the test - it is always failed on timeout. It seems that mocked method "MyCacheManager.getDetails" is called in "sync" mode.

But when I am calling same function from regular code / debug - it is running in async mode (I put Thread.sleep(10000) into MyCacheManager.getDetails method, and Manager.refreshAsync method is exited without waiting / be blocked.

Also, If I am changing the method to use regular FutureTask, test pass as expected.

        ...

        Object res = null;
        FutureTask task = new FutureTask(new Runnable() {
                @Override
                public void run() {
                    MyCacheManager.getDetails(id);
                }
            }, res);            

        m_Log.debug("async mode - send request and do not wait for answer.");

        Executors.newCachedThreadPool().submit(task);

Any idea will be more then welcome! :)
Thanks!

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
evgenyl
  • 7,837
  • 2
  • 27
  • 32
  • I'm not sure I follow why you'd want to sleep in test code. Tests should run quickly. – Louis Wasserman Nov 27 '12 at 16:33
  • 1
    do you never see your `"done async"` log message? – Brian Henry Nov 27 '12 at 17:32
  • @LouisWasserman: I want to be sure that operation is done in "async" mode - it means, that I do not want waiting for sleep finishing. I just want my method MyCacheManager.getDetails(...) will be called and my test will exit the refreshAsync() method. At this point, I'll know that sleep done in "parallel" thread and does not blocking my main test => test finished *before timeout*. But if test will failed on timeout - I know that thread is *sleeping in "sync" way*, and I'll be back from refreshAsync() only after it finished. – evgenyl Nov 28 '12 at 13:03
  • Also, in real test i'll decrease the timeout to be like 1 sec - it'll be enough to "sync" method to be done, and if test was not done - it does not matter how log sleep period was. – evgenyl Nov 28 '12 at 13:03
  • @BrianHenry: I do see this message, but after "finished waiting 5 sec". So I think that test is runs in "sync" mode. – evgenyl Nov 28 '12 at 13:04
  • Can you reduce this to a minimal test case? For example, does the bug occur only if you call both `replay` and `replayAll`? Does it occur only if you call `addCallback`? Does it occur only if the test calls `refreshSchemaDetailsAsync` but the mocked method is `refreshAsync`? Does it occur only if `refreshAsync` is `synchronized`? Does it occur only if you call `shutdown`? – Chris Povirk Dec 03 '12 at 18:28

0 Answers0