11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipackage org.chromium.components.devtools_bridge;
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport android.net.LocalSocket;
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport android.net.LocalSocketAddress;
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.io.IOException;
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.Callable;
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.CountDownLatch;
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.ExecutorService;
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.Executors;
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.concurrent.Future;
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/**
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Utilities to testing a socket tunnel.
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipublic class TestUtils {
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    private static final String CHARSET = "UTF-8";
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Sends |request| string to UNIX socket socketName on another thread and returns
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Future<String> for obtainings response.
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public static Future<String> asyncRequest(final String socketName, final String request) {
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        final ExecutorService executor = Executors.newSingleThreadExecutor();
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return executor.submit(new Callable<String>() {
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            @Override
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            public String call() throws Exception {
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                LocalSocket socket = new LocalSocket();
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                socket.connect(new LocalSocketAddress(socketName));
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                writeAndShutdown(socket, request);
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                String response = readAll(socket);
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                socket.close();
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                executor.shutdown();
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                return response;
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            }
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       });
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public static void writeAndShutdown(LocalSocket socket, String data) throws IOException {
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        socket.getOutputStream().write(data.getBytes(CHARSET));
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        socket.getOutputStream().flush();
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        socket.shutdownOutput();
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Reads all bytes from socket input stream until EOF and converts it to UTF-8 string.
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public static String readAll(LocalSocket socket) throws IOException {
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        byte[] buffer = new byte[1000];
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        int position = 0;
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        while (true) {
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            int count = socket.getInputStream().read(buffer, position, buffer.length - position);
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            if (count == -1)
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                break;
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            position += count;
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return new String(buffer, 0, position, CHARSET);
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Utility class for thread synchronization. Allow to track moving through series of steps.
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public static class StateBarrier<T> {
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        private T mState;
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        private final Object mLock = new Object();
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        public StateBarrier(T initialState) {
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            mState = initialState;
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // Waits until state |from| reached and change state to |to|.
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        public void advance(T from, T to) {
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            synchronized (mLock) {
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                while (mState.equals(from)) {
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    try {
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        mLock.wait();
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    } catch (InterruptedException e) {
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        throw new RuntimeException(e);
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    }
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                }
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                mState = to;
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                mLock.notifyAll();
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            }
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Helper with runs code on another thread and synchronously take the result.
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public static class InvokeHelper<T> {
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        private final CountDownLatch mDone = new CountDownLatch(1);
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        private T mResult = null;
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        private Exception mException = null;
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        public void runOnTargetThread(Callable<T> callable) {
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            try {
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                mResult = callable.call();
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            } catch (Exception e) {
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                mException = e;
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            }
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            mDone.countDown();
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        public T takeResult() throws Exception {
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            mDone.await();
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            if (mException != null)
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                throw mException;
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            else
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                return mResult;
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Adapts Runnable to Callable<Void>.
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public static class RunnableAdapter implements Callable<Void> {
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        private final Runnable mAdaptee;
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        public RunnableAdapter(Runnable adaptee) {
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            mAdaptee = adaptee;
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        @Override
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        public Void call() {
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            mAdaptee.run();
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            return null;
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
135