/******************************************************************************* * Copyright (c) 2012 Wind River Systems, Inc. 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.tcf.debug.test; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; import org.eclipse.tcf.debug.test.services.IWaitForEventCache; import org.eclipse.tcf.debug.test.services.RunControlCM; import org.eclipse.tcf.debug.test.services.RunControlCM.ContextState; import org.eclipse.tcf.debug.test.util.AbstractCache; import org.eclipse.tcf.debug.test.util.ICache; import org.eclipse.tcf.debug.test.util.Transaction; import org.eclipse.tcf.services.IRunControl; import org.eclipse.tcf.services.IRunControl.RunControlContext; import org.junit.Assert; public class RunControlCMTest extends AbstractCMTest { public void testStateResetOnResumeSuspend() throws Exception { final TestProcessInfo processInfo = startProcess("tcf_test_func0"); createBreakpoint("test", "tcf_test_func0"); // Create and validate cache final ICache<ContextState> stateCache = new Transaction<ICache<ContextState>>() { public ICache<ContextState> process() throws InvalidCacheException, ExecutionException { ICache<ContextState> cache = fRunControlCM.getState(processInfo.fThreadId); validate(cache); Assert.assertTrue(cache.getData().suspended == true); return cache; }; }.get(); // Resume thread and wait for suspend new Transaction<Object>() { @Override protected Object process() throws InvalidCacheException, ExecutionException { IWaitForEventCache<Object> waitResume = fRunControlCM.waitForContextResumed(processInfo.fThreadId, this); IWaitForEventCache<Object> waitSuspend = fRunControlCM.waitForContextSuspended(processInfo.fThreadId, this); validate(fRunControlCM.resume(processInfo.fThreadCtx, this, IRunControl.RM_RESUME, 1)); validate(waitResume); if (!waitSuspend.isValid()) { // The state cache should either be invalid, or it should contain updated (running) state. Assert.assertTrue(stateCache.isValid() == false || stateCache.getData().suspended == false); validate(stateCache); Assert.assertTrue(stateCache.getData().suspended == false); } validate(waitSuspend); // The state cache should either be invalid again, or it should contain updated (suspended) state. Assert.assertTrue(stateCache.isValid() == false || stateCache.getData().suspended == true); validate(stateCache); Assert.assertTrue(stateCache.getData().suspended == true); return null; } }.get(); } public void testStateResetOnTerminate() throws Exception { final TestProcessInfo processInfo = startProcess("tcf_test_func0"); // Create and validate cache final ICache<ContextState> stateCache = new Transaction<ICache<ContextState>>() { public ICache<ContextState> process() throws InvalidCacheException, ExecutionException { ICache<ContextState> cache = fRunControlCM.getState(processInfo.fThreadId); validate(cache); Assert.assertTrue(cache.getData().suspended == true); return cache; }; }.get(); // Terminate process and check state new Transaction<Object>() { @Override protected Object process() throws InvalidCacheException, ExecutionException { IWaitForEventCache<String[]> wait = fRunControlCM.waitForContextRemoved(processInfo.fProcessId, this); validate(fRunControlCM.terminate(processInfo.fTestCtx, this)); validate(wait); // The state cache should either be invalid again, or it should contain updated (suspended) state. Assert.assertTrue(stateCache.isValid() == false || stateCache.getError() != null); if (!validateUnchecked(stateCache)) throw new InvalidCacheException(); Assert.assertTrue(stateCache.getError() != null); return null; } }.get(); } public void testRunControlCMChildrenInvalidation() throws Exception { final TestProcessInfo processInfo = startProcess("tcf_test_func0"); createBreakpoint("testRunControlCMChildrenInvalidation", "tcf_test_func0"); // Wait for each threads to start. final String[] threads = new Transaction<String[]>() { List<String> fThreads = new ArrayList<String>(); @Override protected String[] process() throws InvalidCacheException, ExecutionException { IWaitForEventCache<RunControlContext[]> waitCache = fRunControlCM.waitForContextAdded(processInfo.fProcessId, this); validate(fRunControlCM.resume(processInfo.fTestCtx, this, IRunControl.RM_RESUME, 1)); RunControlContext[] addedContexts = validate(waitCache); for (RunControlContext addedContext : addedContexts) { fThreads.add(addedContext.getID()); } if (fThreads.size() < 4) { waitCache.reset(); validate(waitCache); } // Validate children cache String[] children = validate (fRunControlCM.getChildren(processInfo.fProcessId)); Assert.assertTrue( "Expected children array to contain added ids", Arrays.asList(children).containsAll(fThreads)); return fThreads.toArray(new String[fThreads.size()]); } }.get(); // Wait for each thread to suspend, update caches for (final String thread : threads) { new Transaction<Object>() { @Override protected Object process() throws InvalidCacheException, ExecutionException { RunControlCM.ContextState state = validate(fRunControlCM.getState(thread)); if (!state.suspended) { validate( fRunControlCM.waitForContextSuspended(thread, this) ); } String symId = validate( fSymbolsCM.find(thread, new BigInteger(state.pc), "tcf_test_func0") ); Number symAddr = validate( fSymbolsCM.getContext(symId) ).getAddress(); Assert.assertEquals("Expected thread to suspend at breakpoint address", symAddr.toString(), state.pc); String[] children = validate( fRunControlCM.getChildren(thread)); Assert.assertEquals("Expected thread to have no children contexts", 0, children.length); return null; } }.get(); } // End test, check for removed events and that state caches were cleared new Transaction<String>() { @Override protected String process() throws InvalidCacheException, ExecutionException { // Create wait caches fRunControlCM.waitForContextRemoved(processInfo.fProcessId, this); IWaitForEventCache<?>[] waitCaches = new IWaitForEventCache<?>[threads.length]; for (int i = 0; i < threads.length; i++) { waitCaches[i] = fRunControlCM.waitForContextRemoved(threads[i], this); } validate( fDiagnosticsCM.cancelTest(processInfo.fTestId, this) ); validate(waitCaches); validate(fRunControlCM.waitForContextRemoved(processInfo.fProcessId, this)); try { validate( fRunControlCM.getContext(processInfo.fProcessId) ); Assert.fail("Expected error"); } catch (ExecutionException e) {} try { validate( fRunControlCM.getState(processInfo.fProcessId) ); Assert.fail("Expected error"); } catch (ExecutionException e) {} try { String children[] = validate( fRunControlCM.getChildren(processInfo.fProcessId) ); Assert.assertEquals("Expected no children", 0, children.length); } catch (ExecutionException e) {} for (String thread : threads) { try { validate( fRunControlCM.getContext(thread) ); Assert.fail("Expected error"); } catch (ExecutionException e) {} try { validate( fRunControlCM.getState(thread) ); Assert.fail("Expected error"); } catch (ExecutionException e) {} } return null; } }.get(); removeBreakpoint("testRunControlCMChildrenInvalidation"); } public void testChildrenResetOnAddedRemoved() throws Exception { final TestProcessInfo processInfo = startProcess("tcf_test_func0"); createBreakpoint("test", "tcf_test_func0"); // Create and validate cache final ICache<String[]> childrenCache = new Transaction<ICache<String[]>>() { public ICache<String[]> process() throws InvalidCacheException, ExecutionException { ICache<String[]> cache = fRunControlCM.getChildren(processInfo.fProcessId); validate(cache); Assert.assertTrue(cache.getData().length == 1); return cache; }; }.get(); // Wait for each threads to start. final String[] threads = new Transaction<String[]>() { List<String> fThreads = new ArrayList<String>(); @Override protected String[] process() throws InvalidCacheException, ExecutionException { IWaitForEventCache<RunControlContext[]> waitCache = fRunControlCM.waitForContextAdded(processInfo.fProcessId, this); validate(fRunControlCM.resume(processInfo.fTestCtx, this, IRunControl.RM_RESUME, 1)); RunControlContext[] addedContexts = validate(waitCache); for (RunControlContext addedContext : addedContexts) { fThreads.add(addedContext.getID()); } if (fThreads.size() < 4) { waitCache.reset(); validate(waitCache); } // Validate children cache String[] children = validate (childrenCache); Assert.assertTrue( "Expected children array to contain added ids", Arrays.asList(children).containsAll(fThreads)); return fThreads.toArray(new String[fThreads.size()]); } }.get(); // Wait for each thread to suspend, for (final String thread : threads) { new Transaction<Object>() { @Override protected Object process() throws InvalidCacheException, ExecutionException { RunControlCM.ContextState state = validate(fRunControlCM.getState(thread)); if (!state.suspended) { validate( fRunControlCM.waitForContextSuspended(thread, this) ); } String[] children = validate( fRunControlCM.getChildren(thread)); Assert.assertEquals("Expected thread to have no children contexts", 0, children.length); return null; } }.get(); } // End test, check for removed events and that state caches were cleared new Transaction<String>() { @Override protected String process() throws InvalidCacheException, ExecutionException { // Create wait caches fRunControlCM.waitForContextRemoved(processInfo.fProcessId, this); IWaitForEventCache<?>[] waitCaches = new IWaitForEventCache<?>[threads.length]; for (int i = 0; i < threads.length; i++) { waitCaches[i] = fRunControlCM.waitForContextRemoved(threads[i], this); } validate( fDiagnosticsCM.cancelTest(processInfo.fTestId, this) ); validate(waitCaches); validate(fRunControlCM.waitForContextRemoved(processInfo.fProcessId, this)); try { validate( fRunControlCM.getContext(processInfo.fProcessId) ); Assert.fail("Expected error"); } catch (ExecutionException e) {} try { validate( fRunControlCM.getState(processInfo.fProcessId) ); Assert.fail("Expected error"); } catch (ExecutionException e) {} try { String children[] = validate( fRunControlCM.getChildren(processInfo.fProcessId) ); Assert.assertEquals("Expected no children", 0, children.length); } catch (ExecutionException e) {} for (String thread : threads) { try { validate( fRunControlCM.getContext(thread) ); Assert.fail("Expected error"); } catch (ExecutionException e) {} try { validate( fRunControlCM.getState(thread) ); Assert.fail("Expected error"); } catch (ExecutionException e) {} } return null; } }.get(); } public void testMappingCommandCaches() throws Exception { final TestProcessInfo processInfo = startProcess("tcf_test_func0"); // Wait for each threads to start. new Transaction<Object>() { ICache<Object> fFirstCommandCache; @Override protected Object process() throws InvalidCacheException, ExecutionException { ICache<RunControlContext> contextCache = fRunControlCM.getContext(processInfo.fThreadId); validate(contextCache); ICache<Object> resumeCache = fRunControlCM.resume(contextCache.getData(), this, IRunControl.RM_RESUME, 1); if (fFirstCommandCache == null) { // Reset context objet cache to force a new context object to be created and retry. fFirstCommandCache = resumeCache; ((AbstractCache<?>)contextCache).reset(); validate(contextCache); } Assert.assertTrue(resumeCache == fFirstCommandCache); return null; } }.get(); } }