blob: 046f6c29f399a22c9e1e369d47e791f472231886 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2016 Wind River Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.tests.dsf.concurrent;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
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() {
@Override
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<>() {
@Override
protected void execute(DataRequestMonitor<Integer> rm) {
rm.setData(1);
rm.done();
}
};
// Check initial state
assertTrue(!q.isDone());
assertTrue(!q.isCancelled());
fExecutor.execute(q);
assertEquals(1, (int) q.get());
// Check final state
assertTrue(q.isDone());
assertTrue(!q.isCancelled());
}
@Test
public void getErrorTest() throws InterruptedException, ExecutionException {
final String error_message = "Test Error";
Query<Integer> q = new Query<>() {
@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
assertTrue(!q.isDone());
assertTrue(!q.isCancelled());
fExecutor.execute(q);
try {
q.get();
fail("Expected exception");
} catch (ExecutionException e) {
assertEquals(e.getCause().getMessage(), error_message);
}
// Check final state
assertTrue(q.isDone());
assertTrue(!q.isCancelled());
}
@Test
public void doneExceptionTest() throws InterruptedException, ExecutionException {
Query<Integer> q = new Query<>() {
@SuppressWarnings("deprecation")
@Override
protected void execute(DataRequestMonitor<Integer> rm) {
doneException(new Throwable());
}
};
// Check initial state
assertTrue(!q.isDone());
assertTrue(!q.isCancelled());
fExecutor.execute(q);
try {
q.get();
fail("Expected exception");
} catch (ExecutionException e) {
}
// Check final state
assertTrue(q.isDone());
assertTrue(!q.isCancelled());
}
@Test
public void getWithMultipleDispatchesTest() throws InterruptedException, ExecutionException {
Query<Integer> q = new Query<>() {
@Override
protected void execute(final DataRequestMonitor<Integer> rm) {
fExecutor.execute(new DsfRunnable() {
@Override
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);
assertEquals(1, (int) q.get());
}
@Test(expected = ExecutionException.class)
public void exceptionOnGetTest() throws InterruptedException, ExecutionException {
Query<Integer> q = new Query<>() {
@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 {
assertTrue(q.isDone());
assertTrue(!q.isCancelled());
}
}
@Test
public void cancelBeforeWaitingTest() throws InterruptedException, ExecutionException {
final Query<Integer> q = new Query<>() {
@Override
protected void execute(final DataRequestMonitor<Integer> rm) {
fail("Query was cancelled, it should not be called."); //$NON-NLS-1$
rm.done();
}
};
// Cancel before invoking the query.
q.cancel(false);
assertTrue(q.isDone());
assertTrue(q.isCancelled());
// Start the query.
fExecutor.execute(q);
// Block to retrieve data
try {
q.get();
} catch (CancellationException e) {
return; // Success
} finally {
assertTrue(q.isDone());
assertTrue(q.isCancelled());
}
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<>() {
@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() {
@Override
public void requestCanceled(RequestMonitor rm) {
cancelCalled[0] = Boolean.TRUE;
}
});
// Cancel running request.
q.cancel(false);
assertTrue(cancelCalled[0]);
assertTrue(rmHolder[0].isCanceled());
assertTrue(q.isCancelled());
assertTrue(q.isDone());
// Retrieve data
try {
q.get();
} catch (CancellationException e) {
return; // Success
} finally {
assertTrue(q.isDone());
assertTrue(q.isCancelled());
}
// Complete rm and query.
@SuppressWarnings("unchecked")
DataRequestMonitor<Integer> drm = (DataRequestMonitor<Integer>) rmHolder[0];
drm.setData(Integer.valueOf(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 {
assertTrue(q.isDone());
assertTrue(q.isCancelled());
}
assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$
}
@Test
public void getTimeoutTest() throws InterruptedException, ExecutionException {
final Query<Integer> q = new Query<>() {
@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() {
@Override
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 {
assertFalse("Query should not be done yet, it should have timed out first.", q.isDone()); //$NON-NLS-1$
}
assertTrue("TimeoutException should have been thrown", false); //$NON-NLS-1$
}
}