/******************************************************************************* | |
* Copyright (c) 2011 Nokia 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: | |
* Nokia - Initial API and implementation, June, 2011 | |
*******************************************************************************/ | |
package org.eclipse.cdt.debug.edc.tests; | |
import static org.junit.Assert.fail; | |
import java.io.IOException; | |
import java.util.Collection; | |
import java.util.Map; | |
import org.eclipse.cdt.debug.edc.tests.tcfagent.EDCTestAgent; | |
import org.eclipse.cdt.debug.edc.tests.tcfagent.IUnitTestDriver; | |
import org.eclipse.cdt.debug.edc.tests.tcfagent.UnitTestDriverProxy; | |
import org.eclipse.tm.tcf.core.AbstractPeer; | |
import org.eclipse.tm.tcf.protocol.IChannel; | |
import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener; | |
import org.eclipse.tm.tcf.protocol.IPeer; | |
import org.eclipse.tm.tcf.protocol.IService; | |
import org.eclipse.tm.tcf.protocol.IServiceProvider; | |
import org.eclipse.tm.tcf.protocol.Protocol; | |
import org.eclipse.tm.tcf.services.ILocator; | |
import org.eclipse.tm.tcf.services.ILocator.LocatorListener; | |
import org.junit.After; | |
import org.junit.Assert; | |
import org.junit.Before; | |
import org.junit.Test; | |
/** | |
* Test TCF services especially those defined by EDC. | |
*/ | |
abstract public class BaseTCFServiceTest { | |
private boolean peerTested = false; | |
private Exception errorInTCF = null; | |
private boolean errorEncountered = false; | |
private IServiceProvider commonServiceProvider = new IServiceProvider() { | |
/* | |
* Tell the framework the proxy we offer. | |
*/ | |
public IService getServiceProxy(IChannel channel, String serviceName) { | |
if (serviceName.equals(IUnitTestDriver.NAME)) | |
return new UnitTestDriverProxy(channel); | |
// These will be done when EDCDebugger plugin is started. | |
// | |
// else if (serviceName.equals(ILogging.NAME)) | |
// return new LoggingProxy(channel); | |
// else if (serviceName.equals(ISettings.NAME)) | |
// return new SettingsProxy(channel); | |
return null; | |
} | |
public IService[] getLocalService(IChannel channel) { | |
return null; | |
} | |
}; | |
@Before | |
public void setup() { | |
Protocol.invokeLater(new Runnable() { | |
public void run() { | |
System.out.println("!!!! TCF is ready."); | |
} | |
}); | |
Protocol.addServiceProvider(commonServiceProvider); | |
/* | |
* Now start the TCF agent. Note here we are not running the agent in a | |
* separate process. Instead it's running in the same process (namely | |
* same runtime framework of TCF) as the host test code (TCF client). | |
* | |
* PROS: simple and easy to start the agent. Otherwise to launch it in a | |
* separate process automatically, we have to put the agent in a | |
* separate simple plugin, export to a jar file, then launch the jar | |
* file. That would require much more effort, and make it a lot more | |
* hassle to modify the test agent then run it. That also requires extra | |
* effort on auto-build/auto-test machine. | |
* | |
* CONS: It's known that it won't always work well to have TCF agent and | |
* client running in the same process. But with our simple agent, it's | |
* no problem yet so far. If you ever suspect, just manually run the | |
* agent as a "Java Application" (namely run it in a separate process) | |
* and see if it helps. If yes, we have to take the harder way. | |
* | |
* .............06/20/2011 | |
*/ | |
try { | |
getTestAgentInstance().start(); | |
} catch (IOException e) { | |
Assert.fail("Fail to start test agent: " + e.getMessage()); | |
} | |
} | |
@After | |
public void tearDown() { | |
Protocol.removeServiceProvider(commonServiceProvider); | |
Protocol.invokeAndWait(new Runnable() { | |
public void run() { | |
try { | |
// shutdown agent. | |
getTestAgentInstance().stop(); | |
} catch (IOException e) { | |
// ignore | |
} | |
System.out.println("!!!! Test done."); | |
} | |
}); | |
} | |
@Test | |
public void performTest() { | |
Protocol.invokeLater(new Runnable() { | |
public void run() { | |
ILocator loc = Protocol.getLocator(); | |
Map<String, IPeer> peers = loc.getPeers(); | |
for (IPeer p : peers.values()) | |
examinePeer(p); | |
loc.addListener(new LocatorListener() { | |
public void peerRemoved(String id) { | |
System.out.println("----->>> Peer removed:" + id + "\n"); | |
} | |
public void peerHeartBeat(String id) { | |
} | |
public void peerChanged(IPeer peer) { | |
System.out.println("----->>> Peer changed:" + peer.getName() + "\n"); | |
} | |
public void peerAdded(IPeer peer) { | |
System.out.println("----->>> New Peer Discovered:"); | |
examinePeer(peer); | |
} | |
}); | |
} | |
}); | |
// Idle, letting agent and client chat, | |
// but with a time limit in case the communication is hosed. | |
long timeout = 30000; // milliseconds | |
long start = System.currentTimeMillis(); | |
while (!testDone() && !errorEncountered) | |
try { | |
Thread.sleep(1000); | |
long end = System.currentTimeMillis(); | |
if (start + timeout < end) { | |
fail(this.getClass().getName() + " times out, usually because the TCF communication between Eclipse and test agent is hosed."); | |
break; | |
} | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
/* | |
* Test done, check result. | |
*/ | |
if (errorEncountered) { | |
Assert.assertNotNull(errorInTCF); | |
// Search your test code for the error message, then you | |
// would know what went wrong. | |
fail(errorInTCF.getMessage()); | |
} | |
else { | |
assertTestResult(); | |
} | |
} | |
private void examinePeer(IPeer p) { | |
if (! p.getName().equals(getTestAgentInstance().getAgentName())) // only care about the test agent | |
return; | |
if (peerTested ) | |
return; | |
peerTested = true; | |
System.out.println("----------- Test agent info ------------------"); | |
System.out.println("\tID: " + p.getID()); | |
System.out.println("\tName: " + p.getName()); | |
System.out.println("\tTransport Name: " + p.getTransportName()); | |
final IChannel channel = p.openChannel(); | |
channel.addChannelListener(new IChannelListener() { | |
public void onChannelOpened() { | |
if (channel.getState() != IChannel.STATE_OPEN) | |
return; | |
System.out.println("\nChannel opened: " + channel.getLocalPeer().getID() + " <---> " | |
+ channel.getRemotePeer().getID() + "(" + channel.getRemotePeer().getName() + ")"); | |
Collection<String> lservices = channel.getLocalServices(); | |
System.out.println("\tLocal services: "); | |
for (String s : lservices) | |
System.out.println("\t\t" + s); | |
Collection<String> rservices = channel.getRemoteServices(); | |
System.out.println("\tRemote services: "); | |
for (String sname : rservices) { | |
System.out.println("\t\t" + sname); | |
} | |
/* | |
* Test remote services. | |
*/ | |
String[] servicesToTest = getServicesToTest(); | |
// This may be null | |
IUnitTestDriver testDriverSvc = (IUnitTestDriver) channel.getRemoteService(IUnitTestDriver.NAME); | |
for (String s : servicesToTest) { | |
if (! rservices.contains(s)) { | |
errorInTCFThread("The TCF service \"" + s + "\" is not supported by test agent"); | |
return; | |
} | |
IService svc = channel.getRemoteService(s); | |
testTCFService(svc, testDriverSvc); | |
} | |
} | |
public void onChannelClosed(Throwable error) { | |
System.out.println("Channel to this peer closed: " + channel.getRemotePeer().getID()); | |
((AbstractPeer) channel.getRemotePeer()).dispose(); | |
channel.removeChannelListener(this); | |
} | |
public void congestionLevel(int level) { | |
System.out.println("Congestion level is: " + level); | |
} | |
}); | |
} | |
/** | |
* Record error/exception in global variable. | |
* | |
* @param msg | |
*/ | |
protected void errorInTCFThread(String msg) { | |
errorInTCF = new Exception(msg); | |
errorEncountered = true; | |
} | |
abstract protected EDCTestAgent getTestAgentInstance(); | |
/** | |
* Subclass use this to indicate ending of test. | |
*/ | |
abstract protected boolean testDone(); | |
/** | |
* This is where actual test happens. | |
* | |
* Subclass override this to test one TCF service. If any exception or error | |
* is encountered during the test, call {@link #errorInTCFThread(String)} | |
* and return. | |
* | |
* @param svc | |
* the TCF service to test | |
* @param testDriverSvc | |
* test driver service. Can be null if it's not needed for | |
* testing "svc". | |
*/ | |
abstract protected void testTCFService(IService svc, IUnitTestDriver testDriverSvc); | |
/** | |
* Subclass use this to tell the framework which TCF services it wants | |
* to test. | |
* | |
* @return names of TCF services. Can be empty array but cannot be null. | |
*/ | |
abstract protected String[] getServicesToTest(); | |
/** | |
* For subclass to verify test result. | |
*/ | |
abstract protected void assertTestResult(); | |
} |