blob: 0dcda1e5711002a3c30c677b3d2b55cca86ca973 [file] [log] [blame]
/*******************************************************************************
* 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();
}