diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 966457e8e..2f93054bf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -107,6 +107,10 @@ bridge test: mailbox integration test: extends: .optional_tests rules: + - changes: + - mailbox-integration-tests/**/* + when: on_success + allow_failure: false - if: '$CI_PIPELINE_SOURCE == "schedule"' when: on_success - if: '$CI_COMMIT_TAG == null' diff --git a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java index 5be846f61..7859bd652 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/BrambleAndroidModule.java @@ -9,6 +9,7 @@ import org.briarproject.bramble.socks.SocksModule; import org.briarproject.bramble.system.AndroidSystemModule; import org.briarproject.bramble.system.AndroidTaskSchedulerModule; import org.briarproject.bramble.system.AndroidWakefulIoExecutorModule; +import org.briarproject.bramble.system.DefaultThreadFactoryModule; import dagger.Module; @@ -18,6 +19,7 @@ import dagger.Module; AndroidSystemModule.class, AndroidTaskSchedulerModule.class, AndroidWakefulIoExecutorModule.class, + DefaultThreadFactoryModule.class, CircumventionModule.class, DnsModule.class, ReportingModule.class, diff --git a/bramble-core/src/main/java/org/briarproject/bramble/TimeLoggingExecutor.java b/bramble-core/src/main/java/org/briarproject/bramble/TimeLoggingExecutor.java index dc0b96d3d..3513b5f54 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/TimeLoggingExecutor.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/TimeLoggingExecutor.java @@ -4,6 +4,7 @@ import org.briarproject.nullsafety.NotNullByDefault; import java.util.concurrent.BlockingQueue; import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; @@ -19,9 +20,10 @@ public class TimeLoggingExecutor extends ThreadPoolExecutor { public TimeLoggingExecutor(String tag, int corePoolSize, int maxPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, + ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue, - handler); + threadFactory, handler); log = Logger.getLogger(tag); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoExecutorModule.java b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoExecutorModule.java index ab0e4114f..7a069b2eb 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoExecutorModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/crypto/CryptoExecutorModule.java @@ -9,6 +9,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import javax.inject.Inject; @@ -37,31 +38,31 @@ public class CryptoExecutorModule { private static final int MAX_EXECUTOR_THREADS = Math.max(1, Runtime.getRuntime().availableProcessors() - 1); - private final ExecutorService cryptoExecutor; - public CryptoExecutorModule() { - // Use an unbounded queue - BlockingQueue queue = new LinkedBlockingQueue<>(); - // Discard tasks that are submitted during shutdown - RejectedExecutionHandler policy = - new ThreadPoolExecutor.DiscardPolicy(); - // Create a limited # of threads and keep them in the pool for 60 secs - cryptoExecutor = new TimeLoggingExecutor("CryptoExecutor", 0, - MAX_EXECUTOR_THREADS, 60, SECONDS, queue, policy); } @Provides @Singleton @CryptoExecutor ExecutorService provideCryptoExecutorService( - LifecycleManager lifecycleManager) { + LifecycleManager lifecycleManager, ThreadFactory threadFactory) { + // Use an unbounded queue + BlockingQueue queue = new LinkedBlockingQueue<>(); + // Discard tasks that are submitted during shutdown + RejectedExecutionHandler policy = + new ThreadPoolExecutor.DiscardPolicy(); + // Create a limited # of threads and keep them in the pool for 60 secs + ExecutorService cryptoExecutor = new TimeLoggingExecutor( + "CryptoExecutor", 0, MAX_EXECUTOR_THREADS, 60, SECONDS, queue, + threadFactory, policy); lifecycleManager.registerForShutdown(cryptoExecutor); return cryptoExecutor; } @Provides @CryptoExecutor - Executor provideCryptoExecutor() { + Executor provideCryptoExecutor( + @CryptoExecutor ExecutorService cryptoExecutor) { return cryptoExecutor; } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseExecutorModule.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseExecutorModule.java index a65feef89..73b26710a 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseExecutorModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseExecutorModule.java @@ -9,6 +9,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import javax.inject.Inject; @@ -28,24 +29,20 @@ public class DatabaseExecutorModule { ExecutorService executorService; } - private final ExecutorService databaseExecutor; - - public DatabaseExecutorModule() { + @Provides + @Singleton + @DatabaseExecutor + ExecutorService provideDatabaseExecutorService( + LifecycleManager lifecycleManager, ThreadFactory threadFactory) { // Use an unbounded queue BlockingQueue queue = new LinkedBlockingQueue<>(); // Discard tasks that are submitted during shutdown RejectedExecutionHandler policy = new ThreadPoolExecutor.DiscardPolicy(); // Use a single thread and keep it in the pool for 60 secs - databaseExecutor = new TimeLoggingExecutor("DatabaseExecutor", 0, 1, - 60, SECONDS, queue, policy); - } - - @Provides - @Singleton - @DatabaseExecutor - ExecutorService provideDatabaseExecutorService( - LifecycleManager lifecycleManager) { + ExecutorService databaseExecutor = new TimeLoggingExecutor( + "DatabaseExecutor", 0, 1, 60, SECONDS, queue, threadFactory, + policy); lifecycleManager.registerForShutdown(databaseExecutor); return databaseExecutor; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/event/DefaultEventExecutorModule.java b/bramble-core/src/main/java/org/briarproject/bramble/event/DefaultEventExecutorModule.java index 5fc21cc86..2d43800c1 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/event/DefaultEventExecutorModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/event/DefaultEventExecutorModule.java @@ -3,6 +3,7 @@ package org.briarproject.bramble.event; import org.briarproject.bramble.api.event.EventExecutor; import java.util.concurrent.Executor; +import java.util.concurrent.ThreadFactory; import javax.inject.Singleton; @@ -22,10 +23,11 @@ public class DefaultEventExecutorModule { @Provides @Singleton @EventExecutor - Executor provideEventExecutor() { + Executor provideEventExecutor(ThreadFactory threadFactory) { return newSingleThreadExecutor(r -> { - Thread t = new Thread(r); + Thread t = threadFactory.newThread(r); t.setDaemon(true); + t.setName(t.getName() + "-Event"); return t; }); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleModule.java b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleModule.java index 43db266ef..b38f79b1c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/lifecycle/LifecycleModule.java @@ -9,6 +9,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import javax.inject.Inject; @@ -28,19 +29,6 @@ public class LifecycleModule { Executor executor; } - private final ExecutorService ioExecutor; - - public LifecycleModule() { - // The thread pool is unbounded, so use direct handoff - BlockingQueue queue = new SynchronousQueue<>(); - // Discard tasks that are submitted during shutdown - RejectedExecutionHandler policy = - new ThreadPoolExecutor.DiscardPolicy(); - // Create threads as required and keep them in the pool for 60 seconds - ioExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, - 60, SECONDS, queue, policy); - } - @Provides @Singleton ShutdownManager provideShutdownManager() { @@ -57,7 +45,16 @@ public class LifecycleModule { @Provides @Singleton @IoExecutor - Executor provideIoExecutor(LifecycleManager lifecycleManager) { + Executor provideIoExecutor(LifecycleManager lifecycleManager, + ThreadFactory threadFactory) { + // The thread pool is unbounded, so use direct handoff + BlockingQueue queue = new SynchronousQueue<>(); + // Discard tasks that are submitted during shutdown + RejectedExecutionHandler policy = + new ThreadPoolExecutor.DiscardPolicy(); + // Create threads as required and keep them in the pool for 60 seconds + ExecutorService ioExecutor = new ThreadPoolExecutor(0, + Integer.MAX_VALUE, 60, SECONDS, queue, threadFactory, policy); lifecycleManager.registerForShutdown(ioExecutor); return ioExecutor; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiCallerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiCallerImpl.java index ce08b2f25..368c7ed7c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiCallerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApiCallerImpl.java @@ -20,12 +20,15 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; class MailboxApiCallerImpl implements MailboxApiCaller { private final TaskScheduler taskScheduler; + private final MailboxConfig mailboxConfig; private final Executor ioExecutor; @Inject MailboxApiCallerImpl(TaskScheduler taskScheduler, + MailboxConfig mailboxConfig, @IoExecutor Executor ioExecutor) { this.taskScheduler = taskScheduler; + this.mailboxConfig = mailboxConfig; this.ioExecutor = ioExecutor; } @@ -49,7 +52,8 @@ class MailboxApiCallerImpl implements MailboxApiCaller { private boolean cancelled = false; @GuardedBy("lock") - private long retryIntervalMs = MIN_RETRY_INTERVAL_MS; + private long retryIntervalMs = + mailboxConfig.getApiCallerMinRetryInterval(); private Task(ApiCall apiCall) { this.apiCall = apiCall; @@ -74,8 +78,9 @@ class MailboxApiCallerImpl implements MailboxApiCaller { scheduledTask = taskScheduler.schedule(this::callApi, ioExecutor, retryIntervalMs, MILLISECONDS); // Increase the retry interval each time we retry - retryIntervalMs = - min(MAX_RETRY_INTERVAL_MS, retryIntervalMs * 2); + retryIntervalMs = min( + mailboxConfig.getApiCallerMaxRetryInterval(), + retryIntervalMs * 2); } } else { synchronized (lock) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxConfig.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxConfig.java new file mode 100644 index 000000000..7f03dff6d --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxConfig.java @@ -0,0 +1,24 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.bramble.api.plugin.Plugin; + +interface MailboxConfig { + + /** + * The minimum interval between API call retries in milliseconds. + */ + long getApiCallerMinRetryInterval(); + + /** + * The maximum interval between API call retries in milliseconds. + */ + long getApiCallerMaxRetryInterval(); + + /** + * How long (in milliseconds) the Tor plugin needs to be continuously + * {@link Plugin.State#ACTIVE active} before we assume our contacts can + * reach our hidden service. + */ + long getTorReachabilityPeriod(); + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxConfigImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxConfigImpl.java new file mode 100644 index 000000000..fa6a1f528 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxConfigImpl.java @@ -0,0 +1,30 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +@Immutable +@NotNullByDefault +class MailboxConfigImpl implements MailboxConfig { + + @Inject + MailboxConfigImpl() { + } + + @Override + public long getApiCallerMinRetryInterval() { + return MailboxApiCaller.MIN_RETRY_INTERVAL_MS; + } + + @Override + public long getApiCallerMaxRetryInterval() { + return MailboxApiCaller.MAX_RETRY_INTERVAL_MS; + } + + @Override + public long getTorReachabilityPeriod() { + return TorReachabilityMonitor.REACHABILITY_PERIOD_MS; + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/UrlConverterModule.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/ModularMailboxModule.java similarity index 58% rename from bramble-core/src/main/java/org/briarproject/bramble/mailbox/UrlConverterModule.java rename to bramble-core/src/main/java/org/briarproject/bramble/mailbox/ModularMailboxModule.java index cc9d44698..8ddbd7824 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/UrlConverterModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/ModularMailboxModule.java @@ -4,7 +4,11 @@ import dagger.Module; import dagger.Provides; @Module -public class UrlConverterModule { +public class ModularMailboxModule { + @Provides + MailboxConfig provideMailboxConfig(MailboxConfigImpl mailboxConfig) { + return mailboxConfig; + } @Provides UrlConverter provideUrlConverter(UrlConverterImpl urlConverter) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/TorReachabilityMonitorImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/TorReachabilityMonitorImpl.java index 359e70460..20afebe30 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/TorReachabilityMonitorImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/TorReachabilityMonitorImpl.java @@ -32,6 +32,7 @@ class TorReachabilityMonitorImpl private final Executor ioExecutor; private final TaskScheduler taskScheduler; + private final MailboxConfig mailboxConfig; private final PluginManager pluginManager; private final EventBus eventBus; private final Object lock = new Object(); @@ -50,10 +51,12 @@ class TorReachabilityMonitorImpl TorReachabilityMonitorImpl( @IoExecutor Executor ioExecutor, TaskScheduler taskScheduler, + MailboxConfig mailboxConfig, PluginManager pluginManager, EventBus eventBus) { this.ioExecutor = ioExecutor; this.taskScheduler = taskScheduler; + this.mailboxConfig = mailboxConfig; this.pluginManager = pluginManager; this.eventBus = eventBus; } @@ -110,7 +113,7 @@ class TorReachabilityMonitorImpl synchronized (lock) { if (destroyed || task != null) return; task = taskScheduler.schedule(this::onTorReachable, ioExecutor, - REACHABILITY_PERIOD_MS, MILLISECONDS); + mailboxConfig.getTorReachabilityPeriod(), MILLISECONDS); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/system/DefaultTaskSchedulerModule.java b/bramble-core/src/main/java/org/briarproject/bramble/system/DefaultTaskSchedulerModule.java index 3e36faff2..30e473237 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/system/DefaultTaskSchedulerModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/system/DefaultTaskSchedulerModule.java @@ -6,6 +6,7 @@ import org.briarproject.bramble.api.system.TaskScheduler; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; import javax.inject.Inject; import javax.inject.Singleton; @@ -21,18 +22,15 @@ public class DefaultTaskSchedulerModule { TaskScheduler scheduler; } - private final ScheduledExecutorService scheduledExecutorService; - - public DefaultTaskSchedulerModule() { + @Provides + @Singleton + TaskScheduler provideTaskScheduler(LifecycleManager lifecycleManager, + ThreadFactory threadFactory) { // Discard tasks that are submitted during shutdown RejectedExecutionHandler policy = new ScheduledThreadPoolExecutor.DiscardPolicy(); - scheduledExecutorService = new ScheduledThreadPoolExecutor(1, policy); - } - - @Provides - @Singleton - TaskScheduler provideTaskScheduler(LifecycleManager lifecycleManager) { + ScheduledExecutorService scheduledExecutorService = + new ScheduledThreadPoolExecutor(1, threadFactory, policy); lifecycleManager.registerForShutdown(scheduledExecutorService); return new TaskSchedulerImpl(scheduledExecutorService); } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/system/DefaultThreadFactoryModule.java b/bramble-core/src/main/java/org/briarproject/bramble/system/DefaultThreadFactoryModule.java new file mode 100644 index 000000000..d2ea5f976 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/system/DefaultThreadFactoryModule.java @@ -0,0 +1,18 @@ +package org.briarproject.bramble.system; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class DefaultThreadFactoryModule { + @Provides + @Singleton + ThreadFactory provideThreadFactory() { + return Executors.defaultThreadFactory(); + } +} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactExchangeIntegrationTestComponent.java b/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactExchangeIntegrationTestComponent.java index becb74db8..f01e365f1 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactExchangeIntegrationTestComponent.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactExchangeIntegrationTestComponent.java @@ -9,7 +9,7 @@ import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.LifecycleManager; -import org.briarproject.bramble.mailbox.UrlConverterModule; +import org.briarproject.bramble.mailbox.ModularMailboxModule; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; import org.briarproject.bramble.test.TestDnsModule; import org.briarproject.bramble.test.TestPluginConfigModule; @@ -25,7 +25,7 @@ import dagger.Component; @Component(modules = { BrambleCoreIntegrationTestModule.class, BrambleCoreModule.class, - UrlConverterModule.class, + ModularMailboxModule.class, TestDnsModule.class, TestSocksModule.class, TestPluginConfigModule.class, diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiCallerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiCallerImplTest.java index 2612fe16a..b625a94a8 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiCallerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiCallerImplTest.java @@ -21,12 +21,13 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase { private final TaskScheduler taskScheduler = context.mock(TaskScheduler.class); + private final MailboxConfig mailboxConfig = new MailboxConfigImpl(); private final Executor ioExecutor = context.mock(Executor.class); private final ApiCall apiCall = context.mock(ApiCall.class); private final Cancellable scheduledTask = context.mock(Cancellable.class); private final MailboxApiCallerImpl caller = - new MailboxApiCallerImpl(taskScheduler, ioExecutor); + new MailboxApiCallerImpl(taskScheduler, mailboxConfig, ioExecutor); @Test public void testSubmitsTaskImmediately() { diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiTest.java index 3b46320c8..aeaaccbaf 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxApiTest.java @@ -24,9 +24,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.annotation.Nonnull; -import javax.net.SocketFactory; - import okhttp3.OkHttpClient; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -34,8 +31,8 @@ import okhttp3.mockwebserver.RecordedRequest; import okio.Buffer; import static java.util.Collections.singletonList; -import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS; +import static org.briarproject.bramble.mailbox.MailboxTestUtils.createHttpClientProvider; import static org.briarproject.bramble.test.TestUtils.getContactId; import static org.briarproject.bramble.test.TestUtils.getMailboxProperties; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; @@ -56,18 +53,8 @@ public class MailboxApiTest extends BrambleTestCase { @Rule public TemporaryFolder folder = new TemporaryFolder(); - private final OkHttpClient client = new OkHttpClient.Builder() - .socketFactory(SocketFactory.getDefault()) - .connectTimeout(60_000, MILLISECONDS) - .build(); private final WeakSingletonProvider httpClientProvider = - new WeakSingletonProvider() { - @Override - @Nonnull - public OkHttpClient createInstance() { - return client; - } - }; + createHttpClientProvider(); // We aren't using a real onion address, so use the given address verbatim private final UrlConverter urlConverter = onion -> onion; private final MailboxApiImpl api = new MailboxApiImpl(httpClientProvider, diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java index 6a3e312ed..fbc817d3f 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java @@ -22,13 +22,12 @@ import org.jmock.Expectations; import org.junit.Test; import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; import static java.util.Collections.singletonList; +import static org.briarproject.bramble.mailbox.MailboxTestUtils.getQrCodePayload; import static org.briarproject.bramble.test.TestUtils.getContact; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; @@ -59,7 +58,8 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { new MailboxAuthToken(getRandomId()); private final MailboxAuthToken ownerToken = new MailboxAuthToken(getRandomId()); - private final String validPayload = getValidPayload(); + private final String validPayload = + getQrCodePayload(onionBytes, setupToken.getBytes()); private final long time = System.currentTimeMillis(); private final MailboxProperties setupProperties = new MailboxProperties( onion, setupToken, new ArrayList<>()); @@ -194,16 +194,6 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { MailboxPairingState.UnexpectedError.class)); } - private String getValidPayload() { - byte[] payloadBytes = ByteBuffer.allocate(65) - .put((byte) 32) // 1 - .put(onionBytes) // 32 - .put(setupToken.getBytes()) // 32 - .array(); - //noinspection CharsetObjectCanBeUsed - return new String(payloadBytes, Charset.forName("ISO-8859-1")); - } - private PredicateMatcher matches(MailboxProperties p2) { return new PredicateMatcher<>(MailboxProperties.class, p1 -> p1.getAuthToken().equals(p2.getAuthToken()) && diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxTestUtils.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxTestUtils.java new file mode 100644 index 000000000..4795fb739 --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxTestUtils.java @@ -0,0 +1,44 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.bramble.api.WeakSingletonProvider; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +import javax.annotation.Nonnull; +import javax.net.SocketFactory; + +import okhttp3.OkHttpClient; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.briarproject.bramble.test.TestUtils.getRandomId; + +class MailboxTestUtils { + + static String getQrCodePayload(byte[] onionBytes, byte[] setupToken) { + byte[] payloadBytes = ByteBuffer.allocate(65) + .put((byte) 32) // 1 + .put(onionBytes) // 32 + .put(setupToken) // 32 + .array(); + //noinspection CharsetObjectCanBeUsed + return new String(payloadBytes, Charset.forName("ISO-8859-1")); + } + + static String getQrCodePayload(byte[] setupToken) { + return getQrCodePayload(getRandomId(), setupToken); + } + + static WeakSingletonProvider createHttpClientProvider() { + return new WeakSingletonProvider() { + @Override + @Nonnull + public OkHttpClient createInstance() { + return new OkHttpClient.Builder() + .socketFactory(SocketFactory.getDefault()) + .connectTimeout(60_000, MILLISECONDS) + .build(); + } + }; + } +} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/TorReachabilityMonitorImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/TorReachabilityMonitorImplTest.java index 032095cd6..547041a1f 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/TorReachabilityMonitorImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/TorReachabilityMonitorImplTest.java @@ -29,6 +29,7 @@ public class TorReachabilityMonitorImplTest extends BrambleMockTestCase { private final Executor ioExecutor = context.mock(Executor.class); private final TaskScheduler taskScheduler = context.mock(TaskScheduler.class); + private final MailboxConfig mailboxConfig = new MailboxConfigImpl(); private final PluginManager pluginManager = context.mock(PluginManager.class); private final EventBus eventBus = context.mock(EventBus.class); @@ -39,7 +40,7 @@ public class TorReachabilityMonitorImplTest extends BrambleMockTestCase { private final TorReachabilityMonitorImpl monitor = new TorReachabilityMonitorImpl(ioExecutor, taskScheduler, - pluginManager, eventBus); + mailboxConfig, pluginManager, eventBus); @Test public void testSchedulesTaskWhenStartedIfTorIsActive() { diff --git a/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTestComponent.java b/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTestComponent.java index 59435bdb0..6a071e2de 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTestComponent.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTestComponent.java @@ -9,7 +9,8 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.plugin.file.RemovableDriveManager; import org.briarproject.bramble.battery.DefaultBatteryManagerModule; import org.briarproject.bramble.event.DefaultEventExecutorModule; -import org.briarproject.bramble.mailbox.UrlConverterModule; +import org.briarproject.bramble.mailbox.ModularMailboxModule; +import org.briarproject.bramble.system.DefaultThreadFactoryModule; import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule; import org.briarproject.bramble.system.TimeTravelModule; import org.briarproject.bramble.test.TestDatabaseConfigModule; @@ -29,13 +30,14 @@ import dagger.Component; DefaultBatteryManagerModule.class, DefaultEventExecutorModule.class, DefaultWakefulIoExecutorModule.class, + DefaultThreadFactoryModule.class, TestDatabaseConfigModule.class, TestDnsModule.class, TestFeatureFlagModule.class, TestMailboxDirectoryModule.class, RemovableDriveIntegrationTestModule.class, RemovableDriveModule.class, - UrlConverterModule.class, + ModularMailboxModule.class, TestSecureRandomModule.class, TimeTravelModule.class, TestSocksModule.class, diff --git a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTestComponent.java b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTestComponent.java index d6571298e..8a4cda654 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTestComponent.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTestComponent.java @@ -2,7 +2,7 @@ package org.briarproject.bramble.sync; import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons; import org.briarproject.bramble.BrambleCoreModule; -import org.briarproject.bramble.mailbox.UrlConverterModule; +import org.briarproject.bramble.mailbox.ModularMailboxModule; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; import org.briarproject.bramble.test.TestDnsModule; import org.briarproject.bramble.test.TestPluginConfigModule; @@ -16,7 +16,7 @@ import dagger.Component; @Component(modules = { BrambleCoreIntegrationTestModule.class, BrambleCoreModule.class, - UrlConverterModule.class, + ModularMailboxModule.class, TestDnsModule.class, TestSocksModule.class, TestPluginConfigModule.class, diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/BrambleCoreIntegrationTestModule.java b/bramble-core/src/test/java/org/briarproject/bramble/test/BrambleCoreIntegrationTestModule.java index 8d4224df6..e2ddb2fa9 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/BrambleCoreIntegrationTestModule.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/test/BrambleCoreIntegrationTestModule.java @@ -11,6 +11,7 @@ import dagger.Module; DefaultBatteryManagerModule.class, DefaultEventExecutorModule.class, DefaultWakefulIoExecutorModule.class, + TestThreadFactoryModule.class, TestDatabaseConfigModule.class, TestFeatureFlagModule.class, TestMailboxDirectoryModule.class, diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/BrambleIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/test/BrambleIntegrationTest.java index e4cd51826..9e6c41ab6 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/BrambleIntegrationTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/test/BrambleIntegrationTest.java @@ -235,11 +235,16 @@ public abstract class BrambleIntegrationTest { + + static final String URL_BASE = "http://127.0.0.1:8000"; + + AbstractMailboxIntegrationTest() { + TestLogFormatter.use(); + } + + private final TransportId transportId = new TransportId(getRandomString(4)); + private final File dir1 = new File(testDir, "alice"); + private final File dir2 = new File(testDir, "bob"); + private final SecretKey rootKey = getSecretKey(); + + MailboxIntegrationTestComponent c1, c2; + Contact contact1From2, contact2From1; + TestMailbox mailbox; + MailboxApi api = createMailboxApi(); + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + c1 = startTestComponent(dir1, "Alice"); + c2 = startTestComponent(dir2, "Bob"); + mailbox = new TestMailbox(new File(testDir, "mailbox")); + mailbox.startLifecycle(); + } + + @After + @Override + public void tearDown() throws Exception { + super.tearDown(); + c1.getLifecycleManager().stopServices(); + c2.getLifecycleManager().stopServices(); + c1.getLifecycleManager().waitForShutdown(); + c2.getLifecycleManager().waitForShutdown(); + mailbox.stopLifecycle(true); + } + + private MailboxIntegrationTestComponent startTestComponent( + File databaseDir, String name) throws Exception { + TestThreadFactoryModule threadFactoryModule = + new TestThreadFactoryModule(name); + TestDatabaseConfigModule dbModule = + new TestDatabaseConfigModule(databaseDir); + MailboxIntegrationTestComponent component = + DaggerMailboxIntegrationTestComponent + .builder() + .testThreadFactoryModule(threadFactoryModule) + .testDatabaseConfigModule(dbModule) + .build(); + injectEagerSingletons(component); + + setUp(component, name); + return component; + } + + private void setUp(MailboxIntegrationTestComponent device, + String name) throws Exception { + // Add an identity for the user + IdentityManager identityManager = device.getIdentityManager(); + Identity identity = identityManager.createIdentity(name); + identityManager.registerIdentity(identity); + // Start the lifecycle manager + LifecycleManager lifecycleManager = device.getLifecycleManager(); + lifecycleManager.startServices(getSecretKey()); + lifecycleManager.waitForStartup(); + addEventListener(device); + } + + MailboxProperties pair(MailboxIntegrationTestComponent c, + AbstractMailbox mailbox) throws Exception { + MailboxAuthToken setupToken = fromString(mailbox.getSetupToken()); + + MailboxPairingTask pairingTask = c.getMailboxManager() + .startPairingTask(getQrCodePayload(setupToken.getBytes())); + + CountDownLatch latch = new CountDownLatch(1); + pairingTask.addObserver((state) -> { + if (state instanceof MailboxPairingState.Paired) { + latch.countDown(); + } + }); + if (!latch.await(10, SECONDS)) { + fail("Timeout reached when waiting for pairing."); + } + MailboxProperties properties = c.getDatabaseComponent() + .transactionWithNullableResult(true, txn -> + c.getMailboxSettingsManager() + .getOwnMailboxProperties(txn) + ); + assertNotNull(properties); + return properties; + } + + void addContacts() throws Exception { + LocalAuthor author1 = c1.getIdentityManager().getLocalAuthor(); + LocalAuthor author2 = c2.getIdentityManager().getLocalAuthor(); + + ContactId contactId2From1 = + c1.getContactManager().addContact(author2, + author1.getId(), rootKey, + c1.getClock().currentTimeMillis(), + true, true, true); + ContactId contactId1From2 = + c2.getContactManager().addContact(author1, + author2.getId(), rootKey, + c2.getClock().currentTimeMillis(), + false, true, true); + + contact2From1 = c1.getContactManager().getContact(contactId2From1); + contact1From2 = c2.getContactManager().getContact(contactId1From2); + + // Sync client versioning update from 1 to 2 + sync1To2(1, true); + // Sync client versioning update and ack from 2 to 1 + sync2To1(1, true); + // Sync second client versioning update, mailbox properties and ack + // from 1 to 2 + sync1To2(2, true); + // Sync mailbox properties and ack from 2 to 1 + sync2To1(1, true); + // Sync final ack from 1 to 2 + ack1To2(1); + } + + T getFromDb(MailboxIntegrationTestComponent device, + DbCallable callable) throws Exception { + return device.getDatabaseComponent() + .transactionWithResult(true, callable::call); + } + + MailboxProperties getMailboxProperties( + MailboxIntegrationTestComponent device, ContactId contactId) + throws DbException { + DatabaseComponent db = device.getDatabaseComponent(); + MailboxUpdateWithMailbox update = (MailboxUpdateWithMailbox) + db.transactionWithNullableResult(true, txn -> + device.getMailboxUpdateManager() + .getRemoteUpdate(txn, contactId) + ); + if (update == null) fail(); + return update.getMailboxProperties(); + } + + void broadcastMessage(MailboxIntegrationTestComponent from) + throws Exception { + TransportProperties p = from.getTransportPropertyManager() + .getLocalProperties(transportId); + p.put(getRandomString(23), getRandomString(8)); + from.getTransportPropertyManager().mergeLocalProperties(transportId, p); + } + + void sync1To2(int num, boolean valid) throws Exception { + syncMessage(c1, c2, contact2From1.getId(), num, valid); + } + + void sync2To1(int num, boolean valid) throws Exception { + syncMessage(c2, c1, contact1From2.getId(), num, valid); + } + + void ack1To2(int num) throws Exception { + sendAcks(c1, c2, contact2From1.getId(), num); + } + + void ack2To1(int num) throws Exception { + sendAcks(c2, c1, contact1From2.getId(), num); + } + + void assertNumMessages(MailboxIntegrationTestComponent c, + ContactId contactId, int num) throws DbException { + Map p = c.getTransportPropertyManager() + .getRemoteProperties(transportId); + assertEquals(num, p.get(contactId).size()); + } + +} diff --git a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxApiIntegrationTest.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxApiIntegrationTest.java index e6ab68121..d196d180d 100644 --- a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxApiIntegrationTest.java +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxApiIntegrationTest.java @@ -26,7 +26,7 @@ import java.util.List; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; -import static org.briarproject.bramble.mailbox.MailboxIntegrationTestUtils.URL_BASE; +import static org.briarproject.bramble.mailbox.AbstractMailboxIntegrationTest.URL_BASE; import static org.briarproject.bramble.mailbox.MailboxIntegrationTestUtils.createMailboxApi; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; diff --git a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTest.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTest.java new file mode 100644 index 000000000..043257eaf --- /dev/null +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTest.java @@ -0,0 +1,70 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.mailbox.MailboxProperties; +import org.briarproject.bramble.mailbox.MailboxApi.MailboxFile; +import org.junit.Test; + +import java.util.Collection; +import java.util.List; +import java.util.logging.Logger; + +import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.mailbox.MailboxIntegrationTestUtils.retryUntilSuccessOrTimeout; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class MailboxIntegrationTest extends AbstractMailboxIntegrationTest { + + private static final Logger LOG = + getLogger(MailboxIntegrationTest.class.getSimpleName()); + + @Test + public void testSendMessageViaMailbox() throws Exception { + addContacts(); + + // c1 one pairs the mailbox + MailboxProperties props1 = pair(c1, mailbox); + + // Check for number of contacts on mailbox via API every 100ms. + // This should be quick and will succeed with first call. + retryUntilSuccessOrTimeout(1_000, 100, () -> { + Collection contacts = api.getContacts(props1); + return contacts.size() == 1; + }); + + // tell contact about mailbox + sync1To2(1, true); + ack2To1(1); + + // contact should have received their MailboxProperties + MailboxProperties props2 = + getMailboxProperties(c2, contact1From2.getId()); + assertNotNull(props2.getInboxId()); + + // wait until file containing mailbox properties arrived on mailbox + retryUntilSuccessOrTimeout(5_000, 500, () -> { + List files = api.getFiles(props2, props2.getInboxId()); + return files.size() == 1; + }); + LOG.info("Mailbox properties uploaded"); + + // send message and wait for it to arrive via mailbox + broadcastMessage(c1); + + // we don't check for two messages now, because 2 (Bob) might have + // download the first message still in their 1st download cycle. + + // wait for message to arrive + // this might require 2nd download cycle after Tor reachability period + LOG.info("Waiting for delivery of broadcast message"); + awaitPendingMessageDelivery(1); + + // assert that message arrived for c2 + assertNumMessages(c2, contact1From2.getId(), 1); + + // all files were deleted from mailbox + assertEquals(0, api.getFiles(props2, props2.getInboxId()).size()); + } + +} diff --git a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTestComponent.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTestComponent.java index a4fc1adb5..c6c7fd931 100644 --- a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTestComponent.java +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTestComponent.java @@ -1,8 +1,8 @@ package org.briarproject.bramble.mailbox; +import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons; import org.briarproject.bramble.BrambleCoreModule; import org.briarproject.bramble.api.contact.ContactManager; -import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.lifecycle.LifecycleManager; @@ -11,10 +11,9 @@ import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; import org.briarproject.bramble.api.mailbox.MailboxUpdateManager; import org.briarproject.bramble.api.properties.TransportPropertyManager; import org.briarproject.bramble.api.system.Clock; -import org.briarproject.bramble.mailbox.MailboxIntegrationTestUtils.TestUrlConverterModule; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; import org.briarproject.bramble.test.BrambleIntegrationTestComponent; -import org.briarproject.bramble.test.FakeTorPluginConfigModule; +import org.briarproject.bramble.test.MailboxTestPluginConfigModule; import org.briarproject.bramble.test.TestDnsModule; import org.briarproject.bramble.test.TestSocksModule; @@ -26,31 +25,37 @@ import dagger.Component; @Component(modules = { BrambleCoreIntegrationTestModule.class, BrambleCoreModule.class, - TestUrlConverterModule.class, - FakeTorPluginConfigModule.class, + TestModularMailboxModule.class, + MailboxTestPluginConfigModule.class, TestSocksModule.class, TestDnsModule.class, }) interface MailboxIntegrationTestComponent extends BrambleIntegrationTestComponent { - DatabaseComponent getDatabaseComponent(); - - MailboxManager getMailboxManager(); - - MailboxUpdateManager getMailboxUpdateManager(); - - MailboxSettingsManager getMailboxSettingsManager(); - LifecycleManager getLifecycleManager(); + DatabaseComponent getDatabaseComponent(); + ContactManager getContactManager(); + AuthorFactory getAuthorFactory(); + Clock getClock(); + MailboxManager getMailboxManager(); + + MailboxSettingsManager getMailboxSettingsManager(); + + MailboxUpdateManager getMailboxUpdateManager(); + TransportPropertyManager getTransportPropertyManager(); - AuthorFactory getAuthorFactory(); - - CryptoComponent getCrypto(); + class Helper { + static void injectEagerSingletons( + MailboxIntegrationTestComponent c) { + BrambleCoreIntegrationTestEagerSingletons.Helper + .injectEagerSingletons(c); + } + } } diff --git a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTestUtils.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTestUtils.java index 3f27c648d..bcea13ea3 100644 --- a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTestUtils.java +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/MailboxIntegrationTestUtils.java @@ -1,89 +1,16 @@ package org.briarproject.bramble.mailbox; -import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons; -import org.briarproject.bramble.api.WeakSingletonProvider; -import org.briarproject.bramble.api.mailbox.MailboxAuthToken; -import org.briarproject.bramble.test.TestDatabaseConfigModule; - -import java.io.File; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.Arrays; import java.util.concurrent.atomic.AtomicBoolean; -import javax.annotation.Nonnull; -import javax.net.SocketFactory; - -import dagger.Module; -import dagger.Provides; -import okhttp3.OkHttpClient; - import static java.lang.System.currentTimeMillis; -import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.briarproject.bramble.mailbox.MailboxTestUtils.createHttpClientProvider; +import static org.briarproject.bramble.mailbox.TestModularMailboxModule.urlConverter; import static org.junit.Assert.fail; class MailboxIntegrationTestUtils { - static final String URL_BASE = "http://127.0.0.1:8000"; - - static String getQrCodePayload(MailboxAuthToken setupToken) { - byte[] bytes = getQrCodeBytes(setupToken); - Charset charset = Charset.forName("ISO-8859-1"); - return new String(bytes, charset); - } - - private static byte[] getQrCodeBytes(MailboxAuthToken setupToken) { - byte[] hiddenServiceBytes = getHiddenServiceBytes(); - byte[] setupTokenBytes = setupToken.getBytes(); - return ByteBuffer.allocate(65).put((byte) 32) - .put(hiddenServiceBytes).put(setupTokenBytes).array(); - } - - private static byte[] getHiddenServiceBytes() { - byte[] data = new byte[32]; - Arrays.fill(data, (byte) 'a'); - return data; - } - - private static WeakSingletonProvider createHttpClientProvider() { - OkHttpClient client = new OkHttpClient.Builder() - .socketFactory(SocketFactory.getDefault()) - .connectTimeout(60_000, MILLISECONDS) - .build(); - return new WeakSingletonProvider() { - @Override - @Nonnull - public OkHttpClient createInstance() { - return client; - } - }; - } - static MailboxApi createMailboxApi() { - return new MailboxApiImpl(createHttpClientProvider(), - new TestUrlConverter()); - } - - static MailboxIntegrationTestComponent createTestComponent( - File databaseDir) { - MailboxIntegrationTestComponent component = - DaggerMailboxIntegrationTestComponent - .builder() - .testDatabaseConfigModule( - new TestDatabaseConfigModule(databaseDir)) - .build(); - BrambleCoreIntegrationTestEagerSingletons.Helper - .injectEagerSingletons(component); - return component; - } - - @Module - static class TestUrlConverterModule { - - @Provides - UrlConverter provideUrlConverter() { - return new TestUrlConverter(); - } + return new MailboxApiImpl(createHttpClientProvider(), urlConverter); } interface Check { @@ -126,6 +53,7 @@ class MailboxIntegrationTestUtils { return; } try { + //noinspection BusyWait Thread.sleep(step); } catch (InterruptedException ignore) { // continue diff --git a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/OwnMailboxContactListWorkerIntegrationTest.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/OwnMailboxContactListWorkerIntegrationTest.java index d91ca40a0..40b12ffc5 100644 --- a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/OwnMailboxContactListWorkerIntegrationTest.java +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/OwnMailboxContactListWorkerIntegrationTest.java @@ -6,112 +6,49 @@ import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.AuthorFactory; -import org.briarproject.bramble.api.identity.Identity; -import org.briarproject.bramble.api.identity.IdentityManager; -import org.briarproject.bramble.api.lifecycle.LifecycleManager; -import org.briarproject.bramble.api.mailbox.MailboxAuthToken; -import org.briarproject.bramble.api.mailbox.MailboxPairingState.Paired; -import org.briarproject.bramble.api.mailbox.MailboxPairingTask; +import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.mailbox.MailboxProperties; -import org.briarproject.bramble.test.BrambleTestCase; -import org.briarproject.mailbox.lib.TestMailbox; -import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.concurrent.CountDownLatch; -import static org.briarproject.bramble.api.mailbox.MailboxAuthToken.fromString; import static org.briarproject.bramble.mailbox.MailboxIntegrationTestUtils.createMailboxApi; -import static org.briarproject.bramble.mailbox.MailboxIntegrationTestUtils.createTestComponent; -import static org.briarproject.bramble.mailbox.MailboxIntegrationTestUtils.getQrCodePayload; import static org.briarproject.bramble.mailbox.MailboxIntegrationTestUtils.retryUntilSuccessOrTimeout; import static org.briarproject.bramble.test.TestUtils.getSecretKey; -import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.junit.Assert.assertEquals; public class OwnMailboxContactListWorkerIntegrationTest - extends BrambleTestCase { - - @Rule - public TemporaryFolder mailboxDataDirectory = new TemporaryFolder(); - - private TestMailbox mailbox; + extends AbstractMailboxIntegrationTest { private final MailboxApi api = createMailboxApi(); private MailboxProperties ownerProperties; - private final File testDir = getTestDirectory(); - private final File aliceDir = new File(testDir, "alice"); - - private MailboxIntegrationTestComponent component; - private Identity identity; + private LocalAuthor localAuthor1; private final SecretKey rootKey = getSecretKey(); private final long timestamp = System.currentTimeMillis(); @Before + @Override public void setUp() throws Exception { - mailbox = new TestMailbox(mailboxDataDirectory.getRoot()); - mailbox.startLifecycle(); - - MailboxAuthToken setupToken = fromString(mailbox.getSetupToken()); - - component = createTestComponent(aliceDir); - identity = setUp(component, "Alice"); - - MailboxPairingTask pairingTask = component.getMailboxManager() - .startPairingTask(getQrCodePayload(setupToken)); - - CountDownLatch latch = new CountDownLatch(1); - pairingTask.addObserver((state) -> { - if (state instanceof Paired) { - latch.countDown(); - } - }); - latch.await(); - - ownerProperties = component.getDatabaseComponent() - .transactionWithNullableResult(false, txn -> - component.getMailboxSettingsManager() - .getOwnMailboxProperties(txn) - ); - } - - @After - public void tearDown() { - mailbox.stopLifecycle(true); - } - - private Identity setUp(MailboxIntegrationTestComponent device, String name) - throws Exception { - // Add an identity for the user - IdentityManager identityManager = device.getIdentityManager(); - Identity identity = identityManager.createIdentity(name); - identityManager.registerIdentity(identity); - // Start the lifecycle manager - LifecycleManager lifecycleManager = device.getLifecycleManager(); - lifecycleManager.startServices(getSecretKey()); - lifecycleManager.waitForStartup(); - // Check the initial conditions - ContactManager contactManager = device.getContactManager(); - assertEquals(0, contactManager.getPendingContacts().size()); - assertEquals(0, contactManager.getContacts().size()); - return identity; + super.setUp(); + localAuthor1 = c1.getIdentityManager().getLocalAuthor(); + ownerProperties = pair(c1, mailbox); } @Test public void testUploadContacts() throws Exception { + // Check the initial conditions + ContactManager contactManager = c1.getContactManager(); + assertEquals(0, contactManager.getPendingContacts().size()); + assertEquals(0, contactManager.getContacts().size()); + int numContactsToAdd = 5; - List expectedContacts = - createContacts(component, identity, numContactsToAdd); + List expectedContacts = createContacts(c1, numContactsToAdd); // Check for number of contacts on mailbox via API every 100ms retryUntilSuccessOrTimeout(1000, 100, () -> { @@ -125,15 +62,16 @@ public class OwnMailboxContactListWorkerIntegrationTest } private List createContacts( - MailboxIntegrationTestComponent component, Identity local, - int numContacts) throws DbException { + MailboxIntegrationTestComponent component, int numContacts) + throws DbException { List contactIds = new ArrayList<>(); ContactManager contactManager = component.getContactManager(); AuthorFactory authorFactory = component.getAuthorFactory(); for (int i = 0; i < numContacts; i++) { Author remote = authorFactory.createLocalAuthor("Bob " + i); - contactIds.add(contactManager.addContact(remote, local.getId(), - rootKey, timestamp, true, true, true)); + ContactId c = contactManager.addContact(remote, + localAuthor1.getId(), rootKey, timestamp, true, true, true); + contactIds.add(c); } return contactIds; } diff --git a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/TestMailboxConfigImpl.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/TestMailboxConfigImpl.java new file mode 100644 index 000000000..2552fca77 --- /dev/null +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/TestMailboxConfigImpl.java @@ -0,0 +1,30 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; +import javax.inject.Inject; + +@Immutable +@NotNullByDefault +class TestMailboxConfigImpl implements MailboxConfig { + + @Inject + TestMailboxConfigImpl() { + } + + @Override + public long getApiCallerMinRetryInterval() { + return 1000; + } + + @Override + public long getApiCallerMaxRetryInterval() { + return 2000; + } + + @Override + public long getTorReachabilityPeriod() { + return 10_000; + } +} diff --git a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/TestModularMailboxModule.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/TestModularMailboxModule.java new file mode 100644 index 000000000..22e001bae --- /dev/null +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/TestModularMailboxModule.java @@ -0,0 +1,25 @@ +package org.briarproject.bramble.mailbox; + +import org.briarproject.nullsafety.NotNullByDefault; + +import dagger.Module; +import dagger.Provides; + +import static org.briarproject.bramble.mailbox.AbstractMailboxIntegrationTest.URL_BASE; + +@Module +@NotNullByDefault +class TestModularMailboxModule { + + @Provides + MailboxConfig provideMailboxConfig(TestMailboxConfigImpl mailboxConfig) { + return mailboxConfig; + } + + static UrlConverter urlConverter = onion -> URL_BASE; + + @Provides + UrlConverter provideUrlConverter() { + return urlConverter; + } +} diff --git a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/TestUrlConverter.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/TestUrlConverter.java deleted file mode 100644 index 5841e7cc9..000000000 --- a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/mailbox/TestUrlConverter.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.briarproject.bramble.mailbox; - -import org.briarproject.nullsafety.NotNullByDefault; - -import static org.briarproject.bramble.mailbox.MailboxIntegrationTestUtils.URL_BASE; - -@NotNullByDefault -class TestUrlConverter implements UrlConverter { - - @Override - public String convertOnionToBaseUrl(String onion) { - return URL_BASE; - } -} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/FakeTorPlugin.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/FakeTorPlugin.java similarity index 89% rename from bramble-core/src/test/java/org/briarproject/bramble/test/FakeTorPlugin.java rename to mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/FakeTorPlugin.java index 8e68f4f35..fd702cb3c 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/FakeTorPlugin.java +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/FakeTorPlugin.java @@ -4,7 +4,7 @@ import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.keyagreement.KeyAgreementListener; import org.briarproject.bramble.api.plugin.ConnectionHandler; -import org.briarproject.bramble.api.plugin.PluginException; +import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.TorConstants; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin; @@ -21,7 +21,6 @@ import javax.annotation.Nullable; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; -import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; @NotNullByDefault @@ -29,9 +28,14 @@ public class FakeTorPlugin implements DuplexPlugin { private static final Logger LOG = getLogger(FakeTorPlugin.class.getName()); + private final PluginCallback callback; private State state = INACTIVE; + FakeTorPlugin(PluginCallback callback) { + this.callback = callback; + } + @Override public TransportId getId() { return TorConstants.ID; @@ -48,15 +52,17 @@ public class FakeTorPlugin implements DuplexPlugin { } @Override - public void start() throws PluginException { + public void start() { LOG.info("Starting plugin"); state = ACTIVE; + callback.pluginStateChanged(state); } @Override - public void stop() throws PluginException { + public void stop() { LOG.info("Stopping plugin"); - state = DISABLED; + state = INACTIVE; + callback.pluginStateChanged(state); } @Override diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/FakeTorPluginFactory.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/FakeTorPluginFactory.java similarity index 95% rename from bramble-core/src/test/java/org/briarproject/bramble/test/FakeTorPluginFactory.java rename to mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/FakeTorPluginFactory.java index 32ea3139d..9e718991b 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/FakeTorPluginFactory.java +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/FakeTorPluginFactory.java @@ -32,6 +32,6 @@ public class FakeTorPluginFactory implements DuplexPluginFactory { @Nullable @Override public DuplexPlugin createPlugin(PluginCallback callback) { - return new FakeTorPlugin(); + return new FakeTorPlugin(callback); } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/test/FakeTorPluginConfigModule.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/MailboxTestPluginConfigModule.java similarity index 52% rename from bramble-core/src/test/java/org/briarproject/bramble/test/FakeTorPluginConfigModule.java rename to mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/MailboxTestPluginConfigModule.java index 49b9048ad..a8c681bd2 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/test/FakeTorPluginConfigModule.java +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/MailboxTestPluginConfigModule.java @@ -1,27 +1,56 @@ package org.briarproject.bramble.test; +import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.PluginConfig; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory; +import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin; import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory; +import org.briarproject.bramble.plugin.file.MailboxPluginFactory; import org.briarproject.nullsafety.NotNullByDefault; import java.util.Collection; import java.util.List; import java.util.Map; +import javax.annotation.Nullable; + import dagger.Module; import dagger.Provides; -import static java.util.Collections.emptyList; +import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; +import static org.briarproject.bramble.test.TestPluginConfigModule.SIMPLEX_TRANSPORT_ID; @Module -public class FakeTorPluginConfigModule { +public class MailboxTestPluginConfigModule { + + private static final int MAX_LATENCY = 30_000; // 30 seconds + + @NotNullByDefault + private final SimplexPluginFactory simplex = new SimplexPluginFactory() { + + @Override + public TransportId getId() { + return SIMPLEX_TRANSPORT_ID; + } + + @Override + public long getMaxLatency() { + return MAX_LATENCY; + } + + @Override + @Nullable + public SimplexPlugin createPlugin(PluginCallback callback) { + return null; + } + }; @Provides - PluginConfig providePluginConfig(FakeTorPluginFactory tor) { + PluginConfig providePluginConfig(FakeTorPluginFactory tor, + MailboxPluginFactory mailboxPluginFactory) { @NotNullByDefault PluginConfig pluginConfig = new PluginConfig() { @@ -32,7 +61,7 @@ public class FakeTorPluginConfigModule { @Override public Collection getSimplexFactories() { - return emptyList(); + return asList(simplex, mailboxPluginFactory); } @Override diff --git a/mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/TestLogFormatter.java b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/TestLogFormatter.java new file mode 100644 index 000000000..b5b819d15 --- /dev/null +++ b/mailbox-integration-tests/src/test/java/org/briarproject/bramble/test/TestLogFormatter.java @@ -0,0 +1,57 @@ +package org.briarproject.bramble.test; + +import org.briarproject.nullsafety.NotNullByDefault; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.ConsoleHandler; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +import javax.annotation.concurrent.ThreadSafe; + +@ThreadSafe +@NotNullByDefault +public class TestLogFormatter extends SimpleFormatter { + + private final Object lock = new Object(); + private final DateFormat dateFormat; // Locking: lock + private final Date date; // Locking: lock + + public static void use() { + LogManager.getLogManager().reset(); + Logger rootLogger = LogManager.getLogManager().getLogger(""); + ConsoleHandler handler = new ConsoleHandler(); + handler.setFormatter(new TestLogFormatter()); + rootLogger.addHandler(handler); + } + + private TestLogFormatter() { + synchronized (lock) { + dateFormat = new SimpleDateFormat("HH:mm:ss.SSS"); + date = new Date(); + } + } + + @Override + public String format(LogRecord rec) { + if (rec.getThrown() == null) { + String dateString; + synchronized (lock) { + date.setTime(rec.getMillis()); + dateString = dateFormat.format(date); + } + return String.format("%s [%s] %s %s - %s\n", + dateString, + Thread.currentThread().getName(), + rec.getLevel().getName(), + rec.getLoggerName(), + rec.getMessage()); + } else { + return super.format(rec); + } + } +}