diff --git a/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTest.java new file mode 100644 index 000000000..acd4844dc --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTest.java @@ -0,0 +1,177 @@ +package org.briarproject.bramble.plugin.file; + +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.event.Event; +import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.identity.Author; +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.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.file.RemovableDriveTask; +import org.briarproject.bramble.api.plugin.file.RemovableDriveTask.Observer; +import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent; +import org.briarproject.bramble.test.BrambleTestCase; +import org.briarproject.bramble.test.TestDatabaseConfigModule; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.util.concurrent.CountDownLatch; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; +import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; +import static org.briarproject.bramble.test.TestUtils.getSecretKey; +import static org.briarproject.bramble.test.TestUtils.getTestDirectory; +import static org.junit.Assert.assertTrue; + +public class RemovableDriveIntegrationTest extends BrambleTestCase { + + private static final int TIMEOUT_MS = 5_000; + + private final File testDir = getTestDirectory(); + private final File aliceDir = new File(testDir, "alice"); + private final File bobDir = new File(testDir, "bob"); + + private final SecretKey rootKey = getSecretKey(); + private final long timestamp = System.currentTimeMillis(); + + private RemovableDriveIntegrationTestComponent alice, bob; + + @Before + public void setUp() { + assertTrue(testDir.mkdirs()); + alice = DaggerRemovableDriveIntegrationTestComponent.builder() + .testDatabaseConfigModule( + new TestDatabaseConfigModule(aliceDir)).build(); + RemovableDriveIntegrationTestComponent.Helper + .injectEagerSingletons(alice); + bob = DaggerRemovableDriveIntegrationTestComponent.builder() + .testDatabaseConfigModule( + new TestDatabaseConfigModule(bobDir)).build(); + RemovableDriveIntegrationTestComponent.Helper + .injectEagerSingletons(bob); + } + + @Test + public void testWriteAndRead() throws Exception { + // Create the identities + Identity aliceIdentity = + alice.getIdentityManager().createIdentity("Alice"); + Identity bobIdentity = bob.getIdentityManager().createIdentity("Bob"); + // Set up the devices and get the contact IDs + ContactId bobId = setUp(alice, aliceIdentity, + bobIdentity.getLocalAuthor(), true); + ContactId aliceId = setUp(bob, bobIdentity, + aliceIdentity.getLocalAuthor(), false); + // Sync Alice's client versions and transport properties + read(bob, aliceId, write(alice, bobId), 2); + // Sync Bob's client versions and transport properties + read(alice, bobId, write(bob, aliceId), 2); + } + + private ContactId setUp(RemovableDriveIntegrationTestComponent device, + Identity local, Author remote, boolean alice) throws Exception { + // Add an identity for the user + IdentityManager identityManager = device.getIdentityManager(); + identityManager.registerIdentity(local); + // Start the lifecycle manager + LifecycleManager lifecycleManager = device.getLifecycleManager(); + lifecycleManager.startServices(getSecretKey()); + lifecycleManager.waitForStartup(); + // Add the other user as a contact + ContactManager contactManager = device.getContactManager(); + return contactManager.addContact(remote, local.getId(), rootKey, + timestamp, alice, true, true); + } + + @SuppressWarnings("SameParameterValue") + private void read(RemovableDriveIntegrationTestComponent device, + ContactId contactId, File file, int deliveries) throws Exception { + // Listen for message deliveries + MessageDeliveryListener listener = + new MessageDeliveryListener(deliveries); + device.getEventBus().addListener(listener); + // Read the incoming stream + RemovableDriveTask reader = device.getRemovableDriveManager() + .startReaderTask(contactId, file); + CountDownLatch disposedLatch = new CountDownLatch(1); + reader.addObserver(new Observer() { + @Override + public void onProgress(long done, long total) { + } + + @Override + public void onCompletion(boolean success) { + disposedLatch.countDown(); + } + }); + // Wait for the messages to be delivered + assertTrue(listener.delivered.await(TIMEOUT_MS, MILLISECONDS)); + // Clean up the listener + device.getEventBus().removeListener(listener); + // Wait for the reader to be disposed + disposedLatch.await(TIMEOUT_MS, MILLISECONDS); + } + + private File write(RemovableDriveIntegrationTestComponent device, + ContactId contactId) throws Exception { + // Write the outgoing stream to a file + File file = File.createTempFile("sync", ".tmp", testDir); + RemovableDriveTask writer = device.getRemovableDriveManager() + .startWriterTask(contactId, file); + CountDownLatch disposedLatch = new CountDownLatch(1); + writer.addObserver(new Observer() { + @Override + public void onProgress(long done, long total) { + } + + @Override + public void onCompletion(boolean success) { + disposedLatch.countDown(); + } + }); + // Wait for the writer to be disposed + disposedLatch.await(TIMEOUT_MS, MILLISECONDS); + // Return the file containing the stream + return file; + } + + private void tearDown(RemovableDriveIntegrationTestComponent device) + throws Exception { + // Stop the lifecycle manager + LifecycleManager lifecycleManager = device.getLifecycleManager(); + lifecycleManager.stopServices(); + lifecycleManager.waitForShutdown(); + } + + @After + public void tearDown() throws Exception { + // Tear down the devices + tearDown(alice); + tearDown(bob); + deleteTestDirectory(testDir); + } + + @NotNullByDefault + private static class MessageDeliveryListener implements EventListener { + + private final CountDownLatch delivered; + + private MessageDeliveryListener(int deliveries) { + delivered = new CountDownLatch(deliveries); + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof MessageStateChangedEvent) { + MessageStateChangedEvent m = (MessageStateChangedEvent) e; + if (m.getState().equals(DELIVERED)) delivered.countDown(); + } + } + } +} 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 new file mode 100644 index 000000000..9c5c3153d --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTestComponent.java @@ -0,0 +1,53 @@ +package org.briarproject.bramble.plugin.file; + +import org.briarproject.bramble.BrambleCoreEagerSingletons; +import org.briarproject.bramble.BrambleCoreModule; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.event.EventBus; +import org.briarproject.bramble.api.identity.IdentityManager; +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.system.DefaultWakefulIoExecutorModule; +import org.briarproject.bramble.system.TimeTravelModule; +import org.briarproject.bramble.test.TestDatabaseConfigModule; +import org.briarproject.bramble.test.TestSecureRandomModule; + +import javax.inject.Singleton; + +import dagger.Component; + +@Singleton +@Component(modules = { + BrambleCoreModule.class, + DefaultBatteryManagerModule.class, + DefaultEventExecutorModule.class, + DefaultWakefulIoExecutorModule.class, + TestDatabaseConfigModule.class, + RemovableDriveIntegrationTestModule.class, + RemovableDriveModule.class, + TestSecureRandomModule.class, + TimeTravelModule.class +}) +interface RemovableDriveIntegrationTestComponent + extends BrambleCoreEagerSingletons { + + ContactManager getContactManager(); + + EventBus getEventBus(); + + IdentityManager getIdentityManager(); + + LifecycleManager getLifecycleManager(); + + RemovableDriveManager getRemovableDriveManager(); + + class Helper { + + public static void injectEagerSingletons( + RemovableDriveIntegrationTestComponent c) { + BrambleCoreEagerSingletons.Helper.injectEagerSingletons(c); + } + } +} diff --git a/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTestModule.java b/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTestModule.java new file mode 100644 index 000000000..7b4699e10 --- /dev/null +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/file/RemovableDriveIntegrationTestModule.java @@ -0,0 +1,81 @@ +package org.briarproject.bramble.plugin.file; + +import org.briarproject.bramble.api.FeatureFlags; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +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.SimplexPluginFactory; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonList; + +@Module +class RemovableDriveIntegrationTestModule { + + @Provides + @Singleton + PluginConfig providePluginConfig(RemovableDrivePluginFactory drive) { + @NotNullByDefault + PluginConfig pluginConfig = new PluginConfig() { + + @Override + public Collection getDuplexFactories() { + return emptyList(); + } + + @Override + public Collection getSimplexFactories() { + return singletonList(drive); + } + + @Override + public boolean shouldPoll() { + return false; + } + + @Override + public Map> getTransportPreferences() { + return emptyMap(); + } + + }; + return pluginConfig; + } + + @Provides + FeatureFlags provideFeatureFlags() { + return new FeatureFlags() { + + @Override + public boolean shouldEnableImageAttachments() { + return true; + } + + @Override + public boolean shouldEnableProfilePictures() { + return true; + } + + @Override + public boolean shouldEnableDisappearingMessages() { + return true; + } + + @Override + public boolean shouldEnableConnectViaBluetooth() { + return true; + } + }; + } +}