/* * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.errai.bus.client.api; import org.jboss.errai.common.client.api.tasks.AsyncTask; import org.jboss.errai.common.client.api.tasks.HasAsyncTaskRef; import com.google.gwt.junit.client.GWTTestCase; /** * Abstract test that covers the contract of the AsyncTask interface. Tests for client-side AsyncTask implementations * should extend {@link ClientAsyncTaskTest}; tests for server-side implementations should extend this class directly. * * @author Jonathan Fuerth <jfuerth@gmail.com> */ public abstract class AbstractAsyncTaskTest extends GWTTestCase { /** * A Runnable implementation whose instances keep track of how many times they have been run. Optionally wraps a task * that runs whenever {@link #run()} is called. Also implements {@link HasAsyncTaskRef} to make it easier to verify * injection of AsyncTask. */ public static class CountingRunnable implements Runnable, HasAsyncTaskRef { private volatile int runCount = 0; private final Runnable wrappedRunnable; private AsyncTask injectedAsyncTask; public CountingRunnable() { this(null); } public CountingRunnable(Runnable task) { this.wrappedRunnable = task; } @Override public void run() { try { if (wrappedRunnable != null) { wrappedRunnable.run(); } } finally { runCount++; } } /** * Returns the number of times the {@link #run()} method has been called on this CountingRunnable. */ public int getRunCount() { return runCount; } @Override public void setAsyncTask(AsyncTask task) { this.injectedAsyncTask = task; } @Override public AsyncTask getAsyncTask() { return injectedAsyncTask; } } /** * A Runnable implementation that throws RuntimeException every time it is run. */ public static final Runnable BLOW_UP = new Runnable() { @Override public void run() { throw new RuntimeException("This exception is intentionally thrown as part of a test."); }; }; /** * This version returns null, which forces GWTTestCase to run the tests in "pure java" (not client) mode. If you are * testing client-side code, extend {@link ClientAsyncTaskTest} instead of this class. */ @Override public String getModuleName() { return null; } /** * Returns the AsyncTask implementation that should be tested. * * @param task * the Runnable to pass to the execution system. <b>Note to subclassers: this runnable must be passed as-is, * without wrapping.</b> Tests such as {@link #testAsyncTaskRefInjection} depend on it. */ protected abstract AsyncTask getTaskUnderTest(CountingRunnable task); /** * Runs the given Runnable after the AsyncTask most recently returned from {@link #getTaskUnderTest(CountingRunnable)} * has completed. * * @param r */ protected abstract void runAfterTaskFinished(Runnable r); public void testCancellationFlag() throws Exception { final AsyncTask task = getTaskUnderTest(new CountingRunnable()); task.cancel(false); assertTrue(task.isCancelled()); } public void testCancellationFlagOnFailingTest() throws Exception { final AsyncTask task = getTaskUnderTest(new CountingRunnable(BLOW_UP)); runAfterTaskFinished(new Runnable() { @Override public void run() { assertTrue(task.isCancelled()); finishTest(); } }); delayTestFinish(5000); } public void testExitHandlerRunsImmediatelyOnCancelledTask() throws Exception { final AsyncTask task = getTaskUnderTest(new CountingRunnable()); task.cancel(false); final CountingRunnable cr = new CountingRunnable(); task.setExitHandler(cr); assertEquals(1, cr.getRunCount()); } public void testMultipleExitHandlersBeforeTaskFinished() throws Exception { final AsyncTask task = getTaskUnderTest(new CountingRunnable()); final CountingRunnable cr1 = new CountingRunnable(); task.setExitHandler(cr1); final CountingRunnable cr2 = new CountingRunnable(); try { task.setExitHandler(cr2); fail("Expected IllegalStateException"); } catch (final IllegalStateException e) { // expected } runAfterTaskFinished(new Runnable() { @Override public void run() { assertEquals(1, cr1.getRunCount()); assertEquals(0, cr2.getRunCount()); finishTest(); } }); delayTestFinish(5000); } public void testAddExitHandlerBeforeTaskFinished() throws Exception { final AsyncTask task = getTaskUnderTest(new CountingRunnable()); final CountingRunnable cr = new CountingRunnable(); task.setExitHandler(cr); runAfterTaskFinished(new Runnable() { @Override public void run() { assertEquals(1, cr.getRunCount()); finishTest(); } }); delayTestFinish(5000); } public void testAddExitHandlerForFailingTask() throws Exception { final AsyncTask task = getTaskUnderTest(new CountingRunnable(BLOW_UP)); final CountingRunnable cr = new CountingRunnable(); task.setExitHandler(cr); runAfterTaskFinished(new Runnable() { @Override public void run() { assertEquals(1, cr.getRunCount()); finishTest(); } }); delayTestFinish(5000); } public void testIsFinishedAfterTaskFinishes() throws Exception { final CountingRunnable countingRunnable = new CountingRunnable(); final AsyncTask task = getTaskUnderTest(countingRunnable); runAfterTaskFinished(new Runnable() { @Override public void run() { assertEquals(countingRunnable.runCount, 1); assertTrue(task.isFinished()); finishTest(); } }); delayTestFinish(5000); } public void testIsFinishedAfterTaskCancelled() throws Exception { final CountingRunnable countingRunnable = new CountingRunnable(); final AsyncTask task = getTaskUnderTest(countingRunnable); task.cancel(false); assertEquals(countingRunnable.runCount, 0); assertTrue(task.isFinished()); } public void testIsFinishedAfterTaskFailure() throws Exception { final AsyncTask task = getTaskUnderTest(new CountingRunnable(BLOW_UP)); runAfterTaskFinished(new Runnable() { @Override public void run() { assertTrue(task.isFinished()); finishTest(); } }); delayTestFinish(5000); } public void testAsyncTaskRefInjection() throws Exception { final CountingRunnable runnable = new CountingRunnable(); final AsyncTask task = getTaskUnderTest(runnable); assertNotNull("No AsyncTask was injected into runnable", runnable.getAsyncTask()); assertSame("Wrong AsyncTask injected into runnable", task, runnable.getAsyncTask()); } }