/******************************************************************************* * Copyright (c) 2006, 2009 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 junit.framework.Assert; import org.eclipse.cdt.dsf.concurrent.DsfRunnable; import org.eclipse.cdt.dsf.concurrent.ReflectionSequence; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.Sequence; import org.eclipse.cdt.tests.dsf.DsfTestPlugin; import org.eclipse.cdt.tests.dsf.TestDsfExecutor; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Tests that exercise the Sequence object. */ public class DsfSequenceTests { TestDsfExecutor fExecutor; @Before public void startExecutor() throws ExecutionException, InterruptedException { fExecutor = new TestDsfExecutor(); } @After public void shutdownExecutor() throws ExecutionException, InterruptedException { if (!fExecutor.isShutdown()) { // Some tests shut down the executor deliberatly) 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 simpleTest() throws InterruptedException, ExecutionException { // Create a counter for tracking number of steps performed. class IntegerHolder { int fInteger; } final IntegerHolder stepCounter = new IntegerHolder(); // Create the steps of the sequence final Sequence.Step[] steps = new Sequence.Step[] { new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { stepCounter.fInteger++; requestMonitor.done(); } }, new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { stepCounter.fInteger++; requestMonitor.done(); } } }; // Create, start, and wait for the sequence. Sequence sequence = new Sequence(fExecutor) { @Override public Step[] getSteps() { return steps; } }; Assert.assertFalse(sequence.isDone()); Assert.assertFalse(sequence.isCancelled()); fExecutor.execute(sequence); sequence.get(); // Check the count Assert.assertTrue(stepCounter.fInteger == 2); // Check post conditions Assert.assertTrue(sequence.isDone()); Assert.assertFalse(sequence.isCancelled()); } public class SimpleReflectionSequence extends ReflectionSequence { public int fStepCounter; public SimpleReflectionSequence() { super(fExecutor); } @Override protected String[] getExecutionOrder(String groupName) { return new String[] { "step1", "step2"}; } @Execute() public void step1(RequestMonitor rm) { fStepCounter++; rm.done(); } @Execute() public void step2(RequestMonitor rm) { fStepCounter++; rm.done(); } } @Test public void simpleReflectionTest() throws InterruptedException, ExecutionException { // Create, start, and wait for the sequence. SimpleReflectionSequence sequence = new SimpleReflectionSequence(); //Sequence sequence = new SimpleReflectionSequence(); Assert.assertFalse(sequence.isDone()); Assert.assertFalse(sequence.isCancelled()); fExecutor.execute(sequence); sequence.get(); // Check the count Assert.assertTrue(sequence.fStepCounter == 2); // Check post conditions Assert.assertTrue(sequence.isDone()); Assert.assertFalse(sequence.isCancelled()); } @Test (expected = ExecutionException.class) public void rollbackTest() throws InterruptedException, ExecutionException { // Create a counter for tracking number of steps performed and steps // rolled back. class IntegerHolder { int fInteger; } final IntegerHolder stepCounter = new IntegerHolder(); final IntegerHolder rollBackCounter = new IntegerHolder(); // Create the steps of the sequence final Sequence.Step[] steps = new Sequence.Step[] { new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { stepCounter.fInteger++; requestMonitor.done(); } @Override public void rollBack(RequestMonitor requestMonitor) { rollBackCounter.fInteger++; requestMonitor.done(); } }, new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { stepCounter.fInteger++; requestMonitor.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "", null)); //$NON-NLS-1$ requestMonitor.done(); } @Override public void rollBack(RequestMonitor requestMonitor) { rollBackCounter.fInteger++; requestMonitor.done(); } } }; // Create and start. Sequence sequence = new Sequence(fExecutor) { @Override public Step[] getSteps() { return steps; } }; fExecutor.execute(sequence); // Block and wait for sequence to complete. try { sequence.get(); } finally { // Both steps should be performed Assert.assertTrue(stepCounter.fInteger == 2); // Only one step is rolled back, the first one. Assert.assertTrue(rollBackCounter.fInteger == 1); // Check state from Future interface Assert.assertTrue(sequence.isDone()); Assert.assertFalse(sequence.isCancelled()); } Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$ } @Test (expected = ExecutionException.class) public void rejectedTest() throws InterruptedException, ExecutionException { // Create a counter for tracking number of steps performed and steps // rolled back. class IntegerHolder { int fInteger; } final IntegerHolder stepCounter = new IntegerHolder(); final IntegerHolder rollBackCounter = new IntegerHolder(); // Create the steps of the sequence final Sequence.Step[] steps = new Sequence.Step[] { new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { stepCounter.fInteger++; requestMonitor.done(); } @Override public void rollBack(RequestMonitor requestMonitor) { rollBackCounter.fInteger++; requestMonitor.done(); } }, new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { stepCounter.fInteger++; // Shutdown exectutor to force a RejectedExecutionException fExecutor.shutdown(); requestMonitor.done(); } @Override public void rollBack(RequestMonitor requestMonitor) { rollBackCounter.fInteger++; requestMonitor.done(); } } }; // Create and start. Sequence sequence = new Sequence(fExecutor) { @Override public Step[] getSteps() { return steps; } }; fExecutor.execute(sequence); // Block and wait for sequence to complete. try { sequence.get(); } finally { // Both steps should be performed Assert.assertTrue(stepCounter.fInteger == 2); // No steps should be rolled back. Assert.assertTrue(rollBackCounter.fInteger == 0); // Check state from Future interface Assert.assertTrue(sequence.isDone()); Assert.assertFalse(sequence.isCancelled()); } Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$ } public class RollBackReflectionSequence extends ReflectionSequence { public int fStepCounter; public int fRollBackCounter; public RollBackReflectionSequence() { super(fExecutor); } @Override protected String[] getExecutionOrder(String groupName) { return new String[] { "step1", "step2"}; } @Execute() public void step1(RequestMonitor rm) { fStepCounter++; rm.done(); } @RollBack("step1") public void rollBack1(RequestMonitor rm) { fRollBackCounter++; rm.done(); } @Execute() public void step2(RequestMonitor rm) { fStepCounter++; rm.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "", null)); //$NON-NLS-1$ rm.done(); } @RollBack("step2") public void rollBack2(RequestMonitor rm) { fRollBackCounter++; rm.done(); } } @Test (expected = ExecutionException.class) public void rollbackReflectionTest() throws InterruptedException, ExecutionException { // Create and start. RollBackReflectionSequence sequence = new RollBackReflectionSequence(); fExecutor.execute(sequence); // Block and wait for sequence to complete. try { sequence.get(); } finally { // Both steps should be performed Assert.assertEquals(2, sequence.fStepCounter); // Only one step is rolled back, the first one. Assert.assertEquals(1, sequence.fRollBackCounter); // Check state from Future interface Assert.assertTrue(sequence.isDone()); Assert.assertFalse(sequence.isCancelled()); } Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$ } public class RollBackReflectionSequence2 extends ReflectionSequence { public int fStepCounter; public int fRollBackCounter; public RollBackReflectionSequence2() { super(fExecutor); } @Override protected String[] getExecutionOrder(String groupName) { return new String[] { "step1", "step2", "step3" }; } @Execute() public void step1(RequestMonitor rm) { fStepCounter++; rm.done(); } @RollBack("step1") public void rollBack1(RequestMonitor rm) { fRollBackCounter++; rm.done(); } @Execute() public void step2(RequestMonitor rm) { fStepCounter++; rm.done(); } @Execute() public void step3(RequestMonitor rm) { fStepCounter++; rm.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "", null)); //$NON-NLS-1$ rm.done(); } } @Test (expected = ExecutionException.class) public void rollbackReflectionWithoutRollBackMethodTest() throws InterruptedException, ExecutionException { // Create and start. RollBackReflectionSequence2 sequence = new RollBackReflectionSequence2(); fExecutor.execute(sequence); // Block and wait for sequence to complete. try { sequence.get(); } finally { // All three steps should be performed Assert.assertEquals(3, sequence.fStepCounter); // Two steps are rolled back, but only the first one has // a rollback method. Assert.assertEquals(1, sequence.fRollBackCounter); // Check state from Future interface Assert.assertTrue(sequence.isDone()); Assert.assertFalse(sequence.isCancelled()); } Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$ } /** * The goal of this test it to check that if an exception is thrown within * the Step.execute(), the step will return from the Future.get() method. */ @Test (expected = ExecutionException.class) public void exceptionTest() throws InterruptedException, ExecutionException { final Sequence.Step[] steps = new Sequence.Step[] { new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { throw new Error("Exception part of unit test."); //$NON-NLS-1$ } } }; // Create and start. Sequence sequence = new Sequence(fExecutor) { @Override public Step[] getSteps() { return steps; } }; fExecutor.execute(sequence); // Block and wait for sequence to bomplete. try { sequence.get(); } finally { // Check state from Future interface Assert.assertTrue(sequence.isDone()); Assert.assertFalse(sequence.isCancelled()); } Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$ } @Test (expected = CancellationException.class) public void cancelBeforeWaitingTest() throws InterruptedException, ExecutionException { // Create the sequence final Sequence.Step[] steps = new Sequence.Step[] { new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { Assert.assertTrue("Sequence was cancelled, it should not be called.", false); //$NON-NLS-1$ } } }; Sequence sequence = new Sequence(fExecutor) { @Override public Step[] getSteps() { return steps; } }; // Cancel before invoking the sequence. sequence.cancel(false); Assert.assertFalse(sequence.isDone()); Assert.assertTrue(sequence.isCancelled()); // Start the sequence fExecutor.execute(sequence); // Block and wait for sequence to bomplete. try { sequence.get(); } finally { Assert.assertTrue(sequence.isDone()); Assert.assertTrue(sequence.isCancelled()); } Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$ } @Test (expected = CancellationException.class) public void cancelFromStepTest() throws InterruptedException, ExecutionException { // Create a counter for tracking number of steps performed and steps // rolled back. class IntegerHolder { int fInteger; } final IntegerHolder stepCounter = new IntegerHolder(); final IntegerHolder rollBackCounter = new IntegerHolder(); // Create the steps of the sequence final Sequence.Step[] steps = new Sequence.Step[] { new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { stepCounter.fInteger++; requestMonitor.done(); } @Override public void rollBack(RequestMonitor requestMonitor) { rollBackCounter.fInteger++; requestMonitor.done(); } }, new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { stepCounter.fInteger++; // Perform the cancel! getSequence().cancel(false); requestMonitor.done(); } @Override public void rollBack(RequestMonitor requestMonitor) { rollBackCounter.fInteger++; requestMonitor.done(); } } }; // Create and start sequence with a delay. Delay so that we call get() before // cancel is called. final Sequence sequence = new Sequence(fExecutor) { @Override public Step[] getSteps() { return steps; } }; fExecutor.schedule(sequence, 1, TimeUnit.MILLISECONDS); // Block to retrieve data try { sequence.get(); } finally { // Both steps should be performed Assert.assertTrue(stepCounter.fInteger == 2); // Both roll-backs should be performed since cancel does not take effect until // after the step is completed. Assert.assertTrue(rollBackCounter.fInteger == 2); Assert.assertTrue(sequence.isDone()); Assert.assertTrue(sequence.isCancelled()); } Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$ } @Test (expected = CancellationException.class) public void cancelBeforeWithProgressManagerTest() throws InterruptedException, ExecutionException { // Create the sequence final Sequence.Step[] steps = new Sequence.Step[] { new Sequence.Step() { @Override public void execute(RequestMonitor requestMonitor) { Assert.assertTrue("Sequence was cancelled, it should not be called.", false); //$NON-NLS-1$ } } }; // Create the progress monitor that we will cancel. IProgressMonitor pm = new NullProgressMonitor(); // Create the seqeunce with our steps. Sequence sequence = new Sequence(fExecutor, pm, "", "") { //$NON-NLS-1$ //$NON-NLS-2$ @Override public Step[] getSteps() { return steps; } }; // Cancel the progress monitor before invoking the sequence. Note // that the state of the sequence doesn't change yet, because the // sequence does not check the progress monitor until it is executed. pm.setCanceled(true); // Start the sequence fExecutor.execute(sequence); // Block and wait for sequence to bomplete. Exception is thrown, // which is expected. try { sequence.get(); } finally { Assert.assertTrue(sequence.isDone()); Assert.assertTrue(sequence.isCancelled()); } } }