diff options
author | Pawel Piech | 2012-06-15 18:08:54 +0000 |
---|---|---|
committer | Pawel Piech | 2012-07-20 22:26:47 +0000 |
commit | ffcf8a21524290de167d2f0fc05f9b3c33a58c33 (patch) | |
tree | 3031245132ae570ff0a74dc443e7d6879fc47b32 /tests | |
parent | bfef150a18afc709a28ea58cbcb2c8a4ab8a134a (diff) | |
download | org.eclipse.tcf-ffcf8a21524290de167d2f0fc05f9b3c33a58c33.tar.gz org.eclipse.tcf-ffcf8a21524290de167d2f0fc05f9b3c33a58c33.tar.xz org.eclipse.tcf-ffcf8a21524290de167d2f0fc05f9b3c33a58c33.zip |
Bug 380607 - [tests] Intermittent failure in SampleTest.testSteppingDebugViewOnly
Diffstat (limited to 'tests')
9 files changed, 1120 insertions, 193 deletions
diff --git a/tests/plugins/org.eclipse.tcf.debug.test/data/agent/linux/x86/agent b/tests/plugins/org.eclipse.tcf.debug.test/data/agent/linux/x86/agent Binary files differindex 9bc590e22..9bc590e22 100644..100755 --- a/tests/plugins/org.eclipse.tcf.debug.test/data/agent/linux/x86/agent +++ b/tests/plugins/org.eclipse.tcf.debug.test/data/agent/linux/x86/agent diff --git a/tests/plugins/org.eclipse.tcf.debug.test/pom.xml b/tests/plugins/org.eclipse.tcf.debug.test/pom.xml index d50d9fde9..2ca083adb 100644 --- a/tests/plugins/org.eclipse.tcf.debug.test/pom.xml +++ b/tests/plugins/org.eclipse.tcf.debug.test/pom.xml @@ -33,10 +33,15 @@ <configuration> <includes> <include>**/BreakpointsTest.*</include> + <include>**/TransactionTests.*</include> + <include>**/BreakpointDetailPaneTest.*</include> + <include>**/BreakpointsViewTest.*</include> + <include>**/RunControlCMTest.*</include> + <include>**/StackTraceCMTest.*</include> <include>**/SampleTest.*</include> <include>**/CacheTests.*</include> <include>**/QueryTests.*</include> - <include>**/TransactionTests.*</include> + <include>**/RangeCacheTests.*</include> </includes> <!-- <debugPort>8003</debugPort> diff --git a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/AbstractCMTest.java b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/AbstractCMTest.java new file mode 100644 index 000000000..811d7bff6 --- /dev/null +++ b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/AbstractCMTest.java @@ -0,0 +1,689 @@ +/******************************************************************************* + * 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.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.ILaunchesListener2; +import org.eclipse.debug.core.model.IBreakpoint; +import org.eclipse.debug.core.model.IDisconnect; +import org.eclipse.debug.internal.ui.IInternalDebugUIConstants; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.jface.dialogs.MessageDialogWithToggle; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.tcf.debug.test.services.BreakpointsCM; +import org.eclipse.tcf.debug.test.services.DiagnosticsCM; +import org.eclipse.tcf.debug.test.services.LineNumbersCM; +import org.eclipse.tcf.debug.test.services.ProcessesCM; +import org.eclipse.tcf.debug.test.services.RegistersCM; +import org.eclipse.tcf.debug.test.services.RunControlCM; +import org.eclipse.tcf.debug.test.services.RunControlCM.ContextState; +import org.eclipse.tcf.debug.test.services.StackTraceCM; +import org.eclipse.tcf.debug.test.services.SymbolsCM; +import org.eclipse.tcf.debug.test.util.AggregateCallback; +import org.eclipse.tcf.debug.test.util.Callback; +import org.eclipse.tcf.debug.test.util.Callback.ICanceledListener; +import org.eclipse.tcf.debug.test.util.DataCallback; +import org.eclipse.tcf.debug.test.util.ICache; +import org.eclipse.tcf.debug.test.util.Query; +import org.eclipse.tcf.debug.test.util.Task; +import org.eclipse.tcf.debug.test.util.Transaction; +import org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate; +import org.eclipse.tcf.protocol.IChannel; +import org.eclipse.tcf.protocol.IPeer; +import org.eclipse.tcf.protocol.JSON; +import org.eclipse.tcf.protocol.Protocol; +import org.eclipse.tcf.services.IBreakpoints; +import org.eclipse.tcf.services.IDiagnostics; +import org.eclipse.tcf.services.IDiagnostics.ISymbol; +import org.eclipse.tcf.services.IExpressions; +import org.eclipse.tcf.services.ILineNumbers; +import org.eclipse.tcf.services.IMemoryMap; +import org.eclipse.tcf.services.IProcesses; +import org.eclipse.tcf.services.IRegisters; +import org.eclipse.tcf.services.IRegisters.RegistersContext; +import org.eclipse.tcf.services.IRunControl; +import org.eclipse.tcf.services.IRunControl.RunControlContext; +import org.eclipse.tcf.services.IStackTrace; +import org.eclipse.tcf.services.ISymbols; +import org.eclipse.tcf.te.tests.interfaces.IConfigurationProperties; +import org.eclipse.tcf.te.tests.tcf.TcfTestCase; +import org.junit.Assert; +import org.osgi.framework.Bundle; + +/** + * Base test for validating TCF Debugger UI. + */ +@SuppressWarnings("restriction") +public abstract class AbstractCMTest extends TcfTestCase implements IViewerUpdatesListenerConstants { + + private final static int NUM_CHANNELS = 1; + + protected IChannel[] channels; + + private Query<Object> fMonitorChannelQuery; + private List<Throwable> errors = new ArrayList<Throwable>(); + protected ILaunch fLaunch; + + protected Object fTestRunKey; + + protected IDiagnostics diag; + protected IExpressions expr; + protected ISymbols syms; + protected IStackTrace stk; + protected IRunControl rc; + protected IBreakpoints bp; + protected IMemoryMap fMemoryMap; + protected ILineNumbers fLineNumbers; + protected IRegisters fRegisters; + protected IProcesses fProcesses; + + protected RunControlCM fRunControlCM; + protected DiagnosticsCM fDiagnosticsCM; + protected BreakpointsCM fBreakpointsCM; + protected StackTraceCM fStackTraceCM; + protected SymbolsCM fSymbolsCM; + protected LineNumbersCM fLineNumbersCM; + protected RegistersCM fRegistersCM; + protected ProcessesCM fProcessesCM; + + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.tests.CoreTestCase#getTestBundle() + */ + @Override + protected Bundle getTestBundle() { + return Activator.getDefault().getBundle(); + } + + /* (non-Javadoc) + * @see org.eclipse.tcf.te.tests.CoreTestCase#initialize() + */ + @Override + protected void initialize() { + // Turn off the automatic perspective switch and debug view activation to avoid + // JFace views from interfering with the virtual viewers used in tests. + IPreferenceStore prefs = DebugUITools.getPreferenceStore(); + prefs.setValue(IInternalDebugUIConstants.PREF_ACTIVATE_DEBUG_VIEW, false); + prefs.setValue(IInternalDebugUIConstants.PREF_SWITCH_PERSPECTIVE_ON_SUSPEND, MessageDialogWithToggle.NEVER); + + super.initialize(); + // Do not activate debug view or debug perspective, also to avoid interfering + // with tests' virtual viewers. + setProperty(IConfigurationProperties.TARGET_PERSPECTIVE, "org.eclipse.cdt.ui.CPerspective"); //$NON-NLS-1$ + setProperty(IConfigurationProperties.TARGET_VIEW, "org.eclipse.cdt.ui.CView"); //$NON-NLS-1$ + } + + @Override + protected void setUp() throws Exception { + fTestRunKey = new Object(); + + // Launch the agent + super.setUp(); + createLaunch(); + + channels = new IChannel[NUM_CHANNELS]; + + new Query<Object>() { + @Override + protected void execute(DataCallback<Object> callback) { + try { + openChannels(peer, callback); + } + catch (Throwable x) { + errors.add(x); + int cnt = 0; + for (int i = 0; i < channels.length; i++) { + if (channels[i] == null) continue; + if (channels[i].getState() != IChannel.STATE_CLOSED) channels[i].close(); + cnt++; + } + if (cnt == 0) { + callback.setError(errors.get(0)); + callback.done(); + } + } + } + }.get(); + + getRemoteServices(); + + new Task<Object>() { + @Override + public Object call() throws Exception { + setUpServiceListeners(); + return null; + } + }.get(); + + validateTestAvailable(); + clearBreakpoints(); + } + + @Override + protected void tearDown() throws Exception { + new Task<Object>() { + @Override + public Object call() throws Exception { + tearDownServiceListeners(); + return null; + } + }.get(); + + terminateLaunch(); + + new Query<Object>() { + @Override + protected void execute(DataCallback<Object> callback) { + closeChannels(callback); + } + }.get(); + + super.tearDown(); + } + + protected String getDiagnosticsTestName() { + return "RCBP1"; + } + + protected void setUpServiceListeners() throws Exception{ + fRunControlCM = new RunControlCM(rc); + fDiagnosticsCM = new DiagnosticsCM(diag); + fBreakpointsCM = new BreakpointsCM(bp); + fStackTraceCM = new StackTraceCM(stk, rc); + fSymbolsCM = new SymbolsCM(syms, fRunControlCM, fMemoryMap); + fLineNumbersCM = new LineNumbersCM(fLineNumbers, fMemoryMap, fRunControlCM); + fRegistersCM = new RegistersCM(fRegisters, rc); + fProcessesCM = new ProcessesCM(fProcesses); + } + + protected void tearDownServiceListeners() throws Exception{ + fProcessesCM.dispose(); + fRegistersCM.dispose(); + fSymbolsCM.dispose(); + fBreakpointsCM.dispose(); + fStackTraceCM.dispose(); + fRunControlCM.dispose(); + fDiagnosticsCM.dispose(); + fLineNumbersCM.dispose(); + } + + + private void createLaunch() throws Exception { + ILaunchManager lManager = DebugPlugin.getDefault().getLaunchManager(); + ILaunchConfigurationType lcType = lManager.getLaunchConfigurationType("org.eclipse.tcf.debug.LaunchConfigurationType"); + ILaunchConfigurationWorkingCopy lcWc = lcType.newInstance(null, "test"); + lcWc.setAttribute(TCFLaunchDelegate.ATTR_USE_LOCAL_AGENT, false); + lcWc.setAttribute(TCFLaunchDelegate.ATTR_RUN_LOCAL_AGENT, false); + lcWc.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, peer.getID()); + lcWc.doSave(); + fLaunch = lcWc.launch("debug", new NullProgressMonitor()); + Assert.assertTrue( fLaunch instanceof IDisconnect ); + } + + private void terminateLaunch() throws DebugException, InterruptedException, ExecutionException { + ((IDisconnect)fLaunch).disconnect(); + + new Query<Object>() { + @Override + protected void execute(final DataCallback<Object> callback) { + final ILaunchManager lm = DebugPlugin.getDefault().getLaunchManager(); + + final AtomicBoolean callbackDone = new AtomicBoolean(false); + ILaunchesListener2 disconnectListener = new ILaunchesListener2() { + public void launchesAdded(ILaunch[] launches) {} + public void launchesChanged(ILaunch[] launches) {} + public void launchesRemoved(ILaunch[] launches) {} + public void launchesTerminated(ILaunch[] launches) { + if (Arrays.asList(launches).contains(fLaunch)) { + if (!callbackDone.getAndSet(true)) { + lm.removeLaunchListener(this); + callback.done(); + } + } + } + }; + lm.addLaunchListener(disconnectListener); + if (((IDisconnect)fLaunch).isDisconnected() && !callbackDone.getAndSet(true)) { + lm.removeLaunchListener(disconnectListener); + callback.done(); + + } + } + }.get(); + } + + private void getRemoteServices() { + assert !Protocol.isDispatchThread(); + Protocol.invokeAndWait(new Runnable() { + public void run() { + diag = channels[0].getRemoteService(IDiagnostics.class); + expr = channels[0].getRemoteService(IExpressions.class); + syms = channels[0].getRemoteService(ISymbols.class); + stk = channels[0].getRemoteService(IStackTrace.class); + rc = channels[0].getRemoteService(IRunControl.class); + bp = channels[0].getRemoteService(IBreakpoints.class); + fMemoryMap = channels[0].getRemoteService(IMemoryMap.class); + fLineNumbers = channels[0].getRemoteService(ILineNumbers.class); + fRegisters = channels[0].getRemoteService(IRegisters.class); + fProcesses = channels[0].getRemoteService(IProcesses.class); + }; + }); + } + + private void openChannels(IPeer peer, Callback callback) { + assert Protocol.isDispatchThread(); + + for (int i = 0; i < channels.length; i++) { + channels[i] = peer.openChannel(); + } + monitorChannels( + new Callback(callback) { + @Override + protected void handleSuccess() { + fMonitorChannelQuery = new Query<Object>() { + @Override + protected void execute(org.eclipse.tcf.debug.test.util.DataCallback<Object> callback) { + monitorChannels(callback, true); + }; + }; + fMonitorChannelQuery.invoke(); + super.handleSuccess(); + } + }, + false); + } + + private void closeChannels(final Callback callback) { + assert Protocol.isDispatchThread(); + fMonitorChannelQuery.cancel(false); + try { + fMonitorChannelQuery.get(); + } catch (ExecutionException e) { + callback.setError(e.getCause()); + } catch (CancellationException e) { + // expected + } catch (InterruptedException e) { + } + + for (int i = 0; i < channels.length; i++) { + if (channels[i].getState() != IChannel.STATE_CLOSED) channels[i].close(); + } + monitorChannels(callback, true); + } + + private static class ChannelMonitorListener implements IChannel.IChannelListener { + + final IChannel fChannel; + final boolean fClose; + final Callback fCallback; + private boolean fActive = true; + + private class CancelListener implements ICanceledListener { + public void requestCanceled(Callback rm) { + Protocol.invokeLater(new Runnable() { + public void run() { + if (deactivate()) { + fCallback.done(); + } + } + }); + } + } + + private boolean deactivate() { + if (fActive) { + fChannel.removeChannelListener(ChannelMonitorListener.this); + fActive = false; + return true; + } + return false; + } + + ChannelMonitorListener (IChannel channel, Callback cb, boolean close) { + fCallback = cb; + fClose = close; + fChannel = channel; + fChannel.addChannelListener(this); + fCallback.addCancelListener(new CancelListener()); + } + + public void onChannelOpened() { + if (!deactivate()) return; + + fChannel.removeChannelListener(this); + fCallback.done(); + } + + public void congestionLevel(int level) { + } + + public void onChannelClosed(Throwable error) { + if (!deactivate()) return; + + if (!fClose) { + fCallback.setError( new IOException("Remote peer closed connection before all tests finished") ); + } else { + fCallback.setError(error); + } + fCallback.done(); + } + } + + protected void monitorChannels(final Callback callback, final boolean close) { + assert Protocol.isDispatchThread(); + + AggregateCallback acb = new AggregateCallback(callback); + int count = 0; + for (int i = 0; i < channels.length; i++) { + if (!checkChannelsState(channels[i], close)) { + new ChannelMonitorListener(channels[i], new Callback(acb), close); + count++; + } + } + acb.setDoneCount(count); + } + + // Checks whether all channels have achieved the desired state. + private boolean checkChannelsState(IChannel channel, boolean close) { + if (close) { + if (channel.getState() != IChannel.STATE_CLOSED) { + return false; + } + } else { + if (channel.getState() != IChannel.STATE_OPEN) { + return false; + } + } + return true; + } + + private void validateTestAvailable() throws ExecutionException, InterruptedException { + String[] testList = new Transaction<String[]>() { + @Override + protected String[] process() throws InvalidCacheException ,ExecutionException { + return validate( fDiagnosticsCM.getTestList() ); + } + }.get(); + + int i = 0; + for (; i < testList.length; i++) { + if ("RCBP1".equals(testList[i])) break; + } + + Assert.assertTrue("Required test not supported", i != testList.length); + } + + protected void clearBreakpoints() throws InterruptedException, ExecutionException, CoreException { + + // Delete eclipse breakpoints. + IWorkspaceRunnable wr = new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + IBreakpointManager mgr = DebugPlugin.getDefault().getBreakpointManager(); + IBreakpoint[] bps = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(); + mgr.removeBreakpoints(bps, true); + } + }; + ResourcesPlugin.getWorkspace().run(wr, null, 0, null); + + // Delete TCF breakpoints + new Transaction<Object>() { + @Override + protected Object process() throws InvalidCacheException, ExecutionException { + // Initialize the event cache for breakpoint status + @SuppressWarnings("unchecked") + Map<String, Object>[] bps = new Map[] { }; + validate( fBreakpointsCM.set(bps, this) ); + return null; + } + }.get(); + } + + private TestProcessInfo startProcess() throws InterruptedException, ExecutionException { + return new Transaction<TestProcessInfo>() { + @Override + protected TestProcessInfo process() throws Transaction.InvalidCacheException ,ExecutionException { + String testId = validate( fDiagnosticsCM.runTest(getDiagnosticsTestName(), this) ); + RunControlContext testCtx = validate( fRunControlCM.getContext(testId) ); + String processId = testCtx.getProcessID(); + // Create the cache to listen for exceptions. + fRunControlCM.waitForContextException(testId, fTestRunKey); + + String threadId = ""; + if (!processId.equals(testId)) { + threadId = testId; + } else { + String[] threads = validate( fRunControlCM.getChildren(processId) ); + threadId = threads[0]; + } + RunControlContext threadCtx = validate( fRunControlCM.getContext(threadId) ); + + Assert.assertTrue("Invalid thread context", threadCtx.hasState()); + + return new TestProcessInfo(testId, testCtx, processId, threadId, threadCtx); + }; + }.get(); + } + + private boolean runToTestEntry(final TestProcessInfo processInfo, final String testFunc) throws InterruptedException, ExecutionException { + return new Transaction<Boolean>() { + Object fWaitForResumeKey; + Object fWaitForSuspendKey; + boolean fSuspendEventReceived = false; + @Override + protected Boolean process() throws Transaction.InvalidCacheException ,ExecutionException { + ISymbol sym_func0 = validate( fDiagnosticsCM.getSymbol(processInfo.fProcessId, testFunc) ); + String sym_func0_value = sym_func0.getValue().toString(); + ContextState state = validate (fRunControlCM.getState(processInfo.fThreadId)); + + while (!state.suspended || !new BigInteger(state.pc).equals(new BigInteger(sym_func0_value))) { + if (state.suspended && fWaitForSuspendKey == null) { + fSuspendEventReceived = true; + // We are not at test entry. Create a new suspend wait cache. + fWaitForResumeKey = new Object(); + fWaitForSuspendKey = new Object(); + ICache<Object> waitForResume = fRunControlCM.waitForContextResumed(processInfo.fThreadId, fWaitForResumeKey); + + // Issue resume command. + validate( fRunControlCM.resume(processInfo.fThreadCtx, fWaitForResumeKey, IRunControl.RM_RESUME, 1) ); + + // Wait until we receive the resume event. + validate(waitForResume); + fWaitForSuspendKey = new Object(); + fRunControlCM.waitForContextSuspended(processInfo.fThreadId, fWaitForSuspendKey); + } else { + if (fWaitForResumeKey != null) { + // Validate resume command + validate( fRunControlCM.resume(processInfo.fThreadCtx, fWaitForResumeKey, IRunControl.RM_RESUME, 1) ); + fWaitForResumeKey = null; + + } + // Wait until we suspend. + validate( fRunControlCM.waitForContextSuspended(processInfo.fThreadId, fWaitForSuspendKey) ); + fWaitForSuspendKey = null; + } + } + + return fSuspendEventReceived; + } + }.get(); + } + + protected TestProcessInfo startProcess(String testFunc) throws Exception { + String bpId = "entryPointBreakpoint"; + createBreakpoint(bpId, testFunc); + + final TestProcessInfo processInfo = startProcess(); + + runToTestEntry(processInfo, testFunc); + removeBreakpoint(bpId); + + new Transaction<String>() { + @Override + protected String process() throws InvalidCacheException, ExecutionException { + String[] frameIds = validate( fStackTraceCM.getChildren(processInfo.fThreadId) ); + Assert.assertTrue("No stack frames" , frameIds.length != 0); + return frameIds[frameIds.length - 1]; + } + }.get(); + + return processInfo; + } + + protected ContextState resumeAndWaitForSuspend(final RunControlContext context, final int mode) throws InterruptedException, ExecutionException { + return new Transaction<ContextState>() { + @Override + protected ContextState process() throws InvalidCacheException, ExecutionException { + ICache<Object> waitCache = fRunControlCM.waitForContextSuspended(context.getID(), this); + validate( fRunControlCM.resume(context, this, mode, 1) ); + validate(waitCache); + return validate( fRunControlCM.getState(context.getID()) ); + } + }.get(); + } + + protected void createBreakpoint(final String bpId, final String testFunc) + throws InterruptedException, ExecutionException + { + new Transaction<Object>() { + private Map<String,Object> fBp; + { + fBp = new TreeMap<String,Object>(); + fBp.put(IBreakpoints.PROP_ID, bpId); + fBp.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE); + fBp.put(IBreakpoints.PROP_LOCATION, testFunc); + } + + @Override + protected Object process() throws InvalidCacheException, ExecutionException { + // Prime event wait caches + fBreakpointsCM.waitContextAdded(this); + + validate( fBreakpointsCM.add(fBp, this) ); + validate( fBreakpointsCM.waitContextAdded(this)); + + // Wait for breakpoint status event and validate it. + Map<String, Object> status = validate(fBreakpointsCM.getStatus(bpId)); + String s = (String)status.get(IBreakpoints.STATUS_ERROR); + if (s != null) { + Assert.fail("Invalid BP status: " + s); + } + @SuppressWarnings("unchecked") + Collection<Map<String,Object>> list = + (Collection<Map<String,Object>>)status.get(IBreakpoints.STATUS_INSTANCES); + if (list != null) { + String err = null; + for (Map<String,Object> map : list) { + if (map.get(IBreakpoints.INSTANCE_ERROR) != null) { + err = (String)map.get(IBreakpoints.INSTANCE_ERROR); + } + } + if (err != null) { + Assert.fail("Invalid BP status: " + s); + } + } + return null; + } + }.get(); + } + + protected void removeBreakpoint(final String bpId) throws InterruptedException, ExecutionException { + new Transaction<Object>() { + + @Override + protected Object process() throws InvalidCacheException, ExecutionException { + + // Prime event wait caches + fBreakpointsCM.waitContextRemoved(this); + + // Remove + validate( fBreakpointsCM.remove(new String[] { bpId }, this) ); + + // Verify removed event + String[] removedIds = validate( fBreakpointsCM.waitContextRemoved(this)); + Assert.assertTrue(Arrays.asList(removedIds).contains(bpId)); + return null; + } + }.get(); + } + + protected void moveToLocation(final String context, final Number address) throws + DebugException, ExecutionException, InterruptedException + { + final RegistersContext pcReg = new Transaction<RegistersContext>() { + @Override + protected RegistersContext process() throws InvalidCacheException ,ExecutionException { + String[] registers = validate(fRegistersCM.getChildren(context)); + return findPCRegister(registers); + } + + private RegistersContext findPCRegister(String[] registerIds) throws InvalidCacheException ,ExecutionException { + for (String regId : registerIds) { + RegistersContext reg = validate(fRegistersCM.getContext(regId)); + if ( IRegisters.ROLE_PC.equals(reg.getRole()) ) { + return reg; + } + } + for (String regId : registerIds) { + String[] children = validate(fRegistersCM.getChildren(regId)); + RegistersContext pc = findPCRegister(children); + if (pc != null) return pc; + } + return null; + } + }.get(); + + assertNotNull("Cannot find PC register", pcReg); + + new Transaction<Object>() { + @Override + protected Object process() throws Transaction.InvalidCacheException ,ExecutionException { + byte[] value = addressToByteArray(address, pcReg.getSize(), pcReg.isBigEndian()); + validate(fRegistersCM.setContextValue(pcReg, this, value)); + return null; + }; + }.get(); + } + + private byte[] addressToByteArray(Number address, int size, boolean bigEndian) { + byte[] bytes = new byte[size]; + byte[] addrBytes = JSON.toBigInteger(address).toByteArray(); + for (int i=0; i < bytes.length; ++i) { + byte b = 0; + if (i < addrBytes.length) { + b = addrBytes[addrBytes.length - i - 1]; + } + bytes[bigEndian ? size -i - 1 : i] = b; + } + return bytes; + } +} diff --git a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/AbstractTcfUITest.java b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/AbstractTcfUITest.java index b333af29a..b0e924a53 100644 --- a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/AbstractTcfUITest.java +++ b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/AbstractTcfUITest.java @@ -654,8 +654,8 @@ public abstract class AbstractTcfUITest extends TcfTestCase implements IViewerUp // Make sure that delta is posted after launching process so that it doesn't interfere // with the waiting for the whole viewer to update after breakpoint hit (below). - fDebugViewListener.waitTillFinished(MODEL_CHANGED_COMPLETE); - fDebugViewListener.resetModelChanged(); + fDebugViewListener.waitTillFinished(MODEL_CHANGED_COMPLETE| CONTENT_SEQUENCE_COMPLETE | LABEL_SEQUENCE_COMPLETE | LABEL_UPDATES); + fDebugViewListener.reset(); runToTestEntry(processInfo, testFunc); removeBreakpoint(bpId); @@ -678,7 +678,7 @@ public abstract class AbstractTcfUITest extends TcfTestCase implements IViewerUp fDebugViewListener.waitTillFinished(MODEL_CHANGED_COMPLETE | CONTENT_SEQUENCE_COMPLETE | LABEL_SEQUENCE_COMPLETE | LABEL_UPDATES); VirtualItem topFrameItem = fDebugViewListener.findElement( - new Pattern[] { Pattern.compile(".*"), Pattern.compile(".*"), Pattern.compile(".*" + processInfo.fProcessId + ".*\\(Breakpoint.*"), Pattern.compile(".*")}); + new Pattern[] { Pattern.compile(".*"), Pattern.compile(".*"), Pattern.compile(".*" + processInfo.fProcessId + ".*\\(.*[Bb]reakpoint.*"), Pattern.compile(".*")}); if (topFrameItem == null) { Assert.fail("Top stack frame not found. \n\nDebug view dump: \n:" + fDebugViewViewer.toString()); } diff --git a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/RunControlCMTest.java b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/RunControlCMTest.java new file mode 100644 index 000000000..220a412fd --- /dev/null +++ b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/RunControlCMTest.java @@ -0,0 +1,321 @@ +/******************************************************************************* + * 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(); + + } +} diff --git a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/SampleTest.java b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/SampleTest.java index 347d7ed38..f8d2cff66 100644 --- a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/SampleTest.java +++ b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/SampleTest.java @@ -10,22 +10,17 @@ 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 java.util.regex.Pattern; import org.eclipse.debug.internal.ui.viewers.model.provisional.VirtualItem; -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.ICache; import org.eclipse.tcf.debug.test.util.RangeCache; import org.eclipse.tcf.debug.test.util.Transaction; import org.eclipse.tcf.services.ILineNumbers.CodeArea; import org.eclipse.tcf.services.IRunControl; -import org.eclipse.tcf.services.IRunControl.RunControlContext; import org.eclipse.tcf.services.IStackTrace.StackTraceContext; import org.eclipse.tcf.services.ISymbols; import org.eclipse.tcf.services.ISymbols.Symbol; @@ -362,156 +357,4 @@ public class SampleTest extends AbstractTcfUITest { } }.get(); } - - public void testStackTraceCMResetOnContextStateChange() throws Exception { - final TestProcessInfo processInfo = initProcessModel("tcf_test_func2"); - - // Retrieve the current PC and top frame for use later - final String pc = new Transaction<String>() { - @Override - protected String process() throws InvalidCacheException, ExecutionException { - return validate(fRunControlCM.getState(processInfo.fThreadId)).pc; - } - }.get(); - - // Retrieve data from caches (make them valid). - new Transaction<Object>() { - @Override - protected String process() throws InvalidCacheException, ExecutionException { - String[] frameIds = validate( fStackTraceCM.getChildren(processInfo.fThreadId) ); - validate (fStackTraceCM.getContexts(frameIds)); - RangeCache<StackTraceContext> framesRange = fStackTraceCM.getContextRange(processInfo.fThreadId); - validate( framesRange.getRange(0, frameIds.length) ); - return null; - } - }.get(); - - - // Execute a step. - resumeAndWaitForSuspend(processInfo.fThreadCtx, IRunControl.RM_STEP_OUT); - - // End test, check that all caches were reset and now return an error. - new Transaction<Object>() { - @Override - protected Object process() throws InvalidCacheException, ExecutionException { - ICache<String[]> frameIdsCache = fStackTraceCM.getChildren(processInfo.fThreadId); - Assert.assertFalse("Expected cache to be reset", frameIdsCache.isValid()); - return null; - } - }.get(); - - new Transaction<Object>() { - @Override - protected Object process() throws InvalidCacheException, ExecutionException { - String[] frameIds = validate( fStackTraceCM.getChildren(processInfo.fThreadId) ); - ICache<StackTraceContext[]> cache = fStackTraceCM.getContexts(frameIds); - Assert.assertFalse("Expected cache to be reset", cache.isValid()); - - RangeCache<StackTraceContext> framesRange = fStackTraceCM.getContextRange(processInfo.fThreadId); - ICache<List<StackTraceContext>> framesRangeCache = framesRange.getRange(0, frameIds.length); - Assert.assertFalse("Expected cache to be reset", framesRangeCache.isValid()); - - return null; - } - }.get(); - } - - public void testRunControlCMChildrenInvalidation() throws Exception { - final TestProcessInfo processInfo = initProcessModel("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) {} - try { - String children[] = validate( fRunControlCM.getChildren(processInfo.fProcessId) ); - Assert.assertEquals("Expected no children", 0, children.length); - } catch (ExecutionException e) {} - } - - return null; - } - }.get(); - - removeBreakpoint("testRunControlCMChildrenInvalidation"); - - } } diff --git a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/StackTraceCMTest.java b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/StackTraceCMTest.java new file mode 100644 index 000000000..7d1ed61f4 --- /dev/null +++ b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/StackTraceCMTest.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * 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.util.List; +import java.util.concurrent.ExecutionException; + +import org.eclipse.tcf.debug.test.util.ICache; +import org.eclipse.tcf.debug.test.util.RangeCache; +import org.eclipse.tcf.debug.test.util.Transaction; +import org.eclipse.tcf.services.IRunControl; +import org.eclipse.tcf.services.IStackTrace.StackTraceContext; +import org.junit.Assert; + +public class StackTraceCMTest extends AbstractCMTest { + + public void testStackTraceCMResetOnContextStateChange() throws Exception { + final TestProcessInfo processInfo = startProcess("tcf_test_func2"); + + // Retrieve the current PC and top frame for use later + final String pc = new Transaction<String>() { + @Override + protected String process() throws InvalidCacheException, ExecutionException { + return validate(fRunControlCM.getState(processInfo.fThreadId)).pc; + + } + }.get(); + + // Retrieve data from caches (make them valid). + new Transaction<Object>() { + @Override + protected String process() throws InvalidCacheException, ExecutionException { + String[] frameIds = validate( fStackTraceCM.getChildren(processInfo.fThreadId) ); + validate (fStackTraceCM.getContexts(frameIds)); + RangeCache<StackTraceContext> framesRange = fStackTraceCM.getContextRange(processInfo.fThreadId); + List<StackTraceContext> frames = validate( framesRange.getRange(0, frameIds.length) ); + StackTraceContext topFrame = frames.get(frames.size() - 1); + Assert.assertTrue("Expected PC to match", pc.equals(topFrame.getInstructionAddress().toString())); + return null; + } + }.get(); + + + // Execute a step. + resumeAndWaitForSuspend(processInfo.fThreadCtx, IRunControl.RM_STEP_OUT); + + // End test, check that all caches were reset and now return an error. + new Transaction<Object>() { + @Override + protected Object process() throws InvalidCacheException, ExecutionException { + ICache<String[]> frameIdsCache = fStackTraceCM.getChildren(processInfo.fThreadId); + Assert.assertFalse("Expected cache to be reset", frameIdsCache.isValid()); + return null; + } + }.get(); + + new Transaction<Object>() { + @Override + protected Object process() throws InvalidCacheException, ExecutionException { + String[] frameIds = validate( fStackTraceCM.getChildren(processInfo.fThreadId) ); + ICache<StackTraceContext[]> cache = fStackTraceCM.getContexts(frameIds); + Assert.assertFalse("Expected cache to be reset", cache.isValid()); + + RangeCache<StackTraceContext> framesRange = fStackTraceCM.getContextRange(processInfo.fThreadId); + ICache<List<StackTraceContext>> framesRangeCache = framesRange.getRange(0, frameIds.length); + Assert.assertFalse("Expected cache to be reset", framesRangeCache.isValid()); + + return null; + } + }.get(); + + new Transaction<Object>() { + @Override + protected Object process() throws InvalidCacheException, ExecutionException { + String[] frameIds = validate( fStackTraceCM.getChildren(processInfo.fThreadId) ); + + RangeCache<StackTraceContext> framesRange = fStackTraceCM.getContextRange(processInfo.fThreadId); + List<StackTraceContext> frames = validate(framesRange.getRange(frameIds.length - 1, 1)); + StackTraceContext topFrame = frames.get(0); + + Assert.assertFalse("Expected PC to be updated", pc.equals(topFrame.getInstructionAddress().toString())); + return null; + } + }.get(); + } +} diff --git a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/services/RunControlCM.java b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/services/RunControlCM.java index 758a68e68..db8546769 100644 --- a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/services/RunControlCM.java +++ b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/services/RunControlCM.java @@ -132,29 +132,6 @@ public class RunControlCM extends AbstractCacheManager implements RunControlList } - protected abstract static class ContextKey<V> extends Key<V> { - RunControlContext fContext; - - ContextKey(Class<V> cacheClass, RunControlContext context) { - super(cacheClass); - fContext = context; - } - - @Override - public boolean equals(Object obj) { - if (super.equals(obj) && obj instanceof ContextKey<?>) { - return ((ContextKey<?>)obj).fContext.equals(fContext); - } - return false; - } - - @Override - public int hashCode() { - return super.hashCode() + fContext.hashCode(); - } - } - - private class ContextStateCache extends CallbackCache<ContextState> implements IResettable { private class InnerContextStateCache extends TokenCache<ContextState> implements IRunControl.DoneGetState { @@ -231,11 +208,11 @@ public class RunControlCM extends AbstractCacheManager implements RunControlList return mapCache(new ContextStateKey(id)); } - protected abstract static class ContextCommandKey<V> extends ContextKey<V> { + protected abstract static class ContextCommandKey<V> extends IdKey<V> { Object fClientKey; - ContextCommandKey(Class<V> cacheClass, RunControlContext context, Object clientKey) { - super(cacheClass, context); + ContextCommandKey(Class<V> cacheClass, String contextId, Object clientKey) { + super(cacheClass, contextId); fClientKey = clientKey; } @@ -266,7 +243,7 @@ public class RunControlCM extends AbstractCacheManager implements RunControlList return context.suspend(this); } } - return mapCache( new ContextCommandKey<MyCache>(MyCache.class, context, clientKey) { + return mapCache( new ContextCommandKey<MyCache>(MyCache.class, context.getID(), clientKey) { @Override MyCache createCache() { return new MyCache(); } }); } @@ -280,7 +257,7 @@ public class RunControlCM extends AbstractCacheManager implements RunControlList return context.resume(mode, count, this); } } - return mapCache( new ContextCommandKey<MyCache>(MyCache.class, context, clientKey) { + return mapCache( new ContextCommandKey<MyCache>(MyCache.class, context.getID(), clientKey) { @Override MyCache createCache() { return new MyCache(); } }); } @@ -294,7 +271,7 @@ public class RunControlCM extends AbstractCacheManager implements RunControlList return context.resume(mode, count, params, this); } } - return mapCache( new ContextCommandKey<MyCache>(MyCache.class, context, clientKey) { + return mapCache( new ContextCommandKey<MyCache>(MyCache.class, context.getID(), clientKey) { @Override MyCache createCache() { return new MyCache(); } }); } @@ -306,7 +283,7 @@ public class RunControlCM extends AbstractCacheManager implements RunControlList return context.terminate(this); } } - return mapCache( new ContextCommandKey<MyCache>(MyCache.class, context, clientKey) { + return mapCache( new ContextCommandKey<MyCache>(MyCache.class, context.getID(), clientKey) { @Override MyCache createCache() { return new MyCache(); } }); diff --git a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/services/StackTraceCM.java b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/services/StackTraceCM.java index 6d49f6671..6cd144c89 100644 --- a/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/services/StackTraceCM.java +++ b/tests/plugins/org.eclipse.tcf.debug.test/src/org/eclipse/tcf/debug/test/services/StackTraceCM.java @@ -100,8 +100,7 @@ public class StackTraceCM extends AbstractCacheManager implements IRunControl.Ru return mapCache(new IdKey<MyCache>(MyCache.class, parentId) { @Override MyCache createCache() { return new MyCache(); } - }); - + }); } public ICache<StackTraceContext[]> getContexts(final String[] ids) { |