SRADA-885: Implemented socket communication for CliManager and TracingProcesses.
authorp.privalov <p.privalov@partner.samsung.com>
Wed, 6 Jul 2016 17:18:09 +0000 (20:18 +0300)
committerMaria Guseva <m.guseva@samsung.com>
Tue, 19 Jul 2016 13:19:48 +0000 (22:19 +0900)
Added second 'port' argument in TracingProcessManager constructor and
TracingProcessManager.createTracingProcess().

Communication performed with regular unencrypted socket.
Now TracingProcessManager can request and get tracing time from TracingProcess
TracingProcessManager also can request TracingProcess to stop, thus we don't
need to close input stream of TracingProcess to stop it, so we do not need
special listener thread for this event.
ProcessManagerTest, TracingProcessManagerTest, TracingProcessCommunicationTest
also redesigned to meet api changes and to test new communication process.

Change-Id: I257f8dbd6ef5d6e6c54938b0d4d556f55b2b16b1

org.tizen.dynamicanalyzer.cli/src/org/tizen/dynamicanalyzer/cli/manager/ProcessManager.java
org.tizen.dynamicanalyzer.cli/src/org/tizen/dynamicanalyzer/cli/manager/TracingProcessManager.java
org.tizen.dynamicanalyzer.cli/src/org/tizen/dynamicanalyzer/cli/tracing/TracingProcess.java
org.tizen.dynamicanalyzer.cli/src/org/tizen/dynamicanalyzer/cli/utils/Message.java [new file with mode: 0644]
org.tizen.dynamicanalyzer.cli/test/src/org/tizen/dynamicanalyzer/cli/manager/ProcessManagerTest.java
org.tizen.dynamicanalyzer.cli/test/src/org/tizen/dynamicanalyzer/cli/manager/TracingProcessManagerTest.java
org.tizen.dynamicanalyzer.cli/test/src/org/tizen/dynamicanalyzer/cli/tracing/TracingProcessCommunicationTest.java

index b91615e..9bc9f3b 100644 (file)
@@ -24,6 +24,10 @@ public class ProcessManager implements ProcessManagerMBean {
        static int TRACING_PROCESS_STOP_TIMEOUT = 16000; // TODO measure this timeout more accurate later
 
        /**
+        * Value to start port enumeration
+        */
+       public static final int DEFAULT_PORT = 9000;
+       /**
         * Map between device and last trace manager used for that device.
         */
        Map<String, TracingProcessManager> mTracingMap;
@@ -82,9 +86,10 @@ public class ProcessManager implements ProcessManagerMBean {
                        return new DAResult(ErrorCode.ERR_BUSY_DEVICE);
                }
 
+               int port = DEFAULT_PORT + mTracingMap.size();
                final TracingProcessManager tpManager;
                try {
-                       tpManager = TracingProcessManager.createTracingProcess(args);
+                       tpManager = TracingProcessManager.createTracingProcess(args, port);
                } catch (IOException e) {
                        Logger.error("Couldn't start tracing proccess: %s.", e.toString());
                        return new DAResult(ErrorCode.ERR_EXCEPTION_OCCURRED, "Couldn't start tracing process: " + e.toString());
index b3e2e63..a5baf3b 100644 (file)
@@ -1,8 +1,15 @@
 package org.tizen.dynamicanalyzer.cli.manager;
 
+import java.io.BufferedWriter;
 import java.io.File;
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStreamWriter;
 import java.lang.ProcessBuilder.Redirect;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
@@ -11,8 +18,11 @@ import java.util.List;
 import org.tizen.dynamicanalyzer.cli.tracing.TracingArguments;
 import org.tizen.dynamicanalyzer.cli.tracing.TracingArgumentsParser;
 import org.tizen.dynamicanalyzer.cli.tracing.TracingProcess;
+import org.tizen.dynamicanalyzer.cli.utils.Message;
+import org.tizen.dynamicanalyzer.cli.utils.Message.MessageType;
 import org.tizen.dynamicanalyzer.common.path.PathManager;
 import org.tizen.dynamicanalyzer.project.Project;
+import org.tizen.dynamicanalyzer.util.Logger;
 
 /**
  * Class supposed to manage single {@link TracingProcess} instance.
@@ -32,13 +42,19 @@ public class TracingProcessManager {
        }
 
        /**
+        * pipe to TracingProcess to send port
+        */
+       static BufferedWriter bw;
+
+       /**
         * Execute new tracing process with specified arguments and wrap it with {@link TracingProcessManager}.
         *
         * @param args tracing arguments
+        * @param port integer socket port number
         * @return {@link TracingProcessManager} instance that manages corresponding process.
         * @throws IOException in error occurred while executing process
         */
-       public static TracingProcessManager createTracingProcess(TracingArguments args) throws IOException {
+       public static TracingProcessManager createTracingProcess(TracingArguments args, int port) throws IOException {
                // compose command line
                String currentClasspath = System.getProperty("java.class.path");
 
@@ -71,8 +87,17 @@ public class TracingProcessManager {
 
                // actually start separate tracing process
                Process process = pBuilder.start();
+               // send communication port number to tracing process
+               bw = new BufferedWriter(new OutputStreamWriter(
+                               process.getOutputStream(), StandardCharsets.UTF_8));
+               try {
+                       bw.write(Integer.toString(port));
+                       bw.newLine();
+                       bw.flush();
+               } catch (IOException e2) {
+               }
 
-               return new TracingProcessManager(args, process);
+               return new TracingProcessManager(args, process, port);
        }
 
        /**
@@ -91,9 +116,10 @@ public class TracingProcessManager {
        private volatile Thread monitoringThread;
 
        /**
-        * Indicator of whether the output stream was closed.
+        * Thread, that encapsulated all communication with TracingProcess, starts
+        * in constructor
         */
-       private boolean streamClosed = false;
+       private ServerConnection serverConnection;
 
        /**
         * Launch asynchronous monitoring of tracing process state.
@@ -120,11 +146,27 @@ public class TracingProcessManager {
         *
         * @param args arguments with which tracing process started
         * @param process process instance corresponding to the tracing process
+        * @param port integer socket port number
         */
-       private TracingProcessManager(TracingArguments args, Process process) {
+       private TracingProcessManager(TracingArguments args, Process process,
+                       int port) {
                ctx = new TracingProcessContext(args);
                tracingProcess = process;
 
+               try {
+                       final ServerSocket ss = new ServerSocket(port);
+                       Socket socket = ss.accept();
+                       // start processing in separate thread
+                       serverConnection = new ServerConnection(socket);
+                       Thread commThread = new Thread(serverConnection,
+                                       "Communication thread");
+                       commThread.start();
+                       // finally we should close server socket
+                       ss.close();
+               } catch (IOException e1) {
+                       Logger.error("Failed to establish communication between TracingProcessManager and TracingProcess");
+               }
+
                startMonitoring();
        }
 
@@ -154,14 +196,7 @@ public class TracingProcessManager {
                synchronized (this) {
                        if (ctx.isFinished())
                                return;
-
-                       if (!streamClosed) {
-                               // try to send stop signal to the tracing process
-                               // by closing it's input stream
-                               tracingProcess.getOutputStream().close();
-
-                               streamClosed = true;
-                       }
+                       serverConnection.sendMessage(MessageType.STOP_TRACING);
                }
 
                waitForCompletion();
@@ -241,4 +276,79 @@ public class TracingProcessManager {
                return ctx.isFinished();
        }
 
+       private static class ServerConnection implements Runnable {
+               ObjectOutputStream oos;
+               ObjectInputStream ois;
+
+               /**
+                * ConnectionProcessor constructor.
+                *
+                * @param socket connection socket
+                * @throws IOException in case of communication initialization error
+                */
+               private ServerConnection(Socket socket) throws IOException {
+                       this.oos = new ObjectOutputStream(socket.getOutputStream());
+                       this.ois = new ObjectInputStream(socket.getInputStream());
+               }
+
+               /**
+                * Send message to stream.
+                *
+                * @param message message to socket
+                * @throws IOException in case of communication error
+                */
+               public void sendMessage(Message message) throws IOException {
+                       oos.writeObject(message);
+                       oos.flush();
+               }
+
+               /**
+                * Send message to stream. Constructs {@link Message} instance on the
+                * fly.
+                *
+                * @param messageT message type
+                * @param args message arguments
+                * @throws IOException in case of communication error
+                */
+               public void sendMessage(MessageType messageT, String... args)
+                               throws IOException {
+                       sendMessage(new Message(messageT, args));
+               }
+               /**
+                * Actual connection processing.
+                */
+               @Override
+               public void run() {
+                       try {
+                               boolean childAlive = true;
+                               while (childAlive) {
+                                       Object rawObj = ois.readObject();
+                                       if (!(rawObj instanceof Message))
+                                               continue;
+
+                                       Message message = (Message) rawObj;
+                                       switch (message.messageT) {
+                                       case STOP_DONE:
+                                               childAlive = false;
+                                               bw.close();
+                                               break;
+                                       case INFO_TRACING_TIME:
+
+                                               break;
+                                       // Wrong requests
+                                       case REQUEST_TRACING_TIME:
+                                       case STOP_TRACING:
+                                       default:
+                                               Logger.warning("wrong request type for TracingProcessManager");
+                                               break;
+                                       }
+                               }
+                       } catch (ClassNotFoundException e) {
+                               Logger.error("Error while communicating with TracingProcess. Message type can't be resolved.");
+                       } catch (IOException e) {
+                               Logger.info("Communication stopped, stream closed");
+                       }
+               }
+       }
+
 }
index b47b2e8..03b61cc 100644 (file)
@@ -1,9 +1,21 @@
 package org.tizen.dynamicanalyzer.cli.tracing;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 
 import org.apache.commons.cli.ParseException;
 import org.tizen.dynamicanalyzer.cli.CliInternals;
+import org.tizen.dynamicanalyzer.cli.commands.ExitCode;
+import org.tizen.dynamicanalyzer.cli.manager.ProcessManager;
+import org.tizen.dynamicanalyzer.cli.utils.Message;
+import org.tizen.dynamicanalyzer.cli.utils.Message.MessageType;
 import org.tizen.dynamicanalyzer.common.DAResult.ErrorCode;
 import org.tizen.dynamicanalyzer.common.DAState;
 import org.tizen.dynamicanalyzer.common.Global;
@@ -36,12 +48,26 @@ public class TracingProcess {
         */
        private final TracingArguments args;
 
+       /**
+        * client communication thread
+        */
+       private ClientConnection socketConnection;
+
+       /**
+        * Start time value in milliseconds. It's initialized at application start
+        */
        private long startTime;
 
        /**
+        * Stop time value in milliseconds. It's initialized at application stop
+        */
+       private volatile long tracingTime;
+
+       /**
         * Public constructor.
         *
         * @param args tracing input arguments
+        * @param port integer socket port number
         */
        public TracingProcess(TracingArguments args) {
                status = ErrorCode.ERR_UNKNOWN;
@@ -78,8 +104,14 @@ public class TracingProcess {
         * This method should not block caller thread during performing tracing stop.
         */
        public synchronized void stopTrace() {
-               Global.getProject().setTotalStopTime(
-                               (System.currentTimeMillis() - startTime));
+               tracingTime = System.currentTimeMillis() - startTime;
+               Global.getProject().setTotalStopTime(tracingTime);
+               try {
+                       socketConnection.sendMessage(MessageType.INFO_TRACING_TIME,
+                                       Long.toString(tracingTime));
+               } catch (IOException e) {
+                       Logger.error("Got Exception while sending tracing time to TracingProcessManager");
+               }
                CliInternals.stopTracing();
        }
 
@@ -125,7 +157,7 @@ public class TracingProcess {
         *         {@link ErrorCode#ERR_EXCEPTION_OCCURRED} if critical or unexpected error occurred.
         *         TODO complete error codes documentation
         */
-       private static ErrorCode performAllTasks(String[] args) {
+       private static ErrorCode performAllTasks(String[] args, int port) {
                Logger.init(InternalLogger.WARNING);
 
                TracingArguments argsParsed = null;
@@ -140,22 +172,17 @@ public class TracingProcess {
 
                // create instance of tracing process
                final TracingProcess tracingProcess = new TracingProcess(argsParsed);
-
-               // define stop monitor thread behavior
-               Thread stopTraceMonitoringThread = new Thread(new InputStreamEndMonitor(System.in).setOnSuccess(
-                               new Runnable() {
-                                       @Override
-                                       public void run() {
-                                               Logger.info("Monitoring thread got stop signal.");
-
-                                               // stop tracing process
-                                               tracingProcess.stopTrace();
-                                       }
-                               }),
-               "stop-trace-monitoring-thread");
-
-               // main thread shouldn't wait for monitoring completion
-               stopTraceMonitoringThread.setDaemon(true);
+               // communication socket connection
+               try {
+                       //Socket communication estblished between 2 processes on same device
+                       //There were not any secure data, so it is not required to use SSLSocket
+                       Socket socket = new Socket(InetAddress.getLocalHost(), port);
+                       tracingProcess.socketConnection = tracingProcess.getConnProc(socket);
+                       Thread commThread = new Thread(tracingProcess.socketConnection);
+                       commThread.start();
+               } catch (IOException ioe) {
+                       Logger.error("IOException in socket connection.");
+               }
 
                // async start tracing
                Logger.info("Going to start tracing on device '%s'.", argsParsed.getDevice());
@@ -168,8 +195,6 @@ public class TracingProcess {
                }
 
                // async start stop monitor thread
-               stopTraceMonitoringThread.start();
-
                try {
                        // block until tracing will be finished
                        tracingProcess.waitForCompletion();
@@ -190,11 +215,119 @@ public class TracingProcess {
        }
 
        /**
+        * creates ConnectionProcessor by given socket. Return null in case of any
+        * error.
+        *
+        * @param socket
+        * @return
+        */
+       private ClientConnection getConnProc(Socket socket) {
+               try {
+                       return new ClientConnection(socket);
+               } catch (IOException e) {
+               }
+               return null;
+       }
+
+       private static int getPort() {
+               BufferedReader br = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
+               // Reading of unique number of communication port
+               try {
+                       return Integer.parseInt(br.readLine());
+               } catch (NumberFormatException | IOException e) {
+                       System.exit(ExitCode.EX_CONNECTION_ERROR.getCode());
+               }
+               return ProcessManager.DEFAULT_PORT;
+       }
+
+       /**
         * Entry point for tracing process.
         * @param args input parameters for application
         */
        public static void main(String[] args) {
-               ErrorCode exitCode = performAllTasks(args);
+               ErrorCode exitCode = performAllTasks(args, getPort());
                SystemExit.exit(exitCode.getErrorNumber());
        }
+
+       private class ClientConnection implements Runnable {
+               ObjectOutputStream oos;
+               ObjectInputStream ois;
+
+               /**
+                * ConnectionProcessor constructor.
+                *
+                * @param socket connection socket
+                * @throws IOException in case of communication initialization error
+                */
+               private ClientConnection(Socket socket) throws IOException {
+                       this.ois = new ObjectInputStream(socket.getInputStream());
+                       this.oos = new ObjectOutputStream(socket.getOutputStream());
+                       oos.flush();
+               }
+
+               /**
+                * Send message to stream.
+                *
+                * @param message message to socket
+                * @throws IOException in case of communication error
+                */
+               public void sendMessage(Message message) throws IOException{
+                       oos.writeObject(message);
+                       oos.flush();
+               }
+
+               /**
+                * Send message to stream. Constructs {@link Message} instance on the
+                * fly.
+                *
+                * @param messageT message type
+                * @param args message arguments
+                * @throws IOException in case of communication error
+                */
+               public void sendMessage(MessageType messageT, String... args)
+                               throws IOException {
+                       sendMessage(new Message(messageT, args));
+               }
+               /**
+                * Actual connection processing.
+                */
+               @Override
+               public void run() {
+                       try {
+                               while (true) {
+                                       Object rawObj = ois.readObject();
+                                       if (!(rawObj instanceof Message))
+                                               continue;
+
+                                       Message message = (Message) rawObj;
+                                       switch (message.messageT) {
+                                       case STOP_TRACING:
+                                               Logger.info("Stopinng TracingProcess");
+                                               synchronized (this) {
+                                                       if (tracingTime == 0) // check that process is still running
+                                                               stopTrace();
+                                               }
+                                               sendMessage(MessageType.STOP_DONE);
+                                               break;
+                                       case REQUEST_TRACING_TIME:
+                                               sendMessage(MessageType.INFO_TRACING_TIME,
+                                                                       Long.toString(tracingTime));
+                                               break;
+                                       //Wrong requests
+                                       case STOP_DONE:
+                                       case INFO_TRACING_TIME:
+                                       default:
+                                               Logger.warning("wrong request type "
+                                                               + message.messageT.toString()
+                                                               + " for TracingProcess");
+                                               break;
+                                       }
+                               }
+                       } catch (ClassNotFoundException e) {
+                               Logger.error("Error while communicating with TracingProcessManager. Message type can't be resolved.");
+                       } catch (IOException e) {
+                               Logger.info("Communication stopped, stream closed");
+                       }
+               }
+       }
 }
\ No newline at end of file
diff --git a/org.tizen.dynamicanalyzer.cli/src/org/tizen/dynamicanalyzer/cli/utils/Message.java b/org.tizen.dynamicanalyzer.cli/src/org/tizen/dynamicanalyzer/cli/utils/Message.java
new file mode 100644 (file)
index 0000000..47c7e7a
--- /dev/null
@@ -0,0 +1,43 @@
+package org.tizen.dynamicanalyzer.cli.utils;
+
+import java.io.Serializable;
+
+
+/**
+ * Represents message that can be passed between client and server.
+ */
+public class Message implements Serializable {
+
+       public enum MessageType {
+               STOP_TRACING,
+               STOP_DONE,
+               INFO_TRACING_TIME,
+               REQUEST_TRACING_TIME
+       }
+
+       /**
+        * Automatically generated class identifier
+        */
+       private static final long serialVersionUID = -2812158395001795493L;
+
+       /**
+        * Message type.
+        */
+       public MessageType messageT;
+
+       /**
+        * Message arguments.
+        */
+       public String[] args;
+
+       /**
+        * Message constructor
+        *
+        * @param messageT type of message
+        * @param args String representation of message content
+        */
+       public Message(MessageType messageT, String... args) {
+               this.messageT = messageT;
+               this.args = args;
+       }
+}
index 14c682f..2dff96f 100644 (file)
@@ -6,6 +6,8 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -99,11 +101,15 @@ public class ProcessManagerTest {
        }
 
        private void setupManagers() throws Exception {
-               PowerMockito.when(TracingProcessManager.createTracingProcess(args1)).thenReturn(mgr1);
+               PowerMockito
+                               .when(TracingProcessManager.createTracingProcess(eq(args1),
+                                               anyInt())).thenReturn(mgr1);
                Mockito.when(mgr1.getContext()).thenReturn(ctx1);
                Mockito.when(mgr1.isFinished()).thenReturn(false);
 
-               PowerMockito.when(TracingProcessManager.createTracingProcess(args2)).thenReturn(mgr2);
+               PowerMockito
+                               .when(TracingProcessManager.createTracingProcess(eq(args2),
+                                               anyInt())).thenReturn(mgr2);
                Mockito.when(mgr2.getContext()).thenReturn(ctx2);
                Mockito.when(mgr2.isFinished()).thenReturn(false);
 
@@ -131,7 +137,7 @@ public class ProcessManagerTest {
                assertEquals(ErrorCode.SUCCESS.getErrorNumber(), result.getErrorNumber());
 
                PowerMockito.verifyStatic();
-               TracingProcessManager.createTracingProcess(args1);
+               TracingProcessManager.createTracingProcess(args1, 9000);
 
                assertEquals(ctx1, pm.getContext(args1.getDevice()));
        }
index 850344f..c4b4790 100644 (file)
@@ -8,8 +8,13 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.OutputStream;
 import java.lang.reflect.Constructor;
+import java.net.InetAddress;
+import java.net.Socket;
 import java.util.Date;
 import java.util.concurrent.Callable;
 import java.util.concurrent.FutureTask;
@@ -25,7 +30,11 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 import org.powermock.reflect.Whitebox;
 import org.tizen.dynamicanalyzer.cli.tracing.TracingArguments;
+import org.tizen.dynamicanalyzer.cli.utils.Message;
+import org.tizen.dynamicanalyzer.cli.utils.Message.MessageType;
 import org.tizen.dynamicanalyzer.setting.PrimitiveFeature;
+import org.tizen.dynamicanalyzer.util.InternalLogger;
+import org.tizen.dynamicanalyzer.util.Logger;
 
 /**
  * Test for {@link TracingProcessManager} instances.
@@ -41,6 +50,9 @@ public class TracingProcessManagerTest {
        @Mock
        OutputStream oStream;
 
+       static ObjectInputStream ois;
+
+       static final int port = 9000;
        /**
         * Base time unit used in some test for sleep and timeout.
         */
@@ -70,12 +82,21 @@ public class TracingProcessManagerTest {
         * Utility method compares specified time with current system time.
         */
        private void assertCurrentTime(long time_ms) {
-               assertTrue(Math.abs(time_ms - new Date().getTime()) < TIME_EPS_MS);
+               assertTrue(Math.abs(time_ms - new Date().getTime()) < TIME_EPS_MS * 2 + TIMEOUT_MS);
        }
 
+       /**
+        * Tread to emulate TracingProcess communication thread.
+        */
+       Thread commThread;
+
        @Before
        public void setUp() {
+               Logger.init(InternalLogger.DEBUG);
                when(process.getOutputStream()).thenReturn(oStream);
+               commThread = new Thread(new ClientCommunicationStub());
+               commThread.setDaemon(true);
+
 
                // init tracing arguments
                args = new TracingArguments();
@@ -84,13 +105,13 @@ public class TracingProcessManagerTest {
                args.setDuration(0);
                args.addFeature(PrimitiveFeature.CPU_USAGE);
 
-               managerConstructor = Whitebox.getConstructor(TracingProcessManager.class, TracingArguments.class, Process.class);
+               managerConstructor = Whitebox.getConstructor(TracingProcessManager.class, TracingArguments.class, Process.class, int.class);
        }
 
        /**
         * Test manager ability to wait for tracing process completion.
         */
-       @Test(timeout=2*TIMEOUT_MS)
+       @Test(timeout = 2 * TIMEOUT_MS)
        public void waitForCompletion_block_no_except() throws Exception {
                TracingProcessContext ctx = null;
 
@@ -101,9 +122,10 @@ public class TracingProcessManagerTest {
                                return CODE_TO_RETURN;
                        }
                });
+               commThread.start();
 
                // create class under test
-               manager = managerConstructor.newInstance(args, process);
+               manager = managerConstructor.newInstance(args, process, port);
                ctx = manager.getContext();
 
                assertFalse(manager.isFinished());
@@ -124,11 +146,13 @@ public class TracingProcessManagerTest {
         */
        @Test
        public void stopTracing_no_except() throws Exception {
+               commThread.start();
                // create class under test
-               manager = managerConstructor.newInstance(args, process);
+               manager = managerConstructor.newInstance(args, process, port);
                manager.stopTracing();
 
-               verify(oStream).close();
+               assertEquals(MessageType.STOP_TRACING,
+                               ((Message) ois.readObject()).messageT);
        }
 
        /**
@@ -142,6 +166,7 @@ public class TracingProcessManagerTest {
         */
        @Test
        public void stopTracing_already_stopped() throws Exception {
+               commThread.start();
                reached = false;
 
                // setup finish process
@@ -154,7 +179,7 @@ public class TracingProcessManagerTest {
                });
 
                // create class under test
-               manager = managerConstructor.newInstance(args, process);
+               manager = managerConstructor.newInstance(args, process, port);
 
                // synchronization barrier
                while (!reached) {
@@ -181,7 +206,7 @@ public class TracingProcessManagerTest {
         * Test that manager correctly handles successful tracing process
         * completion and synchronously returns error code.
         */
-       @Test(timeout=3*TIMEOUT_MS)
+       @Test(timeout = 3 * TIMEOUT_MS)
        public void stopTracing_timeout_dont_trigger_no_except() throws Exception {
                boolean result = false;
 
@@ -192,9 +217,9 @@ public class TracingProcessManagerTest {
                                return CODE_TO_RETURN;
                        }
                });
-
+               commThread.start();
                // create class under test
-               manager = managerConstructor.newInstance(args, process);
+               manager = managerConstructor.newInstance(args, process, port);
 
                assertFalse(manager.isFinished());
                assertCurrentTime(manager.getContext().getStartTime().getTime());
@@ -214,6 +239,7 @@ public class TracingProcessManagerTest {
         */
        @Test(timeout=3*TIMEOUT_MS)
        public void stopTracing_timeout_trigger_no_except() throws Exception {
+               commThread.start();
                boolean result = false;
 
                when(process.waitFor()).thenAnswer(new Answer<Integer>() {
@@ -229,7 +255,7 @@ public class TracingProcessManagerTest {
                });
 
                // create class under test
-               manager = managerConstructor.newInstance(args, process);
+               manager = managerConstructor.newInstance(args, process, port);
 
                assertFalse(manager.isFinished());
                assertCurrentTime(manager.getContext().getStartTime().getTime());
@@ -252,6 +278,7 @@ public class TracingProcessManagerTest {
         */
        @Test(timeout=TIMEOUT_MS)
        public void forceStopTracing_no_except() throws Exception {
+               commThread.start();
                destroy_called = false;
 
                when(process.waitFor()).thenAnswer(new Answer<Integer>() {
@@ -278,7 +305,7 @@ public class TracingProcessManagerTest {
                }).when(process).destroy();
 
                // create class under test
-               manager = managerConstructor.newInstance(args, process);
+               manager = managerConstructor.newInstance(args, process, port);
 
                assertFalse(manager.isFinished());
                assertCurrentTime(manager.getContext().getStartTime().getTime());
@@ -299,6 +326,7 @@ public class TracingProcessManagerTest {
         */
        @Test
        public void forceStopTracing_already_stopped() throws Exception {
+               commThread.start();
                reached = false;
 
                // setup finish process
@@ -311,7 +339,7 @@ public class TracingProcessManagerTest {
                });
 
                // create class under test
-               manager = managerConstructor.newInstance(args, process);
+               manager = managerConstructor.newInstance(args, process, port);
 
                // synchronization barrier
                while (!reached) {
@@ -346,6 +374,7 @@ public class TracingProcessManagerTest {
         */
        @Test(timeout=2*TIMEOUT_MS)
        public void forceStopTracing_async() throws Exception {
+               commThread.start();
                // setup guarded variable
                pass = false;
 
@@ -383,7 +412,7 @@ public class TracingProcessManagerTest {
                }).when(process).destroy();
 
                // create class under test
-               manager = managerConstructor.newInstance(args, process);
+               manager = managerConstructor.newInstance(args, process, port);
 
                // call stopTracing in separate thread
                FutureTask<Boolean> stopTask = new FutureTask<>(new Callable<Boolean>() {
@@ -415,4 +444,20 @@ public class TracingProcessManagerTest {
                // result of stopTracing(timeout) should be true if process stopped during this period
                assertTrue(stopTaskResult);
        }
+
+       private static class ClientCommunicationStub implements Runnable {
+               // Stub for TracingProcess communication thread.
+               @Override
+               public void run() {
+                       try {
+                               Thread.sleep(TIME_EPS_MS);
+                               Socket socket = new Socket(InetAddress.getLocalHost(), port);
+                               ois = new ObjectInputStream(socket.getInputStream());
+                               ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
+                               oos.flush();
+                       } catch (InterruptedException | IOException e) {
+                               assertTrue(false);
+                       }
+               }
+       }
 }
index c6bc037..a59c90a 100644 (file)
@@ -1,18 +1,21 @@
 package org.tizen.dynamicanalyzer.cli.tracing;
 
-import java.io.InputStream;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.powermock.api.mockito.PowerMockito;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
-import org.tizen.dynamicanalyzer.common.DAResult.ErrorCode;
+import org.tizen.dynamicanalyzer.cli.utils.Message;
+import org.tizen.dynamicanalyzer.cli.utils.Message.MessageType;
 import org.tizen.dynamicanalyzer.setting.PrimitiveFeature;
 
 /**
@@ -25,25 +28,12 @@ public class TracingProcessCommunicationTest {
        // timeout for test
        private static final int TIMEOUT_MS = 500;
 
-       private final ErrorCode codeToReturn = ErrorCode.ERR_OUT_OF_MEMORY;
-
-       private volatile boolean received_signal;
-       private Object received_lock;
-
-       @Mock
-       private InputStream in;
-
-       private InputStreamEndMonitor streamMonitor;
-
-       private TracingProcess tracingProcess;
+       static int port = 9000;
 
        private TracingArguments args;
 
        @Before
        public void setUp() throws Exception {
-               received_signal = false;
-               received_lock = new Object();
-
                args = new TracingArguments();
                args.setApplication("APP");
                args.setDevice("DEV");
@@ -52,79 +42,45 @@ public class TracingProcessCommunicationTest {
        }
 
        /**
-        * Check tracing process  responds on shutdown signal
+        * Check tracing process responds on requests
         */
-       @Test(timeout=2*TIMEOUT_MS)
-       public void interruptCommunication() throws Exception {
-               // setup mocks
-               // mock System.exit method
-               PowerMockito.mockStatic(SystemExit.class);
-
-               // setup mock and spy
-               tracingProcess = PowerMockito.mock(TracingProcess.class);
-               streamMonitor = Mockito.spy(new InputStreamEndMonitor(in));
-
-               // mock objects creation
-               PowerMockito.whenNew(TracingProcess.class).withAnyArguments().thenReturn(tracingProcess);
-               PowerMockito.whenNew(InputStreamEndMonitor.class).withAnyArguments().thenReturn(streamMonitor);
-
-               // fire input stream end event after TIMEOUR_MS delay for in.read()
-               Mockito.when(in.read()).thenAnswer(new Answer<Integer>() {
-                       @Override
-                       public Integer answer(InvocationOnMock invocation) throws Exception {
-                               Thread.sleep(TIMEOUT_MS);
-                               return -1;
-                       }
-               });
-
-               Mockito.when(tracingProcess.startTrace()).thenReturn(ErrorCode.SUCCESS);
-
-               Mockito.when(tracingProcess.getStatus()).then(new Answer<ErrorCode>() {
-                       @Override
-                       public ErrorCode answer(InvocationOnMock invocation) {
-                               // let's return any code
-                               return codeToReturn;
-                       }
-               });
-
-               // answer on stopTrace event
-               Mockito.doAnswer(new Answer<Object>() {
-                       @Override
-                       public Object answer(InvocationOnMock invocation) {
-                               synchronized (received_lock) {
-                                       received_signal = true;
-                                       received_lock.notifyAll();
-                               }
-                               return null;
-                       }
-               }).when(tracingProcess).stopTrace();
+       @Test(timeout = 2 * TIMEOUT_MS)
+       public void testStandardBehavior() throws Exception {
+               Thread thread = new Thread(new CommunicationMock());
+               thread.start();
+               new TracingProcess(args);
+       }
 
-               // waitForCompletion logic
-               Mockito.doAnswer(new Answer<Object>() {
-                       @Override
-                       public Object answer(InvocationOnMock invocation) throws InterruptedException {
-                               synchronized (received_lock) {
-                                       while (!received_signal)
-                                               received_lock.wait();
-                               }
-                               return null;
+       private static class CommunicationMock implements Runnable {
+
+               @Override
+               public void run() {
+                       try {
+                               ServerSocket ss = new ServerSocket(port);
+                               Socket socket = ss.accept();
+                               ss.close();
+                               ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
+                               oos.flush();
+                               ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
+
+                               oos.writeObject(new Message(MessageType.REQUEST_TRACING_TIME));
+                               oos.flush();
+                               Message mes = (Message) ois.readObject();
+                               assertEquals(MessageType.INFO_TRACING_TIME, mes.messageT);
+                               assertEquals(1, mes.args.length);
+                               assertEquals("0", mes.args[0]);
+
+                               oos.writeObject(new Message(MessageType.STOP_TRACING));
+                               oos.flush();
+                               mes = (Message) ois.readObject();
+                               assertEquals(mes.messageT, MessageType.INFO_TRACING_TIME);
+                               assertTrue(Long.parseLong(mes.args[0])>0);
+
+                               mes = (Message) ois.readObject();
+                               assertEquals(MessageType.STOP_DONE, mes.messageT);
+                       } catch (IOException | ClassNotFoundException e) {
+                               assertTrue(false);
                        }
-               }).when(tracingProcess).waitForCompletion();
-
-               // set saveTrace to be successful
-               Mockito.when(tracingProcess.saveTrace()).thenReturn(true);
-
-               // run code under test
-               TracingProcess.main(TracingArgumentsParser.toStringArray(args));
-
-               // verify exit code
-               PowerMockito.verifyStatic();
-               SystemExit.exit(codeToReturn.getErrorNumber());
-
-               // verify others calls
-               Mockito.verify(tracingProcess).startTrace();
-               Mockito.verify(tracingProcess).stopTrace();
-               Mockito.verify(tracingProcess).waitForCompletion();
-
+               }
        }
 }