diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxUploadWorker.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxUploadWorker.java index 5c6462c6d..6e3a72451 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxUploadWorker.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxUploadWorker.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.mailbox; import org.briarproject.bramble.api.Cancellable; +import org.briarproject.bramble.api.connection.ConnectionRegistry; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; @@ -12,6 +13,8 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.mailbox.MailboxFolderId; import org.briarproject.bramble.api.mailbox.MailboxProperties; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent; +import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.OutgoingSessionRecord; import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent; @@ -32,6 +35,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.ThreadSafe; +import static java.lang.Boolean.TRUE; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.logging.Level.INFO; @@ -58,9 +62,16 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver, *

* If there's no data to send, the worker listens for events indicating * that new data may be ready to send. + *

+ * Whenever we're directly connected to the contact, the worker doesn't + * check for data to send or start connectivity checks until the contact + * disconnects. However, if the worker has already started writing and + * uploading a file when the contact connects, the worker will finish the + * upload. */ private enum State { CREATED, + CONNECTED_TO_CONTACT, CHECKING_FOR_DATA, WAITING_FOR_DATA, CONNECTIVITY_CHECK, @@ -95,6 +106,7 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver, private final Clock clock; private final TaskScheduler taskScheduler; private final EventBus eventBus; + private final ConnectionRegistry connectionRegistry; private final ConnectivityChecker connectivityChecker; private final MailboxApiCaller mailboxApiCaller; private final MailboxApi mailboxApi; @@ -121,6 +133,7 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver, Clock clock, TaskScheduler taskScheduler, EventBus eventBus, + ConnectionRegistry connectionRegistry, ConnectivityChecker connectivityChecker, MailboxApiCaller mailboxApiCaller, MailboxApi mailboxApi, @@ -133,6 +146,7 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver, this.clock = clock; this.taskScheduler = taskScheduler; this.eventBus = eventBus; + this.connectionRegistry = connectionRegistry; this.connectivityChecker = connectivityChecker; this.mailboxApiCaller = mailboxApiCaller; this.mailboxApi = mailboxApi; @@ -182,6 +196,12 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver, synchronized (lock) { checkTask = null; if (state != State.CHECKING_FOR_DATA) return; + // Check whether we're directly connected to the contact. Calling + // this while holding the lock isn't ideal, but it avoids races + if (connectionRegistry.isConnected(contactId)) { + state = State.CONNECTED_TO_CONTACT; + return; + } } LOG.info("Checking for data to send"); try { @@ -364,8 +384,11 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver, onDataToSend(); } } else if (e instanceof MessageSharedEvent) { - LOG.info("Message shared"); - onDataToSend(); + MessageSharedEvent m = (MessageSharedEvent) e; + if (m.getGroupVisibility().get(contactId) == TRUE) { + LOG.info("Message shared"); + onDataToSend(); + } } else if (e instanceof GroupVisibilityUpdatedEvent) { GroupVisibilityUpdatedEvent g = (GroupVisibilityUpdatedEvent) e; if (g.getVisibility() == SHARED && @@ -373,6 +396,18 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver, LOG.info("Group shared"); onDataToSend(); } + } else if (e instanceof ContactConnectedEvent) { + ContactConnectedEvent c = (ContactConnectedEvent) e; + if (c.getContactId().equals(contactId)) { + LOG.info("Contact connected"); + onContactConnected(); + } + } else if (e instanceof ContactDisconnectedEvent) { + ContactDisconnectedEvent c = (ContactDisconnectedEvent) e; + if (c.getContactId().equals(contactId)) { + LOG.info("Contact disconnected"); + onContactDisconnected(); + } } } @@ -391,4 +426,36 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver, // If we had scheduled a wakeup when data was due to be sent, cancel it if (wakeupTask != null) wakeupTask.cancel(); } + + @EventExecutor + private void onContactConnected() { + Cancellable wakeupTask = null, checkTask = null; + synchronized (lock) { + if (state == State.DESTROYED) return; + // If we're checking for data to send, waiting for data to send, + // or checking connectivity then wait until we disconnect from + // the contact before proceeding. If we're writing or uploading + // a file then continue + if (state == State.CHECKING_FOR_DATA || + state == State.WAITING_FOR_DATA || + state == State.CONNECTIVITY_CHECK) { + state = State.CONNECTED_TO_CONTACT; + wakeupTask = this.wakeupTask; + this.wakeupTask = null; + checkTask = this.checkTask; + this.checkTask = null; + } + } + if (wakeupTask != null) wakeupTask.cancel(); + if (checkTask != null) checkTask.cancel(); + } + + @EventExecutor + private void onContactDisconnected() { + synchronized (lock) { + if (state != State.CONNECTED_TO_CONTACT) return; + state = State.CHECKING_FOR_DATA; + } + ioExecutor.execute(this::checkForDataToSend); + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxWorkerFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxWorkerFactoryImpl.java index 34a3cab74..dd7155929 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxWorkerFactoryImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxWorkerFactoryImpl.java @@ -1,5 +1,6 @@ package org.briarproject.bramble.mailbox; +import org.briarproject.bramble.api.connection.ConnectionRegistry; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.event.EventBus; @@ -25,6 +26,7 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory { private final Clock clock; private final TaskScheduler taskScheduler; private final EventBus eventBus; + private final ConnectionRegistry connectionRegistry; private final MailboxApiCaller mailboxApiCaller; private final MailboxApi mailboxApi; private final MailboxFileManager mailboxFileManager; @@ -36,6 +38,7 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory { Clock clock, TaskScheduler taskScheduler, EventBus eventBus, + ConnectionRegistry connectionRegistry, MailboxApiCaller mailboxApiCaller, MailboxApi mailboxApi, MailboxFileManager mailboxFileManager, @@ -45,6 +48,7 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory { this.clock = clock; this.taskScheduler = taskScheduler; this.eventBus = eventBus; + this.connectionRegistry = connectionRegistry; this.mailboxApiCaller = mailboxApiCaller; this.mailboxApi = mailboxApi; this.mailboxFileManager = mailboxFileManager; @@ -57,9 +61,9 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory { MailboxProperties properties, MailboxFolderId folderId, ContactId contactId) { MailboxUploadWorker worker = new MailboxUploadWorker(ioExecutor, db, - clock, taskScheduler, eventBus, connectivityChecker, - mailboxApiCaller, mailboxApi, mailboxFileManager, - properties, folderId, contactId); + clock, taskScheduler, eventBus, connectionRegistry, + connectivityChecker, mailboxApiCaller, mailboxApi, + mailboxFileManager, properties, folderId, contactId); eventBus.addListener(worker); return worker; } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxUploadWorkerTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxUploadWorkerTest.java index 048194983..c337c3708 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxUploadWorkerTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxUploadWorkerTest.java @@ -1,12 +1,16 @@ package org.briarproject.bramble.mailbox; import org.briarproject.bramble.api.Cancellable; +import org.briarproject.bramble.api.connection.ConnectionRegistry; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.mailbox.MailboxFolderId; import org.briarproject.bramble.api.mailbox.MailboxProperties; +import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent; +import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent; +import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.OutgoingSessionRecord; import org.briarproject.bramble.api.sync.event.MessageSharedEvent; @@ -25,10 +29,12 @@ import org.junit.Test; import java.io.File; import java.io.IOException; +import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS; import static org.briarproject.bramble.api.mailbox.MailboxConstants.MAX_LATENCY; @@ -50,6 +56,8 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { private final TaskScheduler taskScheduler = context.mock(TaskScheduler.class); private final EventBus eventBus = context.mock(EventBus.class); + private final ConnectionRegistry connectionRegistry = + context.mock(ConnectionRegistry.class); private final ConnectivityChecker connectivityChecker = context.mock(ConnectivityChecker.class); private final MailboxApiCaller mailboxApiCaller = @@ -72,6 +80,9 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { private final MessageId ackedId = new MessageId(getRandomId()); private final MessageId sentId = new MessageId(getRandomId()); private final MessageId newMessageId = new MessageId(getRandomId()); + private final GroupId groupId = new GroupId(getRandomId()); + private final Map groupVisibility = + singletonMap(contactId, true); private File testDir, tempFile; private MailboxUploadWorker worker; @@ -81,8 +92,9 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { testDir = getTestDirectory(); tempFile = new File(testDir, "temp"); worker = new MailboxUploadWorker(ioExecutor, db, clock, taskScheduler, - eventBus, connectivityChecker, mailboxApiCaller, mailboxApi, - mailboxFileManager, mailboxProperties, folderId, contactId); + eventBus, connectionRegistry, connectivityChecker, + mailboxApiCaller, mailboxApi, mailboxFileManager, + mailboxProperties, folderId, contactId); } @After @@ -93,8 +105,11 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { @Test public void testChecksForDataWhenStartedAndRemovesObserverWhenDestroyed() throws Exception { - // When the worker is started it should check for data to send + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); expectCheckForDataToSendNoDataWaiting(); worker.start(); @@ -106,15 +121,59 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { worker.destroy(); } + @Test + public void testDoesNotCheckForDataWhenStartedIfConnectedToContact() { + // When the worker is started it should check the connection registry. + // We're connected to the contact, so the worker should not check for + // data to send + expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(true); + + worker.start(); + + // When the worker is destroyed it should remove the connectivity + // observer and event listener + expectRemoveObserverAndListener(); + + worker.destroy(); + } + + @Test + public void testChecksForDataWhenContactDisconnects() throws Exception { + // When the worker is started it should check the connection registry. + // We're connected to the contact, so the worker should not check for + // data to send + expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(true); + + worker.start(); + + // When the contact disconnects, the worker should start a task to + // check for data to send + expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); + expectCheckForDataToSendNoDataWaiting(); + + worker.eventOccurred(new ContactDisconnectedEvent(contactId)); + + // When the worker is destroyed it should remove the connectivity + // observer and event listener + expectRemoveObserverAndListener(); + + worker.destroy(); + } + @Test public void testChecksConnectivityWhenStartedIfDataIsReady() throws Exception { Transaction recordTxn = new Transaction(null, false); - // When the worker is started it should check for data to send. As - // there's data ready to send immediately, the worker should start a - // connectivity check + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send. As there's data ready to send immediately, the worker + // should start a connectivity check expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); expectCheckForDataToSendAndStartConnectivityCheck(); worker.start(); @@ -149,7 +208,9 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { worker.onConnectivityCheckSucceeded(); // When the upload task runs, it should upload the file, record - // the acked/sent messages in the DB, and check for more data to send + // the acked/sent messages in the DB, and check the connection + // registry. We're not connected to the contact, so the worker should + // check for more data to send context.checking(new DbExpectations() {{ oneOf(mailboxApi).addFile(mailboxProperties, folderId, tempFile); oneOf(db).transaction(with(false), withDbRunnable(recordTxn)); @@ -157,6 +218,7 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { oneOf(db).setMessagesSent(recordTxn, contactId, singletonList(sentId), MAX_LATENCY); }}); + expectCheckConnectionRegistry(false); expectCheckForDataToSendNoDataWaiting(); assertFalse(upload.get().callApi()); @@ -172,11 +234,41 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { } @Test - public void testCancelsApiCallWhenDestroyed() throws Exception { - // When the worker is started it should check for data to send. As - // there's data ready to send immediately, the worker should start a - // connectivity check + public void testDoesNotWriteFileIfContactConnectsDuringConnectivityCheck() + throws Exception { + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send. As there's data ready to send immediately, the worker + // should start a connectivity check expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); + expectCheckForDataToSendAndStartConnectivityCheck(); + + worker.start(); + + // Before the connectivity check succeeds, we make a direct connection + // to the contact + worker.eventOccurred(new ContactConnectedEvent(contactId)); + + // When the connectivity check succeeds, the worker should not start + // writing and uploading a file + worker.onConnectivityCheckSucceeded(); + + // When the worker is destroyed it should remove the connectivity + // observer and event listener + expectRemoveObserverAndListener(); + + worker.destroy(); + } + + @Test + public void testCancelsApiCallWhenDestroyed() throws Exception { + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send. As there's data ready to send immediately, the worker + // should start a connectivity check + expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); expectCheckForDataToSendAndStartConnectivityCheck(); worker.start(); @@ -212,9 +304,7 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { // When the worker is destroyed it should remove the connectivity // observer and event listener and cancel the upload task - context.checking(new Expectations() {{ - oneOf(apiCall).cancel(); - }}); + expectCancelTask(apiCall); expectRemoveObserverAndListener(); worker.destroy(); @@ -230,16 +320,21 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { @Test public void testSchedulesWakeupWhenStartedIfDataIsNotReady() throws Exception { - // When the worker is started it should check for data to send. As - // the data isn't ready to send immediately, the worker should - // schedule a wakeup + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send. As the data isn't ready to send immediately, the + // worker should schedule a wakeup expectRunTaskOnIoExecutor(); AtomicReference wakeup = new AtomicReference<>(); + expectCheckConnectionRegistry(false); expectCheckForDataToSendAndScheduleWakeup(wakeup); worker.start(); - // When the wakeup task runs it should check for data to send + // When the wakeup task runs it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send + expectCheckConnectionRegistry(false); expectCheckForDataToSendNoDataWaiting(); wakeup.get().run(); @@ -252,21 +347,51 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { } @Test - public void testCancelsWakeupIfDestroyedBeforeWakingUp() throws Exception { + public void testCancelsWakeupIfContactConnectsBeforeWakingUp() + throws Exception { // When the worker is started it should check for data to send. As // the data isn't ready to send immediately, the worker should // schedule a wakeup expectRunTaskOnIoExecutor(); AtomicReference wakeup = new AtomicReference<>(); + expectCheckConnectionRegistry(false); + expectCheckForDataToSendAndScheduleWakeup(wakeup); + + worker.start(); + + // Before the wakeup task runs, we make a direct connection to the + // contact. The worker should cancel the wakeup task + expectCancelTask(wakeupTask); + + worker.eventOccurred(new ContactConnectedEvent(contactId)); + + // If the wakeup task runs anyway (cancellation came too late), it + // should return without doing anything + wakeup.get().run(); + + // When the worker is destroyed it should remove the connectivity + // observer and event listener + expectRemoveObserverAndListener(); + + worker.destroy(); + } + + @Test + public void testCancelsWakeupIfDestroyedBeforeWakingUp() throws Exception { + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send. As the data isn't ready to send immediately, the + // worker should schedule a wakeup + expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); + AtomicReference wakeup = new AtomicReference<>(); expectCheckForDataToSendAndScheduleWakeup(wakeup); worker.start(); // When the worker is destroyed it should cancel the wakeup and // remove the connectivity observer and event listener - context.checking(new Expectations() {{ - oneOf(wakeupTask).cancel(); - }}); + expectCancelTask(wakeupTask); expectRemoveObserverAndListener(); worker.destroy(); @@ -279,10 +404,12 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { @Test public void testCancelsWakeupIfEventIsReceivedBeforeWakingUp() throws Exception { - // When the worker is started it should check for data to send. As - // the data isn't ready to send immediately, the worker should - // schedule a wakeup + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send. As the data isn't ready to send immediately, the + // worker should schedule a wakeup expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); AtomicReference wakeup = new AtomicReference<>(); expectCheckForDataToSendAndScheduleWakeup(wakeup); @@ -293,11 +420,10 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { // wakeup task and schedule a check for new data after a short delay AtomicReference check = new AtomicReference<>(); expectScheduleCheck(check, CHECK_DELAY_MS); - context.checking(new Expectations() {{ - oneOf(wakeupTask).cancel(); - }}); + expectCancelTask(wakeupTask); - worker.eventOccurred(new MessageSharedEvent(newMessageId)); + worker.eventOccurred(new MessageSharedEvent(newMessageId, groupId, + groupVisibility)); // If the wakeup task runs anyway (cancellation came too late), it // should return early when it finds the state has changed @@ -306,9 +432,13 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { // Before the check task runs, the worker receives another event that // indicates new data may be available. The event should be ignored, // as a check for new data has already been scheduled - worker.eventOccurred(new MessageSharedEvent(newMessageId)); + worker.eventOccurred(new MessageSharedEvent(newMessageId, groupId, + groupVisibility)); - // When the check task runs, it should check for new data + // When the check task runs, it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // new data + expectCheckConnectionRegistry(false); expectCheckForDataToSendNoDataWaiting(); check.get().run(); @@ -322,8 +452,11 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { @Test public void testCancelsCheckWhenDestroyed() throws Exception { - // When the worker is started it should check for data to send + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); expectCheckForDataToSendNoDataWaiting(); worker.start(); @@ -334,13 +467,12 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { AtomicReference check = new AtomicReference<>(); expectScheduleCheck(check, CHECK_DELAY_MS); - worker.eventOccurred(new MessageSharedEvent(newMessageId)); + worker.eventOccurred(new MessageSharedEvent(newMessageId, groupId, + groupVisibility)); // When the worker is destroyed it should cancel the check and // remove the connectivity observer and event listener - context.checking(new Expectations() {{ - oneOf(checkTask).cancel(); - }}); + expectCancelTask(checkTask); expectRemoveObserverAndListener(); worker.destroy(); @@ -350,13 +482,52 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { check.get().run(); } + @Test + public void testCancelsCheckIfContactConnects() throws Exception { + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send + expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); + expectCheckForDataToSendNoDataWaiting(); + + worker.start(); + + // The worker receives an event that indicates new data may be + // available. The worker should schedule a check for new data after + // a short delay + AtomicReference check = new AtomicReference<>(); + expectScheduleCheck(check, CHECK_DELAY_MS); + + worker.eventOccurred(new MessageSharedEvent(newMessageId, groupId, + groupVisibility)); + + // Before the check task runs, we make a direct connection to the + // contact. The worker should cancel the check + expectCancelTask(checkTask); + + worker.eventOccurred(new ContactConnectedEvent(contactId)); + + // If the check runs anyway (cancellation came too late), it should + // return early when it finds the state has changed + check.get().run(); + + // When the worker is destroyed it should cancel the check and + // remove the connectivity observer and event listener + expectRemoveObserverAndListener(); + + worker.destroy(); + } + @Test public void testRetriesAfterDelayIfExceptionOccursWhileWritingFile() throws Exception { - // When the worker is started it should check for data to send. As - // there's data ready to send immediately, the worker should start a - // connectivity check + // When the worker is started it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // data to send. As there's data ready to send immediately, the worker + // should start a connectivity check expectRunTaskOnIoExecutor(); + expectCheckConnectionRegistry(false); expectCheckForDataToSendAndStartConnectivityCheck(); worker.start(); @@ -375,7 +546,10 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { worker.onConnectivityCheckSucceeded(); - // When the check task runs it should check for new data + // When the check task runs it should check the connection registry. + // We're not connected to the contact, so the worker should check for + // new data + expectCheckConnectionRegistry(false); expectCheckForDataToSendNoDataWaiting(); check.get().run(); @@ -387,6 +561,13 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { worker.destroy(); } + private void expectCheckConnectionRegistry(boolean connected) { + context.checking(new Expectations() {{ + oneOf(connectionRegistry).isConnected(contactId); + will(returnValue(connected)); + }}); + } + private void expectRunTaskOnIoExecutor() { context.checking(new Expectations() {{ oneOf(ioExecutor).execute(with(any(Runnable.class))); @@ -456,6 +637,12 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase { }}); } + private void expectCancelTask(Cancellable task) { + context.checking(new Expectations() {{ + oneOf(task).cancel(); + }}); + } + private void expectRemoveObserverAndListener() { context.checking(new Expectations() {{ oneOf(connectivityChecker).removeObserver(worker);