/******************************************************************************* * Copyright (c) 2006, 2010 Wind River Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.tests.dsf.concurrent; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import junit.framework.Assert; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfRunnable; import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; import org.eclipse.cdt.dsf.concurrent.Query; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor.ICanceledListener; import org.eclipse.cdt.tests.dsf.DsfTestPlugin; import org.eclipse.cdt.tests.dsf.TestDsfExecutor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Tests that exercise the Query object. */ public class DsfQueryTests { TestDsfExecutor fExecutor; @Before public void startServices() throws ExecutionException, InterruptedException { fExecutor = new TestDsfExecutor(); } @After public void shutdownServices() throws ExecutionException, InterruptedException { fExecutor.submit(new DsfRunnable() { public void run() { fExecutor.shutdown(); }}).get(); if (fExecutor.exceptionsCaught()) { Throwable[] exceptions = fExecutor.getExceptions(); throw new ExecutionException(exceptions[0]); } fExecutor = null; } @Test public void simpleGetTest() throws InterruptedException, ExecutionException { Query<Integer> q = new Query<Integer>() { @Override protected void execute(DataRequestMonitor<Integer> rm) { rm.setData(1); rm.done(); } }; // Check initial state Assert.assertTrue(!q.isDone()); Assert.assertTrue(!q.isCancelled()); fExecutor.execute(q); Assert.assertEquals(1, (int)q.get()); // Check final state Assert.assertTrue(q.isDone()); Assert.assertTrue(!q.isCancelled()); } @Test public void getErrorTest() throws InterruptedException, ExecutionException { final String error_message = "Test Error"; Query<Integer> q = new Query<Integer>() { @Override protected void execute(DataRequestMonitor<Integer> rm) { rm.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, error_message, null)); //$NON-NLS-1$ rm.done(); } }; // Check initial state Assert.assertTrue(!q.isDone()); Assert.assertTrue(!q.isCancelled()); fExecutor.execute(q); try { q.get(); Assert.fail("Expected exception"); } catch (ExecutionException e) { Assert.assertEquals(e.getCause().getMessage(), error_message); } // Check final state Assert.assertTrue(q.isDone()); Assert.assertTrue(!q.isCancelled()); } @Test public void doneExceptionTest() throws InterruptedException, ExecutionException { Query<Integer> q = new Query<Integer>() { @SuppressWarnings("deprecation") @Override protected void execute(DataRequestMonitor<Integer> rm) { doneException(new Throwable()); } }; // Check initial state Assert.assertTrue(!q.isDone()); Assert.assertTrue(!q.isCancelled()); fExecutor.execute(q); try { q.get(); Assert.fail("Expected exception"); } catch (ExecutionException e) { } // Check final state Assert.assertTrue(q.isDone()); Assert.assertTrue(!q.isCancelled()); } @Test public void getWithMultipleDispatchesTest() throws InterruptedException, ExecutionException { Query<Integer> q = new Query<Integer>() { @Override protected void execute(final DataRequestMonitor<Integer> rm) { fExecutor.execute(new DsfRunnable() { public void run() { rm.setData(1); rm.done(); } @Override public String toString() { return super.toString() + "\n getWithMultipleDispatchesTest() second runnable"; } //$NON-NLS-1$ }); } @Override public String toString() { return super.toString() + "\n getWithMultipleDispatchesTest() first runnable (query)"; } //$NON-NLS-1$ }; fExecutor.execute(q); Assert.assertEquals(1, (int)q.get()); } @Test (expected = ExecutionException.class) public void exceptionOnGetTest() throws InterruptedException, ExecutionException { Query<Integer> q = new Query<Integer>() { @Override protected void execute(final DataRequestMonitor<Integer> rm) { rm.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "", null)); //$NON-NLS-1$ rm.done(); } }; fExecutor.execute(q); try { q.get(); } finally { Assert.assertTrue(q.isDone()); Assert.assertTrue(!q.isCancelled()); } } @Test public void cancelBeforeWaitingTest() throws InterruptedException, ExecutionException { final Query<Integer> q = new Query<Integer>() { @Override protected void execute(final DataRequestMonitor<Integer> rm) { Assert.fail("Query was cancelled, it should not be called."); //$NON-NLS-1$ rm.done(); } }; // Cancel before invoking the query. q.cancel(false); Assert.assertTrue(q.isDone()); Assert.assertTrue(q.isCancelled()); // Start the query. fExecutor.execute(q); // Block to retrieve data try { q.get(); } catch (CancellationException e) { return; // Success } finally { Assert.assertTrue(q.isDone()); Assert.assertTrue(q.isCancelled()); } Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$ } @Test public void cancelWhileWaitingTest() throws InterruptedException, ExecutionException { final DataRequestMonitor<?>[] rmHolder = new DataRequestMonitor<?>[1]; final Boolean[] cancelCalled = new Boolean[] { Boolean.FALSE }; final Query<Integer> q = new Query<Integer>() { @Override protected void execute(final DataRequestMonitor<Integer> rm) { synchronized (rmHolder) { rmHolder[0] = rm; rmHolder.notifyAll(); } } }; // Start the query. fExecutor.execute(q); // Wait until the query is started synchronized (rmHolder) { while(rmHolder[0] == null) { rmHolder.wait(); } } // Add a cancel listener to the query RM rmHolder[0].addCancelListener(new ICanceledListener() { public void requestCanceled(RequestMonitor rm) { cancelCalled[0] = Boolean.TRUE; } }); // Cancel running request. q.cancel(false); Assert.assertTrue(cancelCalled[0]); Assert.assertTrue(rmHolder[0].isCanceled()); Assert.assertTrue(q.isCancelled()); Assert.assertTrue(q.isDone()); // Retrieve data try { q.get(); } catch (CancellationException e) { return; // Success } finally { Assert.assertTrue(q.isDone()); Assert.assertTrue(q.isCancelled()); } // Complete rm and query. @SuppressWarnings("unchecked") DataRequestMonitor<Integer> drm = (DataRequestMonitor<Integer>)rmHolder[0]; drm.setData(new Integer(1)); rmHolder[0].done(); // Try to retrieve data again, it should still result in // cancellation exception. try { q.get(); } catch (CancellationException e) { return; // Success } finally { Assert.assertTrue(q.isDone()); Assert.assertTrue(q.isCancelled()); } Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$ } @Test public void getTimeoutTest() throws InterruptedException, ExecutionException { final Query<Integer> q = new Query<Integer>() { @Override protected void execute(final DataRequestMonitor<Integer> rm) { // Call done with a delay of 1 second, to avoid stalling the tests. fExecutor.schedule( new DsfRunnable() { public void run() { rm.done(); } }, 60, TimeUnit.SECONDS); } }; fExecutor.execute(q); // Note: no point in checking isDone() and isCancelled() here, because // the value could change on timing. try { q.get(1, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { return; // Success } finally { Assert.assertFalse("Query should not be done yet, it should have timed out first.", q.isDone()); //$NON-NLS-1$ } Assert.assertTrue("TimeoutException should have been thrown", false); //$NON-NLS-1$ } }