package org.intracetest.agent;
import static org.easymock.EasyMock.isA;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import junit.framework.TestCase;
import org.easymock.IAnswer;
import org.easymock.EasyMock;
import org.intrace.output.AgentHelper;
import org.intrace.output.IInstrumentationHandler;
import org.intrace.shared.AgentConfigConstants;
import org.intrace.shared.TraceConfigConstants;
/**
* This test tests the Agent. To run this test you must run the test with this
* JVM argument: "-javaagent:built/traceagent_test.jar="
*/
public class TracingSingleMethodTest extends TestCase
{
private Receiver receiver;
private Sender sender;
private Socket socket;
private String M1 = "org.intracetest.agent.ArgumentTypes#boolArrayArrayArg({{Z)V";
private String M2 = "org.intracetest.agent.ArgumentTypes#objArrayArg({Ljava/lang/Object;)V";
private String M3 = "org.intracetest.agent.ArgumentTypes#doubleArg(D)V";
@Override
protected void setUp() throws Exception
{
super.setUp();
deleteOldClassFiles();
AgentHelper.setInstrumentationHandler(null);
// Wait for agent to startup
Thread.sleep(500);
connectToAgent();
testSetting(AgentConfigConstants.INSTRU_ENABLED, "false");
}
private void deleteOldClassFiles()
{
File genbin = new File("./genbin/");
File[] files = genbin.listFiles();
if (files != null)
{
for (int i = 0; i < files.length; i++)
{
if (files[i].isDirectory())
{
deleteDirectory(files[i]);
}
else
{
files[i].delete();
}
}
}
}
public static boolean deleteDirectory(File path)
{
if (path.exists())
{
File[] files = path.listFiles();
for (int i = 0; i < files.length; i++)
{
if (files[i].isDirectory())
{
deleteDirectory(files[i]);
}
else
{
files[i].delete();
}
}
}
return (path.delete());
}
@SuppressWarnings("unchecked")
private void testSetting(String configConstant, String configValue)
throws Exception
{
Map<String, String> settingsResponseMap = sendAndReceiveSettings(configConstant, configValue);
//System.out.println("Compar1 act: " + settingsResponseMap.get(configConstant) );
//System.out.println("Compar2 exp: " + configValue);
assertEquals(configValue, settingsResponseMap.get(configConstant));
}
@SuppressWarnings("unchecked")
private Map<String,String> sendAndReceiveSettings(String configConstant, String configValue)
throws Exception
{
// Set setting
sender.sendMessage(configConstant + configValue);
Object okResponse = receiver.incomingMessages.take();
assertNotNull(okResponse);
assertTrue(okResponse instanceof String);
assertEquals(okResponse, "OK");
// Get settings
sender.sendMessage("getsettings");
Object settingsResponse = receiver.incomingMessages.take();
assertNotNull(settingsResponse);
assertTrue(settingsResponse instanceof Map<?, ?>);
Map<String, String> settingsResponseMap = (Map<String, String>) settingsResponse;
return settingsResponseMap;
}
public void testArgumentTypesForOneMethod() throws Throwable {
// Create and init the mock
final BlockingQueue<String> capturedTrace = new LinkedBlockingQueue<String>();
IInstrumentationHandler testHandler = new ArgCapture(capturedTrace);
AgentHelper.setInstrumentationHandler(testHandler);
// Setup agent
testSetting(AgentConfigConstants.INSTRU_ENABLED, "false");
//The intArg() method takes a single int parameter...let's trace just this one method.
testSetting(AgentConfigConstants.CLASS_REGEX, "org.intracetest.agent.ArgumentTypes#intArg(I)V");
testSetting(AgentConfigConstants.VERBOSE_MODE, "false");
testSetting(AgentConfigConstants.SAVE_TRACED_CLASSFILES, "true");
testSetting(AgentConfigConstants.INSTRU_ENABLED, "true");
// Run Patterns thread
ArgumentTypes argTypes = new ArgumentTypes();
Thread patternThread = new Thread(argTypes);
patternThread.start();
patternThread.join(5 * 1000);
if (argTypes.th != null)
{
throw argTypes.th;
}
// Parse the trace
Map<String, TraceData> parsedTraceData = new HashMap<String, TraceData>();
String traceLine = capturedTrace.poll();
while (traceLine != null)
{
parseLine(parsedTraceData, traceLine);
traceLine = capturedTrace.poll();
}
/**
Method-level tracing to the rescue!
This map contains trace lines (3 of them) for exactly 1 method invocation
because the new method-level-tracing feature specified only one method.
*/
assertEquals("Exactly 1 TraceData object for method intArg() should have been in this map",1,parsedTraceData.size() );
assertNotNull(parsedTraceData.get("intArg"));
{
TraceData trData = parsedTraceData.get("intArg");
assertEquals(1, trData.args.size());
assertEquals("4", trData.args.get(0));
}
}
private void parseLine(Map<String, TraceData> parsedTraceData,
String traceLine)
{
//System.out.println("Parse: " + traceLine);
if (traceLine.contains("DEBUG"))
return;
String[] traceParts = traceLine.split(":##:");
String traceType = traceParts[0];
String traceLineData = traceParts[1];
traceLineData = traceLineData.substring(1, traceLineData.length() - 1);
String[] dataParts = traceLineData.split(",");
String methodSig;
if (traceType.equals("Throwable"))
{
methodSig = dataParts[2].trim();
}
else
{
methodSig = dataParts[1].trim();
}
TraceData traceData = parsedTraceData.get(methodSig);
if (traceData == null)
{
traceData = new TraceData();
parsedTraceData.put(methodSig, traceData);
}
if (traceType.equals("Enter"))
{
traceData.seenEnter = true;
}
else if (traceType.equals("Exit"))
{
traceData.seenExit = true;
}
else if (traceType.equals("Branch"))
{
traceData.branchLines.add(Integer.parseInt(dataParts[2].trim()));
}
else if (traceType.equals("Throwable"))
{
if (traceLine.contains("Caught"))
{
traceData.caughtLines.add(Integer.parseInt(dataParts[3].trim()));
}
}
else if (traceType.startsWith("Arg"))
{
traceData.args.add(dataParts[2].trim());
}
}
@Override
protected void tearDown() throws Exception
{
receiver.stop();
sender.stop();
socket.close();
super.tearDown();
}
private void connectToAgent() throws Exception
{
String host = "localhost";
int port = Integer.parseInt(System.getProperty("org.intrace.port"));
socket = new Socket();
socket.connect(new InetSocketAddress(host, port));
// Start threads
receiver = new Receiver(socket.getInputStream());
receiver.start();
sender = new Sender(socket.getOutputStream());
sender.start();
}
private static class Sender implements Runnable
{
private final OutputStream outputStream;
private final BlockingQueue<String> outgoingMessages = new LinkedBlockingQueue<String>();
private Thread th;
public Sender(OutputStream outputStream)
{
this.outputStream = outputStream;
}
public void stop()
{
try
{
outputStream.close();
}
catch (IOException e)
{
// Throw away
}
th.interrupt();
}
public void start()
{
th = new Thread(this);
th.setDaemon(true);
th.setName("Sender");
th.start();
}
@Override
public void run()
{
try
{
while (true)
{
String message = outgoingMessages.take();
ObjectOutputStream objOut = new ObjectOutputStream(outputStream);
objOut.writeObject(message);
objOut.flush();
}
}
catch (Exception e)
{
// Do something
}
}
public void sendMessage(String message)
{
try
{
outgoingMessages.put(message);
}
catch (InterruptedException e)
{
// Do nothing
}
}
}
private static class Receiver implements Runnable
{
private final InputStream inputStream;
private final BlockingQueue<Object> incomingMessages = new LinkedBlockingQueue<Object>();
private Thread th;
public Receiver(InputStream inputStream)
{
this.inputStream = inputStream;
}
public void stop()
{
try
{
inputStream.close();
}
catch (IOException e)
{
// Throw away
}
th.interrupt();
}
public void start()
{
th = new Thread(this);
th.setDaemon(true);
th.setName("Receiver");
th.start();
}
@Override
public void run()
{
try
{
while (true)
{
ObjectInputStream objIn = new ObjectInputStream(inputStream);
Object receivedMessage = objIn.readObject();
// System.out.println("Test received: " + receivedMessage);
if (receivedMessage instanceof Map<?, ?>)
{
Map<?, ?> receivedMap = (Map<?, ?>) receivedMessage;
if (receivedMap.containsKey(AgentConfigConstants.NUM_PROGRESS_ID)||
receivedMap.containsKey(AgentConfigConstants.STID))
{
continue;
}
}
incomingMessages.put(receivedMessage);
}
}
catch (Exception e)
{
// Do nothing
}
}
}
}