From 19d2332d86acb090d475c52f7587b04d1e2ccfe5 Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Tue, 29 Jun 2021 21:41:53 -0300
Subject: [PATCH] Convert TorDemo into blocking and async bootstrap tests
And refactor TorIntegrationTest into AsyncBootstrapTest #2.
Note: Adding Tor bootstrapping tests add time to build.
To skip tests, run `$./gradlew clean build -x test`.
---
tor/src/test/java/network/misq/TorDemo.java | 219 -----------------
.../java/network/misq/TorIntegrationTest.java | 70 ------
.../network/misq/tor/AbstractTorTest.java | 228 ++++++++++++++++++
.../network/misq/tor/AsyncBootstrapTest.java | 98 ++++++++
.../misq/tor/BlockingBootstrapTest.java | 70 ++++++
5 files changed, 396 insertions(+), 289 deletions(-)
delete mode 100644 tor/src/test/java/network/misq/TorDemo.java
delete mode 100644 tor/src/test/java/network/misq/TorIntegrationTest.java
create mode 100644 tor/src/test/java/network/misq/tor/AbstractTorTest.java
create mode 100644 tor/src/test/java/network/misq/tor/AsyncBootstrapTest.java
create mode 100644 tor/src/test/java/network/misq/tor/BlockingBootstrapTest.java
diff --git a/tor/src/test/java/network/misq/TorDemo.java b/tor/src/test/java/network/misq/TorDemo.java
deleted file mode 100644
index 7917a96111..0000000000
--- a/tor/src/test/java/network/misq/TorDemo.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * This file is part of Bisq.
- *
- * Bisq is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Bisq is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Bisq. If not, see .
- */
-
-package network.misq;
-
-import com.runjva.sourceforge.jsocks.protocol.SocksSocket;
-import network.misq.common.util.OsUtils;
-import network.misq.tor.OnionAddress;
-import network.misq.tor.Tor;
-import network.misq.tor.TorServerSocket;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.net.SocketFactory;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.net.InetSocketAddress;
-import java.net.Proxy;
-import java.net.Socket;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class TorDemo {
- private static final Logger log = LoggerFactory.getLogger(TorDemo.class);
- private static Tor tor;
-
- public static void main(String[] args) throws InterruptedException {
- String torDirPath = OsUtils.getUserDataDir() + "/TorDemo";
- // useBlockingAPI(torDirPath);
- useNonBlockingAPI(torDirPath);
- }
-
- private static void useBlockingAPI(String torDirPath) {
- try {
- tor = Tor.getTor(torDirPath);
- tor.start();
- TorServerSocket torServerSocket = startServer();
- OnionAddress onionAddress = torServerSocket.getOnionAddress().get();
- sendViaSocketFactory(tor, onionAddress);
- sendViaProxy(tor, onionAddress);
- sendViaSocket(tor, onionAddress);
- sendViaSocksSocket(tor, onionAddress);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private static void useNonBlockingAPI(String torDirPath) throws InterruptedException {
- AtomicBoolean stopped = new AtomicBoolean(false);
- tor = Tor.getTor(torDirPath);
- CountDownLatch latch = new CountDownLatch(1);
- tor.startAsync()
- .thenCompose(result -> startServerAsync()
- .thenAccept(onionAddress -> {
- if (onionAddress == null) {
- return;
- }
-
- sendViaSocketFactory(tor, onionAddress);
- sendViaProxy(tor, onionAddress);
- sendViaSocket(tor, onionAddress);
- sendViaSocksSocket(tor, onionAddress);
- latch.countDown();
- }));
-
- latch.await(2, TimeUnit.MINUTES);
- }
-
- private static TorServerSocket startServer() throws IOException, InterruptedException {
- TorServerSocket torServerSocket = tor.getTorServerSocket();
- torServerSocket.bind(4000, 9999, "hiddenservice_2");
- runServer(torServerSocket);
- return torServerSocket;
- }
-
- private static CompletableFuture startServerAsync() {
- CompletableFuture future = new CompletableFuture<>();
- try {
- TorServerSocket torServerSocket = tor.getTorServerSocket();
- torServerSocket
- .bindAsync(3000, "hiddenservice_3")
- .whenComplete((onionAddress, throwable) -> {
- if (throwable == null) {
- runServer(torServerSocket);
- future.complete(onionAddress);
- } else {
- future.completeExceptionally(throwable);
- }
- });
- } catch (IOException e) {
- future.completeExceptionally(e);
- }
- return future;
- }
-
- private static void runServer(TorServerSocket torServerSocket) {
- new Thread(() -> {
- Thread.currentThread().setName("Server");
- while (true) {
- try {
- log.info("Start listening for new connections on {}", torServerSocket.getOnionAddress());
- Socket clientSocket = torServerSocket.accept();
- createInboundConnection(clientSocket);
- } catch (IOException e) {
- try {
- torServerSocket.close();
- } catch (IOException ignore) {
- }
- }
- }
- }).start();
- }
-
- private static void createInboundConnection(Socket clientSocket) {
- log.info("New client connection accepted");
- new Thread(() -> {
- Thread.currentThread().setName("Read at inbound connection");
- try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(clientSocket.getOutputStream());
- ObjectInputStream objectInputStream = new ObjectInputStream(clientSocket.getInputStream())) {
- objectOutputStream.flush();
- listenOnInputStream(clientSocket, objectInputStream, "inbound connection");
- } catch (IOException e) {
- try {
- clientSocket.close();
- } catch (IOException ignore) {
- }
- }
- }).start();
- }
-
- private static void listenOnInputStream(Socket socket, ObjectInputStream objectInputStream, String info) {
- try {
- while (!Thread.currentThread().isInterrupted()) {
- Object object = objectInputStream.readObject();
- log.info("Received at {} {}", info, object);
- }
- } catch (IOException | ClassNotFoundException e) {
- try {
- socket.close();
- } catch (IOException ignore) {
- }
- }
- }
-
- // Outbound connection
- private static void sendViaSocket(Tor tor, OnionAddress onionAddress) {
- try {
- Socket socket = tor.getSocket("test_stream_id");
- socket.connect(new InetSocketAddress(onionAddress.getHost(), onionAddress.getPort()));
- sendOnOutboundConnection(socket, "test via Socket");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- private static void sendViaSocksSocket(Tor tor, OnionAddress onionAddress) {
- try {
- SocksSocket socket = tor.getSocksSocket(onionAddress.getHost(), onionAddress.getPort(), "test_stream_id");
- sendOnOutboundConnection(socket, "test via SocksSocket");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- private static void sendViaSocketFactory(Tor tor, OnionAddress onionAddress) {
- try {
- SocketFactory socketFactory = tor.getSocketFactory("test_stream_id");
- Socket socket = socketFactory.createSocket(onionAddress.getHost(), onionAddress.getPort());
- sendOnOutboundConnection(socket, "test via SocketFactory");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- private static void sendViaProxy(Tor tor, OnionAddress onionAddress) {
- try {
- Proxy proxy = tor.getProxy("test_stream_id");
- Socket socket = new Socket(proxy);
- socket.connect(new InetSocketAddress(onionAddress.getHost(), onionAddress.getPort()));
- sendOnOutboundConnection(socket, "test via Proxy");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- private static void sendOnOutboundConnection(Socket socket, String msg) {
- log.info("sendViaOutboundConnection {}", msg);
- new Thread(() -> {
- try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
- ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {
- objectOutputStream.writeObject(msg);
- objectOutputStream.flush();
- listenOnInputStream(socket, objectInputStream, "outbound connection");
- } catch (IOException e) {
- try {
- socket.close();
- } catch (IOException ignore) {
- }
- }
- }).start();
- }
-}
diff --git a/tor/src/test/java/network/misq/TorIntegrationTest.java b/tor/src/test/java/network/misq/TorIntegrationTest.java
deleted file mode 100644
index b3d5f0dfd4..0000000000
--- a/tor/src/test/java/network/misq/TorIntegrationTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * This file is part of Bisq.
- *
- * Bisq is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Bisq is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Bisq. If not, see .
- */
-
-package network.misq;
-
-import network.misq.common.util.FileUtils;
-import network.misq.common.util.OsUtils;
-import network.misq.tor.Constants;
-import network.misq.tor.Tor;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.fail;
-
-
-public class TorIntegrationTest {
- private static final Logger log = LoggerFactory.getLogger(TorIntegrationTest.class);
-
- @Test
- public void testShutdownDuringStartup() {
- String torDirPath = OsUtils.getUserDataDir() + "/TorifyIntegrationTest";
- File versionFile = new File(torDirPath + "/" + Constants.VERSION);
- FileUtils.deleteDirectory(new File(torDirPath));
- assertFalse(versionFile.exists());
- Tor tor = Tor.getTor(torDirPath);
- new Thread(() -> {
- try {
- Thread.sleep(200);
- } catch (InterruptedException ignore) {
- }
- tor.shutdown();
-
- }).start();
- Thread mainThread = Thread.currentThread();
- tor.startAsync()
- .exceptionally(throwable -> {
- assertFalse(versionFile.exists());
- mainThread.interrupt();
- return null;
- })
- .thenAccept(result -> {
- if (result == null) {
- return;
- }
- fail();
- });
- try {
- Thread.sleep(2000);
- } catch (InterruptedException ignore) {
- }
- }
-}
diff --git a/tor/src/test/java/network/misq/tor/AbstractTorTest.java b/tor/src/test/java/network/misq/tor/AbstractTorTest.java
new file mode 100644
index 0000000000..7c1782c084
--- /dev/null
+++ b/tor/src/test/java/network/misq/tor/AbstractTorTest.java
@@ -0,0 +1,228 @@
+package network.misq.tor;
+
+
+import com.runjva.sourceforge.jsocks.protocol.SocksSocket;
+import lombok.extern.slf4j.Slf4j;
+import network.misq.common.util.FileUtils;
+import network.misq.common.util.OsUtils;
+
+import javax.net.SocketFactory;
+import java.io.*;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+import static java.lang.String.format;
+import static network.misq.tor.Constants.VERSION;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.fail;
+
+@Slf4j
+abstract class AbstractTorTest {
+
+ private static final String TEST_STREAM_ID = "test_stream_id";
+
+ private enum ConnectionType {
+ INBOUND,
+ OUTBOUND
+ }
+
+ protected static Tor tor;
+ protected static TorServerSocket torServerSocket;
+ protected static OnionAddress onionAddress;
+ protected static boolean isShutdown = false;
+ protected static String expectedMessage;
+
+ protected final Supplier torTestDirPathSpec = () ->
+ OsUtils.getUserDataDir() + File.separator + this.getClass().getSimpleName();
+ protected final Predicate isClassNotFoundException = (ex) -> ex instanceof ClassNotFoundException;
+ protected final Predicate isEOFException = (ex) -> ex instanceof EOFException;
+ protected final Predicate isSocketClosedException = (ex) ->
+ ex instanceof SocketException && ex.getMessage().equals("Socket closed");
+
+ public static void cleanTorInstallDir(String torDirPathSpec) {
+ File torDir = new File(torDirPathSpec);
+ if (torDir.exists()) {
+ log.info("Cleaning tor install dir {}", torDirPathSpec);
+ FileUtils.deleteDirectory(torDir);
+ }
+ File versionFile = new File(torDir, VERSION);
+ assertFalse(versionFile.exists());
+ }
+
+ protected TorServerSocket startServer() throws IOException, InterruptedException {
+ TorServerSocket torServerSocket = tor.getTorServerSocket();
+ torServerSocket.bind(4000, 9999, "hiddenservice_2");
+ runServer(torServerSocket);
+ return torServerSocket;
+ }
+
+ protected CompletableFuture startServerAsync() {
+ CompletableFuture future = new CompletableFuture<>();
+ try {
+ TorServerSocket torServerSocket = tor.getTorServerSocket();
+ torServerSocket
+ .bindAsync(3000, "hiddenservice_3")
+ .whenComplete((onionAddress, throwable) -> {
+ if (throwable == null) {
+ runServer(torServerSocket);
+ future.complete(onionAddress);
+ } else {
+ future.completeExceptionally(throwable);
+ }
+ });
+ } catch (IOException e) {
+ future.completeExceptionally(e);
+ }
+ return future;
+ }
+
+ protected void runServer(TorServerSocket torServerSocket) {
+ new Thread(() -> {
+ Thread.currentThread().setName("Server");
+ while (true) {
+ try {
+ log.info("Start listening for connections on {}.", torServerSocket.getOnionAddress());
+ Socket clientSocket = torServerSocket.accept();
+ createInboundConnection(clientSocket);
+ } catch (IOException ex) {
+ try {
+ if (isShutdown && isSocketClosedException.test(ex)) {
+ log.info("Socket already closed prior to Tor shutdown.");
+ return;
+ } else {
+ torServerSocket.close();
+ fail(ex);
+ }
+ } catch (IOException ignore) {
+ // empty
+ }
+ }
+ }
+ }).start();
+ }
+
+ protected void createInboundConnection(Socket clientSocket) {
+ log.info("New client connection accepted");
+ new Thread(() -> {
+ Thread.currentThread().setName("Read at inbound connection");
+ try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(clientSocket.getOutputStream());
+ ObjectInputStream objectInputStream = new ObjectInputStream(clientSocket.getInputStream())) {
+ objectOutputStream.flush();
+
+ // listenOnInputStream(clientSocket, objectInputStream, "inbound connection");
+ listenOnInputStream(clientSocket, objectInputStream, ConnectionType.INBOUND);
+
+ } catch (IOException ex) {
+ try {
+ clientSocket.close();
+ if (!isEOFException.test(ex))
+ fail(ex);
+ } catch (IOException ignore) {
+ // empty
+ }
+ }
+ }).start();
+ }
+
+ protected void listenOnInputStream(Socket socket,
+ ObjectInputStream objectInputStream,
+ ConnectionType connectionType) {
+ try {
+ while (!Thread.currentThread().isInterrupted()) {
+ Object message = objectInputStream.readObject();
+ log.info("Received '{}' on {} connection.",
+ message,
+ connectionType.name().toLowerCase());
+ if (connectionType.equals(ConnectionType.INBOUND)) {
+ if (!message.equals(expectedMessage)) {
+ fail(format("Did not read expected message from input stream. Was '%s', expected '%s'",
+ expectedMessage,
+ message));
+ }
+ }
+ }
+ } catch (ClassNotFoundException | IOException ex) {
+ closeClientSocketOnException(socket, ex);
+ }
+ }
+
+ private void closeClientSocketOnException(Socket socket, Exception exception) {
+ try {
+ socket.close();
+ } catch (IOException ignored) {
+ // empty
+ }
+ if (!isEOFException.test(exception) || isClassNotFoundException.test(exception))
+ fail(exception);
+ }
+
+ // Outbound Connection
+
+ protected void sendViaSocket(Tor tor, OnionAddress onionAddress) {
+ try {
+ Socket socket = tor.getSocket(TEST_STREAM_ID);
+ socket.connect(new InetSocketAddress(onionAddress.getHost(), onionAddress.getPort()));
+ sendOnOutboundConnection(socket, "Message via Socket");
+ } catch (IOException ex) {
+ fail(ex);
+ }
+ }
+
+ protected void sendViaSocksSocket(Tor tor, OnionAddress onionAddress) {
+ try {
+ SocksSocket socket = tor.getSocksSocket(onionAddress.getHost(), onionAddress.getPort(), TEST_STREAM_ID);
+ sendOnOutboundConnection(socket, "Message via SocksSocket");
+ } catch (IOException ex) {
+ fail(ex);
+ }
+ }
+
+ protected void sendViaSocketFactory(Tor tor, OnionAddress onionAddress) {
+ try {
+ SocketFactory socketFactory = tor.getSocketFactory(TEST_STREAM_ID);
+ Socket socket = socketFactory.createSocket(onionAddress.getHost(), onionAddress.getPort());
+ sendOnOutboundConnection(socket, "Message via SocketFactory");
+ } catch (IOException ex) {
+ fail(ex);
+ }
+ }
+
+ protected void sendViaProxy(Tor tor, OnionAddress onionAddress) {
+ try {
+ Proxy proxy = tor.getProxy(TEST_STREAM_ID);
+ Socket socket = new Socket(proxy);
+ socket.connect(new InetSocketAddress(onionAddress.getHost(), onionAddress.getPort()));
+ sendOnOutboundConnection(socket, "Message via Proxy");
+ } catch (IOException ex) {
+ fail(ex);
+ }
+ }
+
+ protected void sendOnOutboundConnection(Socket socket, String message) {
+ log.info("sendOnOutboundConnection: '{}'", message);
+ new Thread(() -> {
+ try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
+ ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {
+ objectOutputStream.writeObject(message);
+ objectOutputStream.flush();
+
+ expectedMessage = message;
+ listenOnInputStream(socket, objectInputStream, ConnectionType.OUTBOUND);
+
+ } catch (IOException ex) {
+ try {
+ socket.close();
+ if (!isEOFException.test(ex))
+ fail(ex);
+ } catch (IOException ignore) {
+ // empty
+ }
+ }
+ }).start();
+ }
+}
diff --git a/tor/src/test/java/network/misq/tor/AsyncBootstrapTest.java b/tor/src/test/java/network/misq/tor/AsyncBootstrapTest.java
new file mode 100644
index 0000000000..a6dfc58fdc
--- /dev/null
+++ b/tor/src/test/java/network/misq/tor/AsyncBootstrapTest.java
@@ -0,0 +1,98 @@
+package network.misq.tor;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static network.misq.tor.Constants.VERSION;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.fail;
+
+@Slf4j
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class AsyncBootstrapTest extends AbstractTorTest {
+
+ @Test
+ @Order(1)
+ public void testAsyncBootstrap() {
+ try {
+ String torDirPathSpec = torTestDirPathSpec.get();
+ cleanTorInstallDir(torDirPathSpec);
+ tor = Tor.getTor(torDirPathSpec);
+
+ CountDownLatch latch = new CountDownLatch(1);
+ tor.startAsync()
+ .thenCompose(result -> startServerAsync()
+ .thenAccept(onionAddress -> {
+ if (onionAddress == null) {
+ return;
+ }
+ sendViaSocketFactory(tor, onionAddress);
+ sendViaProxy(tor, onionAddress);
+ sendViaSocket(tor, onionAddress);
+ sendViaSocksSocket(tor, onionAddress);
+ latch.countDown();
+ }));
+ //noinspection ResultOfMethodCallIgnored
+ latch.await(2, MINUTES);
+
+ shutdownTor();
+ } catch (InterruptedException ignored) {
+ // empty
+ }
+ }
+
+ @Test
+ @Order(2)
+ public void testShutdownDuringStartup() {
+ String torDirPathSpec = torTestDirPathSpec.get();
+ cleanTorInstallDir(torDirPathSpec);
+ tor = Tor.getTor(torDirPathSpec);
+
+ new Thread(() -> {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException ignored) {
+ // empty
+ }
+ tor.shutdown();
+ }).start();
+
+ Thread mainThread = Thread.currentThread();
+ tor.startAsync()
+ .exceptionally(throwable -> {
+ File versionFile = new File(torDirPathSpec + File.separator + VERSION);
+ assertFalse(versionFile.exists());
+ mainThread.interrupt();
+ return null;
+ })
+ .thenAccept(result -> {
+ if (result == null) {
+ return;
+ }
+ fail();
+ });
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ignored) {
+ // empty
+ }
+ }
+
+ private void shutdownTor() {
+ try {
+ isShutdown = true;
+ tor.getTorServerSocket().close();
+ tor.shutdown();
+ } catch (IOException ex) {
+ fail("Error during Tor shutdown.", ex);
+ }
+ }
+}
diff --git a/tor/src/test/java/network/misq/tor/BlockingBootstrapTest.java b/tor/src/test/java/network/misq/tor/BlockingBootstrapTest.java
new file mode 100644
index 0000000000..8077c9cc52
--- /dev/null
+++ b/tor/src/test/java/network/misq/tor/BlockingBootstrapTest.java
@@ -0,0 +1,70 @@
+package network.misq.tor;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.*;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.fail;
+
+@Slf4j
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class BlockingBootstrapTest extends AbstractTorTest {
+
+ @Test
+ @Order(1)
+ public void testBlockingBootstrap() {
+ try {
+ String torDirPathSpec = torTestDirPathSpec.get();
+ cleanTorInstallDir(torDirPathSpec);
+
+ tor = Tor.getTor(torDirPathSpec);
+ tor.start();
+ torServerSocket = startServer();
+ onionAddress = torServerSocket.getOnionAddress()
+ .orElseThrow(() -> new IllegalStateException("Could not get onion address from tor server socket."));
+ } catch (IOException ex) {
+ fail(ex);
+ } catch (InterruptedException ignored) {
+ // empty
+ }
+ }
+
+ @Test
+ @Order(2)
+ public void testSendMessageViaSocketFactory() {
+ sendViaSocketFactory(tor, onionAddress);
+ }
+
+ @Test
+ @Order(3)
+ public void testSendMessageViaProxy() {
+ sendViaProxy(tor, onionAddress);
+ }
+
+ @Test
+ @Order(4)
+ public void testSendMessageViaSocket() {
+ sendViaSocket(tor, onionAddress);
+ }
+
+ @Test
+ @Order(5)
+ public void testSendMessageViaSocksSocket() {
+ sendViaSocksSocket(tor, onionAddress);
+ }
+
+ @AfterAll
+ public static void shutdownTor() {
+ try {
+ Thread.sleep(5000);
+ isShutdown = true;
+ torServerSocket.close();
+ tor.shutdown();
+ } catch (IOException ex) {
+ fail("Error during Tor shutdown.", ex);
+ } catch (InterruptedException ignored) {
+ // empty
+ }
+ }
+}