mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 11:19:04 +01:00
Compare commits
29 Commits
alpha-1.4.
...
checkstyle
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c42af1489 | ||
|
|
4496df723a | ||
|
|
7aafbdd715 | ||
|
|
617a6db84c | ||
|
|
2c295fb096 | ||
|
|
4af895d124 | ||
|
|
3cd388decd | ||
|
|
08551d16cd | ||
|
|
d905cb6cda | ||
|
|
bcc7a4b93b | ||
|
|
4fe9fa3315 | ||
|
|
079ef5b3c0 | ||
|
|
de76986ee4 | ||
|
|
96630e1b34 | ||
|
|
4eddf625d8 | ||
|
|
28ad66a03d | ||
|
|
0af371d026 | ||
|
|
a57c784b47 | ||
|
|
ab360e1e25 | ||
|
|
9990fb3b8f | ||
|
|
148f61a6b5 | ||
|
|
24d4debde0 | ||
|
|
a1f25c8101 | ||
|
|
62883b4bde | ||
|
|
42243f73f4 | ||
|
|
f4365330cb | ||
|
|
d3a06cf2c0 | ||
|
|
339e4daded | ||
|
|
46352f664c |
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble;
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
import org.briarproject.bramble.battery.AndroidBatteryModule;
|
import org.briarproject.bramble.battery.AndroidBatteryModule;
|
||||||
|
import org.briarproject.bramble.io.DnsModule;
|
||||||
import org.briarproject.bramble.network.AndroidNetworkModule;
|
import org.briarproject.bramble.network.AndroidNetworkModule;
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
||||||
import org.briarproject.bramble.reporting.ReportingModule;
|
import org.briarproject.bramble.reporting.ReportingModule;
|
||||||
@@ -18,6 +19,7 @@ import dagger.Module;
|
|||||||
AndroidTaskSchedulerModule.class,
|
AndroidTaskSchedulerModule.class,
|
||||||
AndroidWakefulIoExecutorModule.class,
|
AndroidWakefulIoExecutorModule.class,
|
||||||
CircumventionModule.class,
|
CircumventionModule.class,
|
||||||
|
DnsModule.class,
|
||||||
ReportingModule.class,
|
ReportingModule.class,
|
||||||
SocksModule.class
|
SocksModule.class
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ targetCompatibility = 1.8
|
|||||||
apply plugin: 'ru.vyarus.animalsniffer'
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
|
apply plugin: 'checkstyle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "com.google.dagger:dagger:$dagger_version"
|
implementation "com.google.dagger:dagger:$dagger_version"
|
||||||
|
|||||||
@@ -283,6 +283,13 @@ public interface DatabaseComponent extends TransactionManager {
|
|||||||
*/
|
*/
|
||||||
Group getGroup(Transaction txn, GroupId g) throws DbException;
|
Group getGroup(Transaction txn, GroupId g) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ID of the group containing the given message.
|
||||||
|
* <p/>
|
||||||
|
* Read-only.
|
||||||
|
*/
|
||||||
|
GroupId getGroupId(Transaction txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the metadata for the given group.
|
* Returns the metadata for the given group.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
package org.briarproject.bramble.api.mailbox;
|
package org.briarproject.bramble.api.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.API_CLIENT_TOO_OLD;
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.API_CLIENT_TOO_OLD;
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.API_SERVER_TOO_OLD;
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.API_SERVER_TOO_OLD;
|
||||||
|
|
||||||
class MailboxHelper {
|
@NotNullByDefault
|
||||||
|
public class MailboxHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the highest major version that both client and server support
|
* Returns the highest major version that both client and server support
|
||||||
* or {@link MailboxConstants#API_SERVER_TOO_OLD} if the server is too old
|
* or {@link MailboxConstants#API_SERVER_TOO_OLD} if the server is too old
|
||||||
* or {@link MailboxConstants#API_CLIENT_TOO_OLD} if the client is too old.
|
* or {@link MailboxConstants#API_CLIENT_TOO_OLD} if the client is too old.
|
||||||
*/
|
*/
|
||||||
static int getHighestCommonMajorVersion(
|
public static int getHighestCommonMajorVersion(
|
||||||
List<MailboxVersion> client, List<MailboxVersion> server) {
|
List<MailboxVersion> client, List<MailboxVersion> server) {
|
||||||
TreeSet<Integer> clientVersions = new TreeSet<>();
|
TreeSet<Integer> clientVersions = new TreeSet<>();
|
||||||
for (MailboxVersion version : client) {
|
for (MailboxVersion version : client) {
|
||||||
@@ -32,4 +35,13 @@ class MailboxHelper {
|
|||||||
return API_SERVER_TOO_OLD;
|
return API_SERVER_TOO_OLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a client and server with the given API versions can
|
||||||
|
* communicate with each other (ie, have any major API versions in common).
|
||||||
|
*/
|
||||||
|
public static boolean isClientCompatibleWithServer(
|
||||||
|
List<MailboxVersion> client, List<MailboxVersion> server) {
|
||||||
|
int common = getHighestCommonMajorVersion(client, server);
|
||||||
|
return common != API_CLIENT_TOO_OLD && common != API_SERVER_TOO_OLD;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public interface MailboxSettingsManager {
|
|||||||
|
|
||||||
interface MailboxHook {
|
interface MailboxHook {
|
||||||
/**
|
/**
|
||||||
* Called when Briar is paired with a mailbox
|
* Called when Briar is paired with a mailbox.
|
||||||
*
|
*
|
||||||
* @param txn A read-write transaction
|
* @param txn A read-write transaction
|
||||||
*/
|
*/
|
||||||
@@ -54,10 +54,20 @@ public interface MailboxSettingsManager {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the mailbox is unpaired
|
* Called when the mailbox is unpaired.
|
||||||
*
|
*
|
||||||
* @param txn A read-write transaction
|
* @param txn A read-write transaction
|
||||||
*/
|
*/
|
||||||
void mailboxUnpaired(Transaction txn) throws DbException;
|
void mailboxUnpaired(Transaction txn) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when we receive our mailbox's server-supported API versions.
|
||||||
|
* This happens whenever we successfully check the connectivity of
|
||||||
|
* our mailbox, so this hook may be called frequently.
|
||||||
|
*
|
||||||
|
* @param txn A read-write transaction
|
||||||
|
*/
|
||||||
|
void serverSupportedVersionsReceived(Transaction txn,
|
||||||
|
List<MailboxVersion> serverSupports) throws DbException;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,12 @@ public interface MailboxUpdateManager {
|
|||||||
*/
|
*/
|
||||||
String GROUP_KEY_SENT_CLIENT_SUPPORTS = "sentClientSupports";
|
String GROUP_KEY_SENT_CLIENT_SUPPORTS = "sentClientSupports";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key in the client's local group for storing the serverSupports list that
|
||||||
|
* was last sent out, if any.
|
||||||
|
*/
|
||||||
|
String GROUP_KEY_SENT_SERVER_SUPPORTS = "sentServerSupports";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the latest {@link MailboxUpdate} sent to the given contact.
|
* Returns the latest {@link MailboxUpdate} sent to the given contact.
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -3,27 +3,28 @@ package org.briarproject.bramble.api.mailbox.event;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event that is broadcast when a mailbox update is sent to a contact.
|
* An event that is broadcast when the first mailbox update is sent to a
|
||||||
|
* newly added contact, which happens in the same transaction in which the
|
||||||
|
* contact is added.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that this event is not broadcast when a mailbox is paired or
|
* This event is not broadcast when the first mailbox update is sent to an
|
||||||
* unpaired, although updates are sent to all contacts in those situations.
|
* existing contact when setting up the
|
||||||
*
|
* {@link MailboxUpdateManager mailbox update client}.
|
||||||
* @see MailboxPairedEvent
|
|
||||||
* @see MailboxUnpairedEvent
|
|
||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class MailboxUpdateSentEvent extends Event {
|
public class MailboxUpdateSentToNewContactEvent extends Event {
|
||||||
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final MailboxUpdate mailboxUpdate;
|
private final MailboxUpdate mailboxUpdate;
|
||||||
|
|
||||||
public MailboxUpdateSentEvent(ContactId contactId,
|
public MailboxUpdateSentToNewContactEvent(ContactId contactId,
|
||||||
MailboxUpdate mailboxUpdate) {
|
MailboxUpdate mailboxUpdate) {
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.mailboxUpdate = mailboxUpdate;
|
this.mailboxUpdate = mailboxUpdate;
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
package org.briarproject.bramble.api.sync.event;
|
package org.briarproject.bramble.api.sync.event;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.Group.Visibility;
|
||||||
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,12 +19,32 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
public class MessageSharedEvent extends Event {
|
public class MessageSharedEvent extends Event {
|
||||||
|
|
||||||
private final MessageId messageId;
|
private final MessageId messageId;
|
||||||
|
private final GroupId groupId;
|
||||||
|
private final Map<ContactId, Boolean> groupVisibility;
|
||||||
|
|
||||||
public MessageSharedEvent(MessageId message) {
|
public MessageSharedEvent(MessageId message, GroupId groupId,
|
||||||
|
Map<ContactId, Boolean> groupVisibility) {
|
||||||
this.messageId = message;
|
this.messageId = message;
|
||||||
|
this.groupId = groupId;
|
||||||
|
this.groupVisibility = groupVisibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessageId getMessageId() {
|
public MessageId getMessageId() {
|
||||||
return messageId;
|
return messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GroupId getGroupId() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the IDs of all contacts for which the visibility of the
|
||||||
|
* message's group is either {@link Visibility#SHARED shared} or
|
||||||
|
* {@link Visibility#VISIBLE visible}. The value in the map is true if the
|
||||||
|
* group is {@link Visibility#SHARED shared} or false if the group is
|
||||||
|
* {@link Visibility#VISIBLE visible}.
|
||||||
|
*/
|
||||||
|
public Map<ContactId, Boolean> getGroupVisibility() {
|
||||||
|
return groupVisibility;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ apply plugin: 'idea'
|
|||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
apply from: '../dagger.gradle'
|
apply from: '../dagger.gradle'
|
||||||
|
apply plugin: 'checkstyle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-api', configuration: 'default')
|
implementation project(path: ':bramble-api', configuration: 'default')
|
||||||
|
|||||||
@@ -320,6 +320,13 @@ interface Database<T> {
|
|||||||
*/
|
*/
|
||||||
Group getGroup(T txn, GroupId g) throws DbException;
|
Group getGroup(T txn, GroupId g) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ID of the group containing the given message.
|
||||||
|
* <p/>
|
||||||
|
* Read-only.
|
||||||
|
*/
|
||||||
|
GroupId getGroupId(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the metadata for the given group.
|
* Returns the metadata for the given group.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -345,8 +352,11 @@ interface Database<T> {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of all contacts to which the given group's visibility is
|
* Returns the IDs of all contacts for which the given group's visibility
|
||||||
* either {@link Visibility VISIBLE} or {@link Visibility SHARED}.
|
* is either {@link Visibility#SHARED shared} or
|
||||||
|
* {@link Visibility#VISIBLE visible}. The value in the map is true if the
|
||||||
|
* group is {@link Visibility#SHARED shared} or false if the group is
|
||||||
|
* {@link Visibility#VISIBLE visible}.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -287,7 +287,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
transaction.attach(new MessageAddedEvent(m, null));
|
transaction.attach(new MessageAddedEvent(m, null));
|
||||||
transaction.attach(new MessageStateChangedEvent(m.getId(), true,
|
transaction.attach(new MessageStateChangedEvent(m.getId(), true,
|
||||||
DELIVERED));
|
DELIVERED));
|
||||||
if (shared) transaction.attach(new MessageSharedEvent(m.getId()));
|
if (shared) {
|
||||||
|
Map<ContactId, Boolean> visibility =
|
||||||
|
db.getGroupVisibility(txn, m.getGroupId());
|
||||||
|
transaction.attach(new MessageSharedEvent(m.getId(),
|
||||||
|
m.getGroupId(), visibility));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
db.mergeMessageMetadata(txn, m.getId(), meta);
|
db.mergeMessageMetadata(txn, m.getId(), meta);
|
||||||
}
|
}
|
||||||
@@ -550,6 +555,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
return db.getGroup(txn, g);
|
return db.getGroup(txn, g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupId getGroupId(Transaction transaction, MessageId m)
|
||||||
|
throws DbException {
|
||||||
|
T txn = unbox(transaction);
|
||||||
|
if (!db.containsMessage(txn, m))
|
||||||
|
throw new NoSuchMessageException();
|
||||||
|
return db.getGroupId(txn, m);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Metadata getGroupMetadata(Transaction transaction, GroupId g)
|
public Metadata getGroupMetadata(Transaction transaction, GroupId g)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -1182,7 +1196,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
if (db.getMessageState(txn, m) != DELIVERED)
|
if (db.getMessageState(txn, m) != DELIVERED)
|
||||||
throw new IllegalArgumentException("Shared undelivered message");
|
throw new IllegalArgumentException("Shared undelivered message");
|
||||||
db.setMessageShared(txn, m, true);
|
db.setMessageShared(txn, m, true);
|
||||||
transaction.attach(new MessageSharedEvent(m));
|
GroupId g = db.getGroupId(txn, m);
|
||||||
|
Map<ContactId, Boolean> visibility = db.getGroupVisibility(txn, g);
|
||||||
|
transaction.attach(new MessageSharedEvent(m, g, visibility));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1683,6 +1683,27 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupId getGroupId(Connection txn, MessageId m) throws DbException {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
String sql = "SELECT groupId FROM messages WHERE messageId = ?";
|
||||||
|
ps = txn.prepareStatement(sql);
|
||||||
|
ps.setBytes(1, m.getBytes());
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
if (!rs.next()) throw new DbStateException();
|
||||||
|
GroupId g = new GroupId(rs.getBytes(1));
|
||||||
|
rs.close();
|
||||||
|
ps.close();
|
||||||
|
return g;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
tryToClose(rs, LOG, WARNING);
|
||||||
|
tryToClose(ps, LOG, WARNING);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Group> getGroups(Connection txn, ClientId c,
|
public Collection<Group> getGroups(Connection txn, ClientId c,
|
||||||
int majorVersion) throws DbException {
|
int majorVersion) throws DbException {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.feed;
|
package org.briarproject.bramble.io;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
package org.briarproject.briar.feed;
|
package org.briarproject.bramble.io;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
@@ -9,6 +11,7 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import okhttp3.Dns;
|
import okhttp3.Dns;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
class NoDns implements Dns {
|
class NoDns implements Dns {
|
||||||
|
|
||||||
private static final byte[] UNSPECIFIED_ADDRESS = new byte[4];
|
private static final byte[] UNSPECIFIED_ADDRESS = new byte[4];
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
@@ -10,15 +14,21 @@ import javax.inject.Provider;
|
|||||||
class MailboxClientFactoryImpl implements MailboxClientFactory {
|
class MailboxClientFactoryImpl implements MailboxClientFactory {
|
||||||
|
|
||||||
private final MailboxWorkerFactory workerFactory;
|
private final MailboxWorkerFactory workerFactory;
|
||||||
|
private final TaskScheduler taskScheduler;
|
||||||
|
private final Executor ioExecutor;
|
||||||
private final Provider<ContactMailboxConnectivityChecker>
|
private final Provider<ContactMailboxConnectivityChecker>
|
||||||
contactCheckerProvider;
|
contactCheckerProvider;
|
||||||
private final Provider<OwnMailboxConnectivityChecker> ownCheckerProvider;
|
private final Provider<OwnMailboxConnectivityChecker> ownCheckerProvider;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
MailboxClientFactoryImpl(MailboxWorkerFactory workerFactory,
|
MailboxClientFactoryImpl(MailboxWorkerFactory workerFactory,
|
||||||
|
TaskScheduler taskScheduler,
|
||||||
|
@IoExecutor Executor ioExecutor,
|
||||||
Provider<ContactMailboxConnectivityChecker> contactCheckerProvider,
|
Provider<ContactMailboxConnectivityChecker> contactCheckerProvider,
|
||||||
Provider<OwnMailboxConnectivityChecker> ownCheckerProvider) {
|
Provider<OwnMailboxConnectivityChecker> ownCheckerProvider) {
|
||||||
this.workerFactory = workerFactory;
|
this.workerFactory = workerFactory;
|
||||||
|
this.taskScheduler = taskScheduler;
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
this.contactCheckerProvider = contactCheckerProvider;
|
this.contactCheckerProvider = contactCheckerProvider;
|
||||||
this.ownCheckerProvider = ownCheckerProvider;
|
this.ownCheckerProvider = ownCheckerProvider;
|
||||||
}
|
}
|
||||||
@@ -37,6 +47,6 @@ class MailboxClientFactoryImpl implements MailboxClientFactory {
|
|||||||
MailboxProperties properties) {
|
MailboxProperties properties) {
|
||||||
ConnectivityChecker connectivityChecker = ownCheckerProvider.get();
|
ConnectivityChecker connectivityChecker = ownCheckerProvider.get();
|
||||||
return new OwnMailboxClient(workerFactory, connectivityChecker,
|
return new OwnMailboxClient(workerFactory, connectivityChecker,
|
||||||
reachabilityMonitor, properties);
|
reachabilityMonitor, taskScheduler, ioExecutor, properties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,667 @@
|
|||||||
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
|
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.event.EventExecutor;
|
||||||
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||||
|
import org.briarproject.bramble.api.mailbox.event.MailboxPairedEvent;
|
||||||
|
import org.briarproject.bramble.api.mailbox.event.MailboxUnpairedEvent;
|
||||||
|
import org.briarproject.bramble.api.mailbox.event.MailboxUpdateSentToNewContactEvent;
|
||||||
|
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
|
||||||
|
import org.briarproject.bramble.api.mailbox.event.RemoteMailboxUpdateEvent;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
|
import org.briarproject.bramble.api.plugin.event.TransportActiveEvent;
|
||||||
|
import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
||||||
|
import static org.briarproject.bramble.api.mailbox.MailboxHelper.isClientCompatibleWithServer;
|
||||||
|
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||||
|
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
|
||||||
|
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component manages a {@link MailboxClient} for each mailbox we know
|
||||||
|
* about and are able to use (our own mailbox and/or contacts' mailboxes).
|
||||||
|
* The clients are created when we come online (i.e. when the Tor plugin
|
||||||
|
* becomes {@link Plugin.State#ACTIVE active}) and destroyed when we go
|
||||||
|
* offline.
|
||||||
|
* <p/>
|
||||||
|
* The manager keeps track of the latest {@link MailboxUpdate} sent to and
|
||||||
|
* received from each contact. These updates are used to decide which
|
||||||
|
* mailboxes the manager needs clients for, and which mailbox (if any) should
|
||||||
|
* be used for uploading data to and/or downloading data from each contact.
|
||||||
|
* <p/>
|
||||||
|
* The assignments of contacts to mailboxes for upload and/or download may
|
||||||
|
* change when the following events happen:
|
||||||
|
* <ul>
|
||||||
|
* <li> A mailbox is paired or unpaired </li>
|
||||||
|
* <li> A contact is added or removed </li>
|
||||||
|
* <li> A {@link MailboxUpdate} is received from a contact </li>
|
||||||
|
* <li> We discover that our own mailbox's supported API versions have
|
||||||
|
* changed </li>
|
||||||
|
* </ul>
|
||||||
|
* <p/>
|
||||||
|
* The manager keeps its mutable state consistent with the state in the DB by
|
||||||
|
* using commit actions and events to update the manager's state on the event
|
||||||
|
* thread.
|
||||||
|
*/
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
class MailboxClientManager implements Service, EventListener {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(MailboxClientManager.class.getName());
|
||||||
|
|
||||||
|
private final Executor eventExecutor, dbExecutor;
|
||||||
|
private final TransactionManager db;
|
||||||
|
private final ContactManager contactManager;
|
||||||
|
private final PluginManager pluginManager;
|
||||||
|
private final MailboxSettingsManager mailboxSettingsManager;
|
||||||
|
private final MailboxUpdateManager mailboxUpdateManager;
|
||||||
|
private final MailboxClientFactory mailboxClientFactory;
|
||||||
|
private final TorReachabilityMonitor reachabilityMonitor;
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
// All of the following mutable state must only be accessed on the
|
||||||
|
// event thread
|
||||||
|
private final Map<ContactId, Updates> contactUpdates = new HashMap<>();
|
||||||
|
private final Map<ContactId, MailboxClient> contactClients =
|
||||||
|
new HashMap<>();
|
||||||
|
@Nullable
|
||||||
|
private MailboxProperties ownProperties = null;
|
||||||
|
@Nullable
|
||||||
|
private MailboxClient ownClient = null;
|
||||||
|
private boolean online = false, handleEvents = false;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MailboxClientManager(@EventExecutor Executor eventExecutor,
|
||||||
|
@DatabaseExecutor Executor dbExecutor,
|
||||||
|
TransactionManager db,
|
||||||
|
ContactManager contactManager,
|
||||||
|
PluginManager pluginManager,
|
||||||
|
MailboxSettingsManager mailboxSettingsManager,
|
||||||
|
MailboxUpdateManager mailboxUpdateManager,
|
||||||
|
MailboxClientFactory mailboxClientFactory,
|
||||||
|
TorReachabilityMonitor reachabilityMonitor) {
|
||||||
|
this.eventExecutor = eventExecutor;
|
||||||
|
this.dbExecutor = dbExecutor;
|
||||||
|
this.db = db;
|
||||||
|
this.contactManager = contactManager;
|
||||||
|
this.pluginManager = pluginManager;
|
||||||
|
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||||
|
this.mailboxUpdateManager = mailboxUpdateManager;
|
||||||
|
this.mailboxClientFactory = mailboxClientFactory;
|
||||||
|
this.reachabilityMonitor = reachabilityMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startService() throws ServiceException {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
|
reachabilityMonitor.start();
|
||||||
|
dbExecutor.execute(this::loadMailboxProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DatabaseExecutor
|
||||||
|
private void loadMailboxProperties() {
|
||||||
|
LOG.info("Loading mailbox properties");
|
||||||
|
try {
|
||||||
|
db.transaction(true, txn -> {
|
||||||
|
Map<ContactId, Updates> updates = new HashMap<>();
|
||||||
|
for (Contact c : contactManager.getContacts(txn)) {
|
||||||
|
MailboxUpdate local = mailboxUpdateManager
|
||||||
|
.getLocalUpdate(txn, c.getId());
|
||||||
|
MailboxUpdate remote = mailboxUpdateManager
|
||||||
|
.getRemoteUpdate(txn, c.getId());
|
||||||
|
updates.put(c.getId(), new Updates(local, remote));
|
||||||
|
}
|
||||||
|
MailboxProperties ownProps =
|
||||||
|
mailboxSettingsManager.getOwnMailboxProperties(txn);
|
||||||
|
// Use a commit action so the state in memory remains
|
||||||
|
// consistent with the state in the DB
|
||||||
|
txn.attach(() -> initialiseState(updates, ownProps));
|
||||||
|
});
|
||||||
|
} catch (DbException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void initialiseState(Map<ContactId, Updates> updates,
|
||||||
|
@Nullable MailboxProperties ownProps) {
|
||||||
|
contactUpdates.putAll(updates);
|
||||||
|
ownProperties = ownProps;
|
||||||
|
Plugin tor = pluginManager.getPlugin(ID);
|
||||||
|
if (tor != null && tor.getState() == ACTIVE) {
|
||||||
|
LOG.info("Online");
|
||||||
|
online = true;
|
||||||
|
createClients();
|
||||||
|
}
|
||||||
|
// Now that the mutable state has been initialised we can start
|
||||||
|
// handling events. This is done in a commit action so that we don't
|
||||||
|
// miss any changes to the DB state or handle events for any changes
|
||||||
|
// that were already reflected in the initial load
|
||||||
|
handleEvents = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void createClients() {
|
||||||
|
LOG.info("Creating clients");
|
||||||
|
for (Entry<ContactId, Updates> e : contactUpdates.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
Updates u = e.getValue();
|
||||||
|
if (isContactMailboxUsable(u.remote)) {
|
||||||
|
// Create and start a client for the contact's mailbox
|
||||||
|
MailboxClient contactClient = createAndStartClient(c);
|
||||||
|
// Assign the contact to the contact's mailbox for upload
|
||||||
|
assignContactToContactMailboxForUpload(c, contactClient, u);
|
||||||
|
if (!isOwnMailboxUsable(ownProperties, u.remote)) {
|
||||||
|
// We don't have a usable mailbox, so assign the contact to
|
||||||
|
// the contact's mailbox for download too
|
||||||
|
assignContactToContactMailboxForDownload(c,
|
||||||
|
contactClient, u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ownProperties == null) return;
|
||||||
|
if (!isOwnMailboxUsable(ownProperties)) {
|
||||||
|
LOG.warning("We have a mailbox but we can't use it");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Create and start a client for our mailbox
|
||||||
|
createAndStartClientForOwnMailbox();
|
||||||
|
// Assign contacts to our mailbox for upload/download
|
||||||
|
for (Entry<ContactId, Updates> e : contactUpdates.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
Updates u = e.getValue();
|
||||||
|
if (isOwnMailboxUsable(ownProperties, u.remote)) {
|
||||||
|
// Assign the contact to our mailbox for download
|
||||||
|
assignContactToOwnMailboxForDownload(c, u);
|
||||||
|
if (!isContactMailboxUsable(u.remote)) {
|
||||||
|
// The contact doesn't have a usable mailbox, so assign
|
||||||
|
// the contact to our mailbox for upload too
|
||||||
|
assignContactToOwnMailboxForUpload(c, u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopService() throws ServiceException {
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
eventExecutor.execute(() -> {
|
||||||
|
handleEvents = false;
|
||||||
|
if (online) destroyClients();
|
||||||
|
latch.countDown();
|
||||||
|
});
|
||||||
|
reachabilityMonitor.destroy();
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new ServiceException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void destroyClients() {
|
||||||
|
LOG.info("Destroying clients");
|
||||||
|
for (MailboxClient client : contactClients.values()) {
|
||||||
|
client.destroy();
|
||||||
|
}
|
||||||
|
contactClients.clear();
|
||||||
|
destroyOwnClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void destroyOwnClient() {
|
||||||
|
if (ownClient != null) {
|
||||||
|
ownClient.destroy();
|
||||||
|
ownClient = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eventOccurred(Event e) {
|
||||||
|
if (!handleEvents) return;
|
||||||
|
if (e instanceof TransportActiveEvent) {
|
||||||
|
TransportActiveEvent t = (TransportActiveEvent) e;
|
||||||
|
if (t.getTransportId().equals(ID)) onTorActive();
|
||||||
|
} else if (e instanceof TransportInactiveEvent) {
|
||||||
|
TransportInactiveEvent t = (TransportInactiveEvent) e;
|
||||||
|
if (t.getTransportId().equals(ID)) onTorInactive();
|
||||||
|
} else if (e instanceof MailboxPairedEvent) {
|
||||||
|
LOG.info("Mailbox paired");
|
||||||
|
MailboxPairedEvent m = (MailboxPairedEvent) e;
|
||||||
|
onMailboxPaired(m.getProperties(), m.getLocalUpdates());
|
||||||
|
} else if (e instanceof MailboxUnpairedEvent) {
|
||||||
|
LOG.info("Mailbox unpaired");
|
||||||
|
MailboxUnpairedEvent m = (MailboxUnpairedEvent) e;
|
||||||
|
onMailboxUnpaired(m.getLocalUpdates());
|
||||||
|
} else if (e instanceof MailboxUpdateSentToNewContactEvent) {
|
||||||
|
LOG.info("Contact added");
|
||||||
|
MailboxUpdateSentToNewContactEvent
|
||||||
|
m = (MailboxUpdateSentToNewContactEvent) e;
|
||||||
|
onContactAdded(m.getContactId(), m.getMailboxUpdate());
|
||||||
|
} else if (e instanceof ContactRemovedEvent) {
|
||||||
|
LOG.info("Contact removed");
|
||||||
|
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
||||||
|
onContactRemoved(c.getContactId());
|
||||||
|
} else if (e instanceof RemoteMailboxUpdateEvent) {
|
||||||
|
LOG.info("Remote mailbox update");
|
||||||
|
RemoteMailboxUpdateEvent r = (RemoteMailboxUpdateEvent) e;
|
||||||
|
onRemoteMailboxUpdate(r.getContact(), r.getMailboxUpdate());
|
||||||
|
} else if (e instanceof OwnMailboxConnectionStatusEvent) {
|
||||||
|
OwnMailboxConnectionStatusEvent o =
|
||||||
|
(OwnMailboxConnectionStatusEvent) e;
|
||||||
|
onOwnMailboxConnectionStatusChanged(o.getStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void onTorActive() {
|
||||||
|
// If we checked the plugin at startup concurrently with the plugin
|
||||||
|
// becoming active then `online` may already be true when we receive
|
||||||
|
// the first TransportActiveEvent, in which case ignore it
|
||||||
|
if (online) return;
|
||||||
|
LOG.info("Online");
|
||||||
|
online = true;
|
||||||
|
createClients();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void onTorInactive() {
|
||||||
|
// If we checked the plugin at startup concurrently with the plugin
|
||||||
|
// becoming inactive then `online` may already be false when we
|
||||||
|
// receive the first TransportInactiveEvent, in which case ignore it
|
||||||
|
if (!online) return;
|
||||||
|
LOG.info("Offline");
|
||||||
|
online = false;
|
||||||
|
destroyClients();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void onMailboxPaired(MailboxProperties ownProps,
|
||||||
|
Map<ContactId, MailboxUpdateWithMailbox> localUpdates) {
|
||||||
|
for (Entry<ContactId, MailboxUpdateWithMailbox> e :
|
||||||
|
localUpdates.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
Updates u = contactUpdates.get(c);
|
||||||
|
contactUpdates.put(c, new Updates(e.getValue(), u.remote));
|
||||||
|
}
|
||||||
|
ownProperties = ownProps;
|
||||||
|
if (!online) return;
|
||||||
|
if (!isOwnMailboxUsable(ownProperties)) {
|
||||||
|
LOG.warning("We have a mailbox but we can't use it");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Create and start a client for our mailbox
|
||||||
|
createAndStartClientForOwnMailbox();
|
||||||
|
// Assign contacts to our mailbox for upload/download
|
||||||
|
for (Entry<ContactId, Updates> e : contactUpdates.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
Updates u = e.getValue();
|
||||||
|
if (!isOwnMailboxUsable(ownProperties, u.remote)) {
|
||||||
|
// Our mailbox isn't usable for communicating with this
|
||||||
|
// contact, so don't assign/reassign this contact
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isContactMailboxUsable(u.remote)) {
|
||||||
|
// The contact has a usable mailbox, so the contact should
|
||||||
|
// currently be assigned to the contact's mailbox for upload
|
||||||
|
// and download. Reassign the contact to our mailbox for
|
||||||
|
// download
|
||||||
|
MailboxClient contactClient =
|
||||||
|
requireNonNull(contactClients.get(c));
|
||||||
|
contactClient.deassignContactForDownload(c);
|
||||||
|
} else {
|
||||||
|
// The contact doesn't have a usable mailbox, so assign the
|
||||||
|
// contact to our mailbox for upload
|
||||||
|
assignContactToOwnMailboxForUpload(c, u);
|
||||||
|
}
|
||||||
|
assignContactToOwnMailboxForDownload(c, u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void onMailboxUnpaired(Map<ContactId, MailboxUpdate> localUpdates) {
|
||||||
|
for (Entry<ContactId, MailboxUpdate> e : localUpdates.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
Updates updates = contactUpdates.get(c);
|
||||||
|
contactUpdates.put(c, new Updates(e.getValue(), updates.remote));
|
||||||
|
}
|
||||||
|
MailboxProperties oldOwnProperties = ownProperties;
|
||||||
|
ownProperties = null;
|
||||||
|
if (!online) return;
|
||||||
|
// Destroy the client for our own mailbox, if any
|
||||||
|
destroyOwnClient();
|
||||||
|
// Reassign contacts to their own mailboxes for download where possible
|
||||||
|
for (Entry<ContactId, Updates> e : contactUpdates.entrySet()) {
|
||||||
|
ContactId c = e.getKey();
|
||||||
|
Updates u = e.getValue();
|
||||||
|
if (isContactMailboxUsable(u.remote) &&
|
||||||
|
isOwnMailboxUsable(oldOwnProperties, u.remote)) {
|
||||||
|
// The contact should currently be assigned to our mailbox
|
||||||
|
// for download. Reassign the contact to the contact's
|
||||||
|
// mailbox for download
|
||||||
|
MailboxClient contactClient =
|
||||||
|
requireNonNull(contactClients.get(c));
|
||||||
|
assignContactToContactMailboxForDownload(c, contactClient, u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void onContactAdded(ContactId c, MailboxUpdate u) {
|
||||||
|
Updates old = contactUpdates.put(c, new Updates(u, null));
|
||||||
|
if (old != null) throw new IllegalStateException();
|
||||||
|
// We haven't yet received an update from the newly added contact,
|
||||||
|
// so at this stage we don't need to assign the contact to any
|
||||||
|
// mailboxes for upload or download
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void onContactRemoved(ContactId c) {
|
||||||
|
Updates updates = requireNonNull(contactUpdates.remove(c));
|
||||||
|
if (!online) return;
|
||||||
|
// Destroy the client for the contact's mailbox, if any
|
||||||
|
MailboxClient client = contactClients.remove(c);
|
||||||
|
if (client != null) client.destroy();
|
||||||
|
// If we have a mailbox and the contact is assigned to it for upload
|
||||||
|
// and/or download, deassign the contact
|
||||||
|
if (ownProperties == null) return;
|
||||||
|
if (isOwnMailboxUsable(ownProperties, updates.remote)) {
|
||||||
|
// We have a usable mailbox, so the contact should currently be
|
||||||
|
// assigned to our mailbox for download. Deassign the contact from
|
||||||
|
// our mailbox for download
|
||||||
|
requireNonNull(ownClient).deassignContactForDownload(c);
|
||||||
|
if (!isContactMailboxUsable(updates.remote)) {
|
||||||
|
// The contact doesn't have a usable mailbox, so the contact
|
||||||
|
// should currently be assigned to our mailbox for upload.
|
||||||
|
// Deassign the contact from our mailbox for upload
|
||||||
|
requireNonNull(ownClient).deassignContactForUpload(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void onRemoteMailboxUpdate(ContactId c, MailboxUpdate remote) {
|
||||||
|
Updates old = contactUpdates.get(c);
|
||||||
|
MailboxUpdate oldRemote = old.remote;
|
||||||
|
Updates u = new Updates(old.local, remote);
|
||||||
|
contactUpdates.put(c, u);
|
||||||
|
if (!online) return;
|
||||||
|
// What may have changed?
|
||||||
|
// * Contact's mailbox may be usable now, was unusable before
|
||||||
|
// * Contact's mailbox may be unusable now, was usable before
|
||||||
|
// * Contact's mailbox may have been replaced
|
||||||
|
// * Contact's mailbox may have changed its API versions
|
||||||
|
// * Contact may be able to use our mailbox now, was unable before
|
||||||
|
// * Contact may be unable to use our mailbox now, was able before
|
||||||
|
boolean wasContactMailboxUsable = isContactMailboxUsable(oldRemote);
|
||||||
|
boolean isContactMailboxUsable = isContactMailboxUsable(remote);
|
||||||
|
boolean wasOwnMailboxUsable =
|
||||||
|
isOwnMailboxUsable(ownProperties, oldRemote);
|
||||||
|
boolean isOwnMailboxUsable = isOwnMailboxUsable(ownProperties, remote);
|
||||||
|
|
||||||
|
// Create/destroy/replace the client for the contact's mailbox if needed
|
||||||
|
MailboxClient contactClient = null;
|
||||||
|
boolean clientReplaced = false;
|
||||||
|
if (isContactMailboxUsable) {
|
||||||
|
if (wasContactMailboxUsable) {
|
||||||
|
MailboxProperties oldProps = getMailboxProperties(oldRemote);
|
||||||
|
MailboxProperties newProps = getMailboxProperties(remote);
|
||||||
|
if (oldProps.equals(newProps)) {
|
||||||
|
// The contact previously had a usable mailbox, now has
|
||||||
|
// a usable mailbox, it's the same mailbox, and its API
|
||||||
|
// versions haven't changed. Keep using the existing client
|
||||||
|
contactClient = requireNonNull(contactClients.get(c));
|
||||||
|
} else {
|
||||||
|
// The contact previously had a usable mailbox and now has
|
||||||
|
// a usable mailbox, but either it's a new mailbox or its
|
||||||
|
// API versions have changed. Replace the client
|
||||||
|
requireNonNull(contactClients.remove(c)).destroy();
|
||||||
|
contactClient = createAndStartClient(c);
|
||||||
|
clientReplaced = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The client didn't previously have a usable mailbox but now
|
||||||
|
// has one. Create and start a client
|
||||||
|
contactClient = createAndStartClient(c);
|
||||||
|
}
|
||||||
|
} else if (wasContactMailboxUsable) {
|
||||||
|
// The client previously had a usable mailbox but no longer does.
|
||||||
|
// Destroy the existing client
|
||||||
|
requireNonNull(contactClients.remove(c)).destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean wasAssignedToOwnMailboxForUpload =
|
||||||
|
wasOwnMailboxUsable && !wasContactMailboxUsable;
|
||||||
|
boolean willBeAssignedToOwnMailboxForUpload =
|
||||||
|
isOwnMailboxUsable && !isContactMailboxUsable;
|
||||||
|
|
||||||
|
boolean wasAssignedToContactMailboxForDownload =
|
||||||
|
!wasOwnMailboxUsable && wasContactMailboxUsable;
|
||||||
|
boolean willBeAssignedToContactMailboxForDownload =
|
||||||
|
!isOwnMailboxUsable && isContactMailboxUsable;
|
||||||
|
|
||||||
|
// Deassign the contact for upload/download if needed
|
||||||
|
if (wasAssignedToOwnMailboxForUpload &&
|
||||||
|
!willBeAssignedToOwnMailboxForUpload) {
|
||||||
|
requireNonNull(ownClient).deassignContactForUpload(c);
|
||||||
|
}
|
||||||
|
if (wasOwnMailboxUsable && !isOwnMailboxUsable) {
|
||||||
|
requireNonNull(ownClient).deassignContactForDownload(c);
|
||||||
|
}
|
||||||
|
// If the client for the contact's mailbox was replaced or destroyed
|
||||||
|
// above then we don't need to deassign the contact for download
|
||||||
|
if (wasAssignedToContactMailboxForDownload &&
|
||||||
|
!willBeAssignedToContactMailboxForDownload &&
|
||||||
|
!clientReplaced && isContactMailboxUsable) {
|
||||||
|
requireNonNull(contactClient).deassignContactForDownload(c);
|
||||||
|
}
|
||||||
|
// We never need to deassign the contact from the contact's mailbox for
|
||||||
|
// upload: this would only be needed if the contact's mailbox were no
|
||||||
|
// longer usable, in which case the client would already have been
|
||||||
|
// destroyed above. Thanks to the linter for spotting this
|
||||||
|
|
||||||
|
// Assign the contact for upload/download if needed
|
||||||
|
if (!wasAssignedToOwnMailboxForUpload &&
|
||||||
|
willBeAssignedToOwnMailboxForUpload) {
|
||||||
|
assignContactToOwnMailboxForUpload(c, u);
|
||||||
|
}
|
||||||
|
if (!wasOwnMailboxUsable && isOwnMailboxUsable) {
|
||||||
|
assignContactToOwnMailboxForDownload(c, u);
|
||||||
|
}
|
||||||
|
if ((!wasContactMailboxUsable || clientReplaced) &&
|
||||||
|
isContactMailboxUsable) {
|
||||||
|
assignContactToContactMailboxForUpload(c, contactClient, u);
|
||||||
|
}
|
||||||
|
if ((!wasAssignedToContactMailboxForDownload || clientReplaced) &&
|
||||||
|
willBeAssignedToContactMailboxForDownload) {
|
||||||
|
assignContactToContactMailboxForDownload(c, contactClient, u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void onOwnMailboxConnectionStatusChanged(MailboxStatus status) {
|
||||||
|
if (!online || ownProperties == null) return;
|
||||||
|
List<MailboxVersion> oldServerSupports =
|
||||||
|
ownProperties.getServerSupports();
|
||||||
|
List<MailboxVersion> newServerSupports = status.getServerSupports();
|
||||||
|
if (!oldServerSupports.equals(newServerSupports)) {
|
||||||
|
LOG.info("Our mailbox's supported API versions have changed");
|
||||||
|
// This potentially affects every assignment of contacts to
|
||||||
|
// mailboxes for upload and download, so just rebuild the clients
|
||||||
|
// and assignments from scratch
|
||||||
|
destroyClients();
|
||||||
|
createClients();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void createAndStartClientForOwnMailbox() {
|
||||||
|
if (ownClient != null) throw new IllegalStateException();
|
||||||
|
ownClient = mailboxClientFactory.createOwnMailboxClient(
|
||||||
|
reachabilityMonitor, requireNonNull(ownProperties));
|
||||||
|
ownClient.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private MailboxClient createAndStartClient(ContactId c) {
|
||||||
|
MailboxClient client = mailboxClientFactory
|
||||||
|
.createContactMailboxClient(reachabilityMonitor);
|
||||||
|
MailboxClient old = contactClients.put(c, client);
|
||||||
|
if (old != null) throw new IllegalStateException();
|
||||||
|
client.start();
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void assignContactToOwnMailboxForDownload(ContactId c, Updates u) {
|
||||||
|
MailboxProperties localProps = getMailboxProperties(u.local);
|
||||||
|
requireNonNull(ownClient).assignContactForDownload(c,
|
||||||
|
requireNonNull(ownProperties),
|
||||||
|
requireNonNull(localProps.getOutboxId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void assignContactToOwnMailboxForUpload(ContactId c, Updates u) {
|
||||||
|
MailboxProperties localProps = getMailboxProperties(u.local);
|
||||||
|
requireNonNull(ownClient).assignContactForUpload(c,
|
||||||
|
requireNonNull(ownProperties),
|
||||||
|
requireNonNull(localProps.getInboxId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void assignContactToContactMailboxForDownload(ContactId c,
|
||||||
|
MailboxClient contactClient, Updates u) {
|
||||||
|
MailboxProperties remoteProps =
|
||||||
|
getMailboxProperties(requireNonNull(u.remote));
|
||||||
|
contactClient.assignContactForDownload(c, remoteProps,
|
||||||
|
requireNonNull(remoteProps.getInboxId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventExecutor
|
||||||
|
private void assignContactToContactMailboxForUpload(ContactId c,
|
||||||
|
MailboxClient contactClient, Updates u) {
|
||||||
|
MailboxProperties remoteProps =
|
||||||
|
getMailboxProperties(requireNonNull(u.remote));
|
||||||
|
contactClient.assignContactForUpload(c, remoteProps,
|
||||||
|
requireNonNull(remoteProps.getOutboxId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link MailboxProperties} included in the given update,
|
||||||
|
* which must be a {@link MailboxUpdateWithMailbox}.
|
||||||
|
*/
|
||||||
|
private MailboxProperties getMailboxProperties(MailboxUpdate update) {
|
||||||
|
if (!(update instanceof MailboxUpdateWithMailbox)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
MailboxUpdateWithMailbox mailbox = (MailboxUpdateWithMailbox) update;
|
||||||
|
return mailbox.getMailboxProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if we can use our own mailbox to communicate with the
|
||||||
|
* contact that sent the given update.
|
||||||
|
*/
|
||||||
|
private boolean isOwnMailboxUsable(
|
||||||
|
@Nullable MailboxProperties ownProperties,
|
||||||
|
@Nullable MailboxUpdate remote) {
|
||||||
|
if (ownProperties == null || remote == null) return false;
|
||||||
|
return isMailboxUsable(remote.getClientSupports(),
|
||||||
|
ownProperties.getServerSupports());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if we can use the contact's mailbox to communicate with
|
||||||
|
* the contact that sent the given update.
|
||||||
|
*/
|
||||||
|
private boolean isContactMailboxUsable(@Nullable MailboxUpdate remote) {
|
||||||
|
if (remote instanceof MailboxUpdateWithMailbox) {
|
||||||
|
MailboxUpdateWithMailbox remoteMailbox =
|
||||||
|
(MailboxUpdateWithMailbox) remote;
|
||||||
|
return isMailboxUsable(remoteMailbox.getClientSupports(),
|
||||||
|
remoteMailbox.getMailboxProperties().getServerSupports());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if we can communicate with a contact that has the given
|
||||||
|
* client-supported API versions via a mailbox with the given
|
||||||
|
* server-supported API versions.
|
||||||
|
*/
|
||||||
|
private boolean isMailboxUsable(List<MailboxVersion> contactClient,
|
||||||
|
List<MailboxVersion> server) {
|
||||||
|
return isClientCompatibleWithServer(contactClient, server)
|
||||||
|
&& isClientCompatibleWithServer(CLIENT_SUPPORTS, server);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if our client-supported API versions are compatible with
|
||||||
|
* our own mailbox's server-supported API versions.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
|
private boolean isOwnMailboxUsable(MailboxProperties ownProperties) {
|
||||||
|
return isClientCompatibleWithServer(CLIENT_SUPPORTS,
|
||||||
|
ownProperties.getServerSupports());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A container for the latest {@link MailboxUpdate updates} sent to and
|
||||||
|
* received from a given contact.
|
||||||
|
*/
|
||||||
|
private static class Updates {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The latest update sent to the contact.
|
||||||
|
*/
|
||||||
|
private final MailboxUpdate local;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The latest update received from the contact, or null if no update
|
||||||
|
* has been received.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private final MailboxUpdate remote;
|
||||||
|
|
||||||
|
private Updates(MailboxUpdate local, @Nullable MailboxUpdate remote) {
|
||||||
|
this.local = local;
|
||||||
|
this.remote = remote;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,17 +4,22 @@ import org.briarproject.bramble.api.FeatureFlags;
|
|||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.data.MetadataEncoder;
|
import org.briarproject.bramble.api.data.MetadataEncoder;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.event.EventExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxManager;
|
import org.briarproject.bramble.api.mailbox.MailboxManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
import org.briarproject.bramble.api.sync.validation.ValidationManager;
|
import org.briarproject.bramble.api.sync.validation.ValidationManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -37,6 +42,8 @@ public class MailboxModule {
|
|||||||
MailboxUpdateManager mailboxUpdateManager;
|
MailboxUpdateManager mailboxUpdateManager;
|
||||||
@Inject
|
@Inject
|
||||||
MailboxFileManager mailboxFileManager;
|
MailboxFileManager mailboxFileManager;
|
||||||
|
@Inject
|
||||||
|
MailboxClientManager mailboxClientManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -126,4 +133,49 @@ public class MailboxModule {
|
|||||||
MailboxWorkerFactoryImpl mailboxWorkerFactory) {
|
MailboxWorkerFactoryImpl mailboxWorkerFactory) {
|
||||||
return mailboxWorkerFactory;
|
return mailboxWorkerFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
MailboxClientFactory provideMailboxClientFactory(
|
||||||
|
MailboxClientFactoryImpl mailboxClientFactory) {
|
||||||
|
return mailboxClientFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
MailboxApiCaller provideMailboxApiCaller(
|
||||||
|
MailboxApiCallerImpl mailboxApiCaller) {
|
||||||
|
return mailboxApiCaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
TorReachabilityMonitor provideTorReachabilityMonitor(
|
||||||
|
TorReachabilityMonitorImpl reachabilityMonitor) {
|
||||||
|
return reachabilityMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
MailboxClientManager provideMailboxClientManager(
|
||||||
|
@EventExecutor Executor eventExecutor,
|
||||||
|
@DatabaseExecutor Executor dbExecutor,
|
||||||
|
TransactionManager db,
|
||||||
|
ContactManager contactManager,
|
||||||
|
PluginManager pluginManager,
|
||||||
|
MailboxSettingsManager mailboxSettingsManager,
|
||||||
|
MailboxUpdateManager mailboxUpdateManager,
|
||||||
|
MailboxClientFactory mailboxClientFactory,
|
||||||
|
TorReachabilityMonitor reachabilityMonitor,
|
||||||
|
FeatureFlags featureFlags,
|
||||||
|
LifecycleManager lifecycleManager,
|
||||||
|
EventBus eventBus) {
|
||||||
|
MailboxClientManager manager = new MailboxClientManager(eventExecutor,
|
||||||
|
dbExecutor, db, contactManager, pluginManager,
|
||||||
|
mailboxSettingsManager, mailboxUpdateManager,
|
||||||
|
mailboxClientFactory, reachabilityMonitor);
|
||||||
|
if (featureFlags.shouldEnableMailbox()) {
|
||||||
|
lifecycleManager.registerService(manager);
|
||||||
|
eventBus.addListener(manager);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,12 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
|||||||
@Override
|
@Override
|
||||||
public void recordSuccessfulConnection(Transaction txn, long now,
|
public void recordSuccessfulConnection(Transaction txn, long now,
|
||||||
List<MailboxVersion> versions) throws DbException {
|
List<MailboxVersion> versions) throws DbException {
|
||||||
|
// if we no longer have a paired mailbox, return
|
||||||
|
Settings oldSettings =
|
||||||
|
settingsManager.getSettings(txn, SETTINGS_NAMESPACE);
|
||||||
|
String onion = oldSettings.get(SETTINGS_KEY_ONION);
|
||||||
|
String token = oldSettings.get(SETTINGS_KEY_TOKEN);
|
||||||
|
if (isNullOrEmpty(onion) || isNullOrEmpty(token)) return;
|
||||||
Settings s = new Settings();
|
Settings s = new Settings();
|
||||||
// record the successful connection
|
// record the successful connection
|
||||||
s.putLong(SETTINGS_KEY_LAST_ATTEMPT, now);
|
s.putLong(SETTINGS_KEY_LAST_ATTEMPT, now);
|
||||||
@@ -126,6 +132,9 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
|||||||
s.putInt(SETTINGS_KEY_ATTEMPTS, 0);
|
s.putInt(SETTINGS_KEY_ATTEMPTS, 0);
|
||||||
encodeServerSupports(versions, s);
|
encodeServerSupports(versions, s);
|
||||||
settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE);
|
settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE);
|
||||||
|
for (MailboxHook hook : hooks) {
|
||||||
|
hook.serverSupportedVersionsReceived(txn, versions);
|
||||||
|
}
|
||||||
// broadcast status event
|
// broadcast status event
|
||||||
MailboxStatus status = new MailboxStatus(now, now, 0, versions);
|
MailboxStatus status = new MailboxStatus(now, now, 0, versions);
|
||||||
txn.attach(new OwnMailboxConnectionStatusEvent(status));
|
txn.attach(new OwnMailboxConnectionStatusEvent(status));
|
||||||
@@ -134,8 +143,12 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
|||||||
@Override
|
@Override
|
||||||
public void recordFailedConnectionAttempt(Transaction txn, long now)
|
public void recordFailedConnectionAttempt(Transaction txn, long now)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
// if we no longer have a paired mailbox, return
|
||||||
Settings oldSettings =
|
Settings oldSettings =
|
||||||
settingsManager.getSettings(txn, SETTINGS_NAMESPACE);
|
settingsManager.getSettings(txn, SETTINGS_NAMESPACE);
|
||||||
|
String onion = oldSettings.get(SETTINGS_KEY_ONION);
|
||||||
|
String token = oldSettings.get(SETTINGS_KEY_TOKEN);
|
||||||
|
if (isNullOrEmpty(onion) || isNullOrEmpty(token)) return;
|
||||||
int newAttempts = 1 + oldSettings.getInt(SETTINGS_KEY_ATTEMPTS, 0);
|
int newAttempts = 1 + oldSettings.getInt(SETTINGS_KEY_ATTEMPTS, 0);
|
||||||
long lastSuccess = oldSettings.getLong(SETTINGS_KEY_LAST_SUCCESS, 0);
|
long lastSuccess = oldSettings.getLong(SETTINGS_KEY_LAST_SUCCESS, 0);
|
||||||
Settings newSettings = new Settings();
|
Settings newSettings = new Settings();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
|||||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||||
import org.briarproject.bramble.api.mailbox.event.MailboxPairedEvent;
|
import org.briarproject.bramble.api.mailbox.event.MailboxPairedEvent;
|
||||||
import org.briarproject.bramble.api.mailbox.event.MailboxUnpairedEvent;
|
import org.briarproject.bramble.api.mailbox.event.MailboxUnpairedEvent;
|
||||||
import org.briarproject.bramble.api.mailbox.event.MailboxUpdateSentEvent;
|
import org.briarproject.bramble.api.mailbox.event.MailboxUpdateSentToNewContactEvent;
|
||||||
import org.briarproject.bramble.api.mailbox.event.RemoteMailboxUpdateEvent;
|
import org.briarproject.bramble.api.mailbox.event.RemoteMailboxUpdateEvent;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.Group;
|
import org.briarproject.bramble.api.sync.Group;
|
||||||
@@ -49,6 +49,9 @@ import java.util.Map.Entry;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
|
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||||
import static org.briarproject.bramble.api.sync.validation.IncomingMessageHook.DeliveryAction.ACCEPT_DO_NOT_SHARE;
|
import static org.briarproject.bramble.api.sync.validation.IncomingMessageHook.DeliveryAction.ACCEPT_DO_NOT_SHARE;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -115,13 +118,12 @@ class MailboxUpdateManagerImpl implements MailboxUpdateManager,
|
|||||||
}
|
}
|
||||||
Group g = getContactGroup(c);
|
Group g = getContactGroup(c);
|
||||||
storeMessageReplaceLatest(txn, g.getId(), updated);
|
storeMessageReplaceLatest(txn, g.getId(), updated);
|
||||||
txn.attach(new MailboxUpdateSentEvent(c.getId(), updated));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
db.addGroup(txn, localGroup);
|
db.addGroup(txn, localGroup);
|
||||||
// Set things up for any pre-existing contacts
|
// Set things up for any pre-existing contacts
|
||||||
for (Contact c : db.getContacts(txn)) {
|
for (Contact c : db.getContacts(txn)) {
|
||||||
addingContact(txn, c);
|
addingContact(txn, c, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +139,17 @@ class MailboxUpdateManagerImpl implements MailboxUpdateManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addingContact(Transaction txn, Contact c) throws DbException {
|
public void addingContact(Transaction txn, Contact c) throws DbException {
|
||||||
|
addingContact(txn, c, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param attachEvent True if a {@link MailboxUpdateSentToNewContactEvent}
|
||||||
|
* should be attached to the transaction. We should only do this when
|
||||||
|
* adding a new contact, not when setting up this client for an existing
|
||||||
|
* contact.
|
||||||
|
*/
|
||||||
|
private void addingContact(Transaction txn, Contact c, boolean attachEvent)
|
||||||
|
throws DbException {
|
||||||
// Create a group to share with the contact
|
// Create a group to share with the contact
|
||||||
Group g = getContactGroup(c);
|
Group g = getContactGroup(c);
|
||||||
db.addGroup(txn, g);
|
db.addGroup(txn, g);
|
||||||
@@ -157,7 +170,9 @@ class MailboxUpdateManagerImpl implements MailboxUpdateManager,
|
|||||||
// Not paired, but we still want to get our clientSupports sent
|
// Not paired, but we still want to get our clientSupports sent
|
||||||
u = sendUpdateNoMailbox(txn, c);
|
u = sendUpdateNoMailbox(txn, c);
|
||||||
}
|
}
|
||||||
txn.attach(new MailboxUpdateSentEvent(c.getId(), u));
|
if (attachEvent) {
|
||||||
|
txn.attach(new MailboxUpdateSentToNewContactEvent(c.getId(), u));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -175,6 +190,12 @@ class MailboxUpdateManagerImpl implements MailboxUpdateManager,
|
|||||||
localUpdates.put(c.getId(), u);
|
localUpdates.put(c.getId(), u);
|
||||||
}
|
}
|
||||||
txn.attach(new MailboxPairedEvent(p, localUpdates));
|
txn.attach(new MailboxPairedEvent(p, localUpdates));
|
||||||
|
// Store the list of server-supported versions
|
||||||
|
try {
|
||||||
|
storeSentServerSupports(txn, p.getServerSupports());
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -185,6 +206,78 @@ class MailboxUpdateManagerImpl implements MailboxUpdateManager,
|
|||||||
localUpdates.put(c.getId(), u);
|
localUpdates.put(c.getId(), u);
|
||||||
}
|
}
|
||||||
txn.attach(new MailboxUnpairedEvent(localUpdates));
|
txn.attach(new MailboxUnpairedEvent(localUpdates));
|
||||||
|
// Remove the list of server-supported versions
|
||||||
|
try {
|
||||||
|
BdfDictionary meta = BdfDictionary.of(new BdfEntry(
|
||||||
|
GROUP_KEY_SENT_SERVER_SUPPORTS, NULL_VALUE));
|
||||||
|
clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta);
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serverSupportedVersionsReceived(Transaction txn,
|
||||||
|
List<MailboxVersion> serverSupports) throws DbException {
|
||||||
|
try {
|
||||||
|
List<MailboxVersion> oldServerSupports =
|
||||||
|
loadSentServerSupports(txn);
|
||||||
|
if (serverSupports.equals(oldServerSupports)) return;
|
||||||
|
storeSentServerSupports(txn, serverSupports);
|
||||||
|
for (Contact c : db.getContacts(txn)) {
|
||||||
|
Group contactGroup = getContactGroup(c);
|
||||||
|
LatestUpdate latest =
|
||||||
|
findLatest(txn, contactGroup.getId(), true);
|
||||||
|
// This method should only be called when we have a mailbox,
|
||||||
|
// in which case we should have sent a local update to every
|
||||||
|
// contact
|
||||||
|
if (latest == null) throw new DbException();
|
||||||
|
BdfList body =
|
||||||
|
clientHelper.getMessageAsList(txn, latest.messageId);
|
||||||
|
MailboxUpdate oldUpdate = parseUpdate(body);
|
||||||
|
if (!oldUpdate.hasMailbox()) throw new DbException();
|
||||||
|
MailboxUpdateWithMailbox newUpdate = updateServerSupports(
|
||||||
|
(MailboxUpdateWithMailbox) oldUpdate, serverSupports);
|
||||||
|
storeMessageReplaceLatest(txn, contactGroup.getId(), newUpdate,
|
||||||
|
latest);
|
||||||
|
}
|
||||||
|
} catch (FormatException e) {
|
||||||
|
throw new DbException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeSentServerSupports(Transaction txn,
|
||||||
|
List<MailboxVersion> serverSupports)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
BdfDictionary meta = BdfDictionary.of(new BdfEntry(
|
||||||
|
GROUP_KEY_SENT_SERVER_SUPPORTS,
|
||||||
|
encodeSupportsList(serverSupports)));
|
||||||
|
clientHelper.mergeGroupMetadata(txn, localGroup.getId(), meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MailboxVersion> loadSentServerSupports(Transaction txn)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn,
|
||||||
|
localGroup.getId());
|
||||||
|
BdfList serverSupports =
|
||||||
|
meta.getOptionalList(GROUP_KEY_SENT_SERVER_SUPPORTS);
|
||||||
|
if (serverSupports == null) return emptyList();
|
||||||
|
return clientHelper.parseMailboxVersionList(serverSupports);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link MailboxUpdateWithMailbox} that updates the list
|
||||||
|
* of server-supported API versions in the given
|
||||||
|
* {@link MailboxUpdateWithMailbox}.
|
||||||
|
*/
|
||||||
|
private MailboxUpdateWithMailbox updateServerSupports(
|
||||||
|
MailboxUpdateWithMailbox old, List<MailboxVersion> serverSupports) {
|
||||||
|
MailboxProperties oldProps = old.getMailboxProperties();
|
||||||
|
MailboxProperties newProps = new MailboxProperties(oldProps.getOnion(),
|
||||||
|
oldProps.getAuthToken(), serverSupports,
|
||||||
|
requireNonNull(oldProps.getInboxId()),
|
||||||
|
requireNonNull(oldProps.getOutboxId()));
|
||||||
|
return new MailboxUpdateWithMailbox(old.getClientSupports(), newProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -304,21 +397,27 @@ class MailboxUpdateManagerImpl implements MailboxUpdateManager,
|
|||||||
MailboxUpdate u) throws DbException {
|
MailboxUpdate u) throws DbException {
|
||||||
try {
|
try {
|
||||||
LatestUpdate latest = findLatest(txn, g, true);
|
LatestUpdate latest = findLatest(txn, g, true);
|
||||||
long version = latest == null ? 1 : latest.version + 1;
|
storeMessageReplaceLatest(txn, g, u, latest);
|
||||||
Message m = clientHelper.createMessage(g, clock.currentTimeMillis(),
|
|
||||||
encodeProperties(version, u));
|
|
||||||
BdfDictionary meta = new BdfDictionary();
|
|
||||||
meta.put(MSG_KEY_VERSION, version);
|
|
||||||
meta.put(MSG_KEY_LOCAL, true);
|
|
||||||
clientHelper.addLocalMessage(txn, m, meta, true, false);
|
|
||||||
if (latest != null) {
|
|
||||||
db.removeMessage(txn, latest.messageId);
|
|
||||||
}
|
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void storeMessageReplaceLatest(Transaction txn, GroupId g,
|
||||||
|
MailboxUpdate u, @Nullable LatestUpdate latest)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
long version = latest == null ? 1 : latest.version + 1;
|
||||||
|
Message m = clientHelper.createMessage(g, clock.currentTimeMillis(),
|
||||||
|
encodeProperties(version, u));
|
||||||
|
BdfDictionary meta = new BdfDictionary();
|
||||||
|
meta.put(MSG_KEY_VERSION, version);
|
||||||
|
meta.put(MSG_KEY_LOCAL, true);
|
||||||
|
clientHelper.addLocalMessage(txn, m, meta, true, false);
|
||||||
|
if (latest != null) {
|
||||||
|
db.removeMessage(txn, latest.messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private LatestUpdate findLatest(Transaction txn, GroupId g, boolean local)
|
private LatestUpdate findLatest(Transaction txn, GroupId g, boolean local)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Cancellable;
|
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.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
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.MailboxFolderId;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
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.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||||
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
|
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.GuardedBy;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
@@ -58,9 +62,16 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver,
|
|||||||
* <p>
|
* <p>
|
||||||
* If there's no data to send, the worker listens for events indicating
|
* If there's no data to send, the worker listens for events indicating
|
||||||
* that new data may be ready to send.
|
* that new data may be ready to send.
|
||||||
|
* <p>
|
||||||
|
* 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 {
|
private enum State {
|
||||||
CREATED,
|
CREATED,
|
||||||
|
CONNECTED_TO_CONTACT,
|
||||||
CHECKING_FOR_DATA,
|
CHECKING_FOR_DATA,
|
||||||
WAITING_FOR_DATA,
|
WAITING_FOR_DATA,
|
||||||
CONNECTIVITY_CHECK,
|
CONNECTIVITY_CHECK,
|
||||||
@@ -95,6 +106,7 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver,
|
|||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final TaskScheduler taskScheduler;
|
private final TaskScheduler taskScheduler;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
private final ConnectionRegistry connectionRegistry;
|
||||||
private final ConnectivityChecker connectivityChecker;
|
private final ConnectivityChecker connectivityChecker;
|
||||||
private final MailboxApiCaller mailboxApiCaller;
|
private final MailboxApiCaller mailboxApiCaller;
|
||||||
private final MailboxApi mailboxApi;
|
private final MailboxApi mailboxApi;
|
||||||
@@ -121,6 +133,7 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver,
|
|||||||
Clock clock,
|
Clock clock,
|
||||||
TaskScheduler taskScheduler,
|
TaskScheduler taskScheduler,
|
||||||
EventBus eventBus,
|
EventBus eventBus,
|
||||||
|
ConnectionRegistry connectionRegistry,
|
||||||
ConnectivityChecker connectivityChecker,
|
ConnectivityChecker connectivityChecker,
|
||||||
MailboxApiCaller mailboxApiCaller,
|
MailboxApiCaller mailboxApiCaller,
|
||||||
MailboxApi mailboxApi,
|
MailboxApi mailboxApi,
|
||||||
@@ -133,6 +146,7 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver,
|
|||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.taskScheduler = taskScheduler;
|
this.taskScheduler = taskScheduler;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.connectionRegistry = connectionRegistry;
|
||||||
this.connectivityChecker = connectivityChecker;
|
this.connectivityChecker = connectivityChecker;
|
||||||
this.mailboxApiCaller = mailboxApiCaller;
|
this.mailboxApiCaller = mailboxApiCaller;
|
||||||
this.mailboxApi = mailboxApi;
|
this.mailboxApi = mailboxApi;
|
||||||
@@ -182,6 +196,12 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver,
|
|||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
checkTask = null;
|
checkTask = null;
|
||||||
if (state != State.CHECKING_FOR_DATA) return;
|
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");
|
LOG.info("Checking for data to send");
|
||||||
try {
|
try {
|
||||||
@@ -364,8 +384,14 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver,
|
|||||||
onDataToSend();
|
onDataToSend();
|
||||||
}
|
}
|
||||||
} else if (e instanceof MessageSharedEvent) {
|
} else if (e instanceof MessageSharedEvent) {
|
||||||
LOG.info("Message shared");
|
MessageSharedEvent m = (MessageSharedEvent) e;
|
||||||
onDataToSend();
|
// If the contact is present in the map (ie the value is not null)
|
||||||
|
// and the value is true, the message's group is shared with the
|
||||||
|
// contact and therefore the message may now be sendable
|
||||||
|
if (m.getGroupVisibility().get(contactId) == TRUE) {
|
||||||
|
LOG.info("Message shared");
|
||||||
|
onDataToSend();
|
||||||
|
}
|
||||||
} else if (e instanceof GroupVisibilityUpdatedEvent) {
|
} else if (e instanceof GroupVisibilityUpdatedEvent) {
|
||||||
GroupVisibilityUpdatedEvent g = (GroupVisibilityUpdatedEvent) e;
|
GroupVisibilityUpdatedEvent g = (GroupVisibilityUpdatedEvent) e;
|
||||||
if (g.getVisibility() == SHARED &&
|
if (g.getVisibility() == SHARED &&
|
||||||
@@ -373,6 +399,18 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver,
|
|||||||
LOG.info("Group shared");
|
LOG.info("Group shared");
|
||||||
onDataToSend();
|
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 +429,36 @@ class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver,
|
|||||||
// If we had scheduled a wakeup when data was due to be sent, cancel it
|
// If we had scheduled a wakeup when data was due to be sent, cancel it
|
||||||
if (wakeupTask != null) wakeupTask.cancel();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.connection.ConnectionRegistry;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
@@ -25,6 +26,7 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory {
|
|||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final TaskScheduler taskScheduler;
|
private final TaskScheduler taskScheduler;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
private final ConnectionRegistry connectionRegistry;
|
||||||
private final MailboxApiCaller mailboxApiCaller;
|
private final MailboxApiCaller mailboxApiCaller;
|
||||||
private final MailboxApi mailboxApi;
|
private final MailboxApi mailboxApi;
|
||||||
private final MailboxFileManager mailboxFileManager;
|
private final MailboxFileManager mailboxFileManager;
|
||||||
@@ -36,6 +38,7 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory {
|
|||||||
Clock clock,
|
Clock clock,
|
||||||
TaskScheduler taskScheduler,
|
TaskScheduler taskScheduler,
|
||||||
EventBus eventBus,
|
EventBus eventBus,
|
||||||
|
ConnectionRegistry connectionRegistry,
|
||||||
MailboxApiCaller mailboxApiCaller,
|
MailboxApiCaller mailboxApiCaller,
|
||||||
MailboxApi mailboxApi,
|
MailboxApi mailboxApi,
|
||||||
MailboxFileManager mailboxFileManager,
|
MailboxFileManager mailboxFileManager,
|
||||||
@@ -45,6 +48,7 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory {
|
|||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.taskScheduler = taskScheduler;
|
this.taskScheduler = taskScheduler;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.connectionRegistry = connectionRegistry;
|
||||||
this.mailboxApiCaller = mailboxApiCaller;
|
this.mailboxApiCaller = mailboxApiCaller;
|
||||||
this.mailboxApi = mailboxApi;
|
this.mailboxApi = mailboxApi;
|
||||||
this.mailboxFileManager = mailboxFileManager;
|
this.mailboxFileManager = mailboxFileManager;
|
||||||
@@ -57,9 +61,9 @@ class MailboxWorkerFactoryImpl implements MailboxWorkerFactory {
|
|||||||
MailboxProperties properties, MailboxFolderId folderId,
|
MailboxProperties properties, MailboxFolderId folderId,
|
||||||
ContactId contactId) {
|
ContactId contactId) {
|
||||||
MailboxUploadWorker worker = new MailboxUploadWorker(ioExecutor, db,
|
MailboxUploadWorker worker = new MailboxUploadWorker(ioExecutor, db,
|
||||||
clock, taskScheduler, eventBus, connectivityChecker,
|
clock, taskScheduler, eventBus, connectionRegistry,
|
||||||
mailboxApiCaller, mailboxApi, mailboxFileManager,
|
connectivityChecker, mailboxApiCaller, mailboxApi,
|
||||||
properties, folderId, contactId);
|
mailboxFileManager, properties, folderId, contactId);
|
||||||
eventBus.addListener(worker);
|
eventBus.addListener(worker);
|
||||||
return worker;
|
return worker;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Cancellable;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||||
|
import org.briarproject.bramble.mailbox.ConnectivityChecker.ConnectivityObserver;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -11,17 +15,27 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.HOURS;
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class OwnMailboxClient implements MailboxClient {
|
class OwnMailboxClient implements MailboxClient, ConnectivityObserver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How often to check our own mailbox's connectivity.
|
||||||
|
* <p>
|
||||||
|
* Package access for testing.
|
||||||
|
*/
|
||||||
|
static final long CONNECTIVITY_CHECK_INTERVAL_MS = HOURS.toMillis(1);
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(OwnMailboxClient.class.getName());
|
getLogger(OwnMailboxClient.class.getName());
|
||||||
@@ -29,6 +43,9 @@ class OwnMailboxClient implements MailboxClient {
|
|||||||
private final MailboxWorkerFactory workerFactory;
|
private final MailboxWorkerFactory workerFactory;
|
||||||
private final ConnectivityChecker connectivityChecker;
|
private final ConnectivityChecker connectivityChecker;
|
||||||
private final TorReachabilityMonitor reachabilityMonitor;
|
private final TorReachabilityMonitor reachabilityMonitor;
|
||||||
|
private final TaskScheduler taskScheduler;
|
||||||
|
private final Executor ioExecutor;
|
||||||
|
private final MailboxProperties properties;
|
||||||
private final MailboxWorker contactListWorker;
|
private final MailboxWorker contactListWorker;
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
|
||||||
@@ -53,14 +70,30 @@ class OwnMailboxClient implements MailboxClient {
|
|||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private final Set<ContactId> assignedForDownload = new HashSet<>();
|
private final Set<ContactId> assignedForDownload = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scheduled task for periodically checking whether the mailbox is
|
||||||
|
* reachable.
|
||||||
|
*/
|
||||||
|
@GuardedBy("lock")
|
||||||
|
@Nullable
|
||||||
|
private Cancellable connectivityTask = null;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private boolean destroyed = false;
|
||||||
|
|
||||||
OwnMailboxClient(MailboxWorkerFactory workerFactory,
|
OwnMailboxClient(MailboxWorkerFactory workerFactory,
|
||||||
ConnectivityChecker connectivityChecker,
|
ConnectivityChecker connectivityChecker,
|
||||||
TorReachabilityMonitor reachabilityMonitor,
|
TorReachabilityMonitor reachabilityMonitor,
|
||||||
|
TaskScheduler taskScheduler,
|
||||||
|
@IoExecutor Executor ioExecutor,
|
||||||
MailboxProperties properties) {
|
MailboxProperties properties) {
|
||||||
if (!properties.isOwner()) throw new IllegalArgumentException();
|
if (!properties.isOwner()) throw new IllegalArgumentException();
|
||||||
this.workerFactory = workerFactory;
|
this.workerFactory = workerFactory;
|
||||||
this.connectivityChecker = connectivityChecker;
|
this.connectivityChecker = connectivityChecker;
|
||||||
this.reachabilityMonitor = reachabilityMonitor;
|
this.reachabilityMonitor = reachabilityMonitor;
|
||||||
|
this.taskScheduler = taskScheduler;
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.properties = properties;
|
||||||
contactListWorker = workerFactory.createContactListWorkerForOwnMailbox(
|
contactListWorker = workerFactory.createContactListWorkerForOwnMailbox(
|
||||||
connectivityChecker, properties);
|
connectivityChecker, properties);
|
||||||
}
|
}
|
||||||
@@ -68,6 +101,7 @@ class OwnMailboxClient implements MailboxClient {
|
|||||||
@Override
|
@Override
|
||||||
public void start() {
|
public void start() {
|
||||||
LOG.info("Started");
|
LOG.info("Started");
|
||||||
|
checkConnectivity();
|
||||||
contactListWorker.start();
|
contactListWorker.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,15 +110,21 @@ class OwnMailboxClient implements MailboxClient {
|
|||||||
LOG.info("Destroyed");
|
LOG.info("Destroyed");
|
||||||
List<MailboxWorker> uploadWorkers;
|
List<MailboxWorker> uploadWorkers;
|
||||||
MailboxWorker downloadWorker;
|
MailboxWorker downloadWorker;
|
||||||
|
Cancellable connectivityTask;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
uploadWorkers = new ArrayList<>(this.uploadWorkers.values());
|
uploadWorkers = new ArrayList<>(this.uploadWorkers.values());
|
||||||
this.uploadWorkers.clear();
|
this.uploadWorkers.clear();
|
||||||
downloadWorker = this.downloadWorker;
|
downloadWorker = this.downloadWorker;
|
||||||
this.downloadWorker = null;
|
this.downloadWorker = null;
|
||||||
|
connectivityTask = this.connectivityTask;
|
||||||
|
this.connectivityTask = null;
|
||||||
|
destroyed = true;
|
||||||
}
|
}
|
||||||
// Destroy the workers (with apologies to Mr Marx and Mr Engels)
|
// Destroy the workers (with apologies to Mr Marx and Mr Engels)
|
||||||
for (MailboxWorker worker : uploadWorkers) worker.destroy();
|
for (MailboxWorker worker : uploadWorkers) worker.destroy();
|
||||||
if (downloadWorker != null) downloadWorker.destroy();
|
if (downloadWorker != null) downloadWorker.destroy();
|
||||||
|
// If a connectivity check is scheduled, cancel it
|
||||||
|
if (connectivityTask != null) connectivityTask.cancel();
|
||||||
contactListWorker.destroy();
|
contactListWorker.destroy();
|
||||||
// The connectivity checker belongs to the client, so it should be
|
// The connectivity checker belongs to the client, so it should be
|
||||||
// destroyed. The Tor reachability monitor is shared between clients,
|
// destroyed. The Tor reachability monitor is shared between clients,
|
||||||
@@ -155,4 +195,28 @@ class OwnMailboxClient implements MailboxClient {
|
|||||||
}
|
}
|
||||||
if (toDestroy != null) toDestroy.destroy();
|
if (toDestroy != null) toDestroy.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkConnectivity() {
|
||||||
|
synchronized (lock) {
|
||||||
|
if (destroyed) return;
|
||||||
|
connectivityTask = null;
|
||||||
|
}
|
||||||
|
connectivityChecker.checkConnectivity(properties, this);
|
||||||
|
// Avoid leaking observer in case destroy() is called concurrently
|
||||||
|
// before observer is added
|
||||||
|
boolean removeObserver;
|
||||||
|
synchronized (lock) {
|
||||||
|
removeObserver = destroyed;
|
||||||
|
}
|
||||||
|
if (removeObserver) connectivityChecker.removeObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectivityCheckSucceeded() {
|
||||||
|
synchronized (lock) {
|
||||||
|
if (destroyed) return;
|
||||||
|
connectivityTask = taskScheduler.schedule(this::checkConnectivity,
|
||||||
|
ioExecutor, CONNECTIVITY_CHECK_INTERVAL_MS, MILLISECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
interface UrlConverter {
|
interface UrlConverter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a raw onion address, excluding the .onion suffix, into an
|
* Converts a raw onion address, excluding the .onion suffix, into an
|
||||||
* HTTP URL.
|
* HTTP URL.
|
||||||
*/
|
*/
|
||||||
String convertOnionToBaseUrl(String onion);
|
String convertOnionToBaseUrl(String onion);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
@@ -233,7 +234,13 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) interrupt();
|
if (c.getContactId().equals(contactId)) interrupt();
|
||||||
} else if (e instanceof MessageSharedEvent) {
|
} else if (e instanceof MessageSharedEvent) {
|
||||||
generateOffer();
|
MessageSharedEvent m = (MessageSharedEvent) e;
|
||||||
|
// If the contact is present in the map (ie the value is not null)
|
||||||
|
// and the value is true, the message's group is shared with the
|
||||||
|
// contact and therefore the message may now be sendable
|
||||||
|
if (m.getGroupVisibility().get(contactId) == TRUE) {
|
||||||
|
generateOffer();
|
||||||
|
}
|
||||||
} else if (e instanceof GroupVisibilityUpdatedEvent) {
|
} else if (e instanceof GroupVisibilityUpdatedEvent) {
|
||||||
GroupVisibilityUpdatedEvent g = (GroupVisibilityUpdatedEvent) e;
|
GroupVisibilityUpdatedEvent g = (GroupVisibilityUpdatedEvent) e;
|
||||||
if (g.getVisibility() == SHARED &&
|
if (g.getVisibility() == SHARED &&
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import org.briarproject.bramble.api.identity.IdentityManager;
|
|||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
||||||
|
import org.briarproject.bramble.test.TestDnsModule;
|
||||||
|
import org.briarproject.bramble.test.TestSocksModule;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@@ -20,7 +22,9 @@ import dagger.Component;
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
BrambleCoreIntegrationTestModule.class,
|
BrambleCoreIntegrationTestModule.class,
|
||||||
BrambleCoreModule.class
|
BrambleCoreModule.class,
|
||||||
|
TestDnsModule.class,
|
||||||
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
interface ContactExchangeIntegrationTestComponent
|
interface ContactExchangeIntegrationTestComponent
|
||||||
extends BrambleCoreIntegrationTestEagerSingletons {
|
extends BrambleCoreIntegrationTestEagerSingletons {
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import static java.util.Arrays.asList;
|
|||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.emptyMap;
|
import static java.util.Collections.emptyMap;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
import static java.util.concurrent.TimeUnit.HOURS;
|
import static java.util.concurrent.TimeUnit.HOURS;
|
||||||
import static org.briarproject.bramble.api.db.DatabaseComponent.TIMER_NOT_STARTED;
|
import static org.briarproject.bramble.api.db.DatabaseComponent.TIMER_NOT_STARTED;
|
||||||
import static org.briarproject.bramble.api.record.Record.RECORD_HEADER_BYTES;
|
import static org.briarproject.bramble.api.record.Record.RECORD_HEADER_BYTES;
|
||||||
@@ -283,12 +284,16 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
temporary, null);
|
temporary, null);
|
||||||
oneOf(database).mergeMessageMetadata(txn, messageId, metadata);
|
oneOf(database).mergeMessageMetadata(txn, messageId, metadata);
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
// The message was added, so the listeners should be called
|
// Broadcast events for message being added and changing state
|
||||||
oneOf(eventBus).broadcast(with(any(MessageAddedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessageAddedEvent.class)));
|
||||||
oneOf(eventBus).broadcast(with(any(
|
oneOf(eventBus).broadcast(with(any(
|
||||||
MessageStateChangedEvent.class)));
|
MessageStateChangedEvent.class)));
|
||||||
if (shared)
|
// If message is shared, get group visibility and broadcast event
|
||||||
|
if (shared) {
|
||||||
|
oneOf(database).getGroupVisibility(txn, groupId);
|
||||||
|
will(returnValue(singletonMap(contactId, true)));
|
||||||
oneOf(eventBus).broadcast(with(any(MessageSharedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessageSharedEvent.class)));
|
||||||
|
}
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
eventExecutor, shutdownManager);
|
eventExecutor, shutdownManager);
|
||||||
@@ -694,11 +699,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Check whether the message is in the DB (which it's not)
|
// Check whether the message is in the DB (which it's not)
|
||||||
exactly(15).of(database).startTransaction();
|
exactly(16).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
exactly(15).of(database).containsMessage(txn, messageId);
|
exactly(16).of(database).containsMessage(txn, messageId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
exactly(15).of(database).abortTransaction(txn);
|
exactly(16).of(database).abortTransaction(txn);
|
||||||
// Allow other checks to pass
|
// Allow other checks to pass
|
||||||
allowing(database).containsContact(txn, contactId);
|
allowing(database).containsContact(txn, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
@@ -722,6 +727,14 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
// Expected
|
// Expected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
db.transaction(true, transaction ->
|
||||||
|
db.getGroupId(transaction, messageId));
|
||||||
|
fail();
|
||||||
|
} catch (NoSuchMessageException expected) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.transaction(true, transaction ->
|
db.transaction(true, transaction ->
|
||||||
db.getMessage(transaction, messageId));
|
db.getMessage(transaction, messageId));
|
||||||
@@ -1873,12 +1886,16 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).containsMessage(txn, messageId);
|
oneOf(database).containsMessage(txn, messageId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getMessageDependents(txn, messageId);
|
oneOf(database).getMessageDependents(txn, messageId);
|
||||||
// broadcast for message added event
|
// Broadcast events for message being added and changing state
|
||||||
oneOf(eventBus).broadcast(with(any(MessageAddedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessageAddedEvent.class)));
|
||||||
oneOf(eventBus).broadcast(with(any(
|
oneOf(eventBus).broadcast(with(any(
|
||||||
MessageStateChangedEvent.class)));
|
MessageStateChangedEvent.class)));
|
||||||
if (shared)
|
// If message is shared, get group visibility and broadcast event
|
||||||
|
if (shared) {
|
||||||
|
oneOf(database).getGroupVisibility(txn, groupId);
|
||||||
|
will(returnValue(singletonMap(contactId, true)));
|
||||||
oneOf(eventBus).broadcast(with(any(MessageSharedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(MessageSharedEvent.class)));
|
||||||
|
}
|
||||||
// endTransaction()
|
// endTransaction()
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
// close()
|
// close()
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
assertTrue(db.containsContact(txn, contactId));
|
assertTrue(db.containsContact(txn, contactId));
|
||||||
assertTrue(db.containsGroup(txn, groupId));
|
assertTrue(db.containsGroup(txn, groupId));
|
||||||
assertTrue(db.containsMessage(txn, messageId));
|
assertTrue(db.containsMessage(txn, messageId));
|
||||||
|
assertEquals(groupId, db.getGroupId(txn, messageId));
|
||||||
assertArrayEquals(message.getBody(),
|
assertArrayEquals(message.getBody(),
|
||||||
db.getMessage(txn, messageId).getBody());
|
db.getMessage(txn, messageId).getBody());
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,929 @@
|
|||||||
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
|
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||||
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
||||||
|
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||||
|
import org.briarproject.bramble.api.mailbox.event.MailboxPairedEvent;
|
||||||
|
import org.briarproject.bramble.api.mailbox.event.MailboxUnpairedEvent;
|
||||||
|
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
|
||||||
|
import org.briarproject.bramble.api.mailbox.event.RemoteMailboxUpdateEvent;
|
||||||
|
import org.briarproject.bramble.api.plugin.Plugin.State;
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||||
|
import org.briarproject.bramble.api.plugin.event.TransportActiveEvent;
|
||||||
|
import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent;
|
||||||
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.briarproject.bramble.test.DbExpectations;
|
||||||
|
import org.briarproject.bramble.test.RunAction;
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
||||||
|
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||||
|
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
|
||||||
|
import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING;
|
||||||
|
import static org.briarproject.bramble.api.plugin.TorConstants.ID;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getContact;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||||
|
|
||||||
|
public class MailboxClientManagerTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
|
private final Executor eventExecutor =
|
||||||
|
context.mock(Executor.class, "eventExecutor");
|
||||||
|
private final Executor dbExecutor =
|
||||||
|
context.mock(Executor.class, "dbExecutor");
|
||||||
|
private final TransactionManager db =
|
||||||
|
context.mock(TransactionManager.class);
|
||||||
|
private final ContactManager contactManager =
|
||||||
|
context.mock(ContactManager.class);
|
||||||
|
private final PluginManager pluginManager =
|
||||||
|
context.mock(PluginManager.class);
|
||||||
|
private final MailboxSettingsManager mailboxSettingsManager =
|
||||||
|
context.mock(MailboxSettingsManager.class);
|
||||||
|
private final MailboxUpdateManager mailboxUpdateManager =
|
||||||
|
context.mock(MailboxUpdateManager.class);
|
||||||
|
private final MailboxClientFactory mailboxClientFactory =
|
||||||
|
context.mock(MailboxClientFactory.class);
|
||||||
|
private final TorReachabilityMonitor reachabilityMonitor =
|
||||||
|
context.mock(TorReachabilityMonitor.class);
|
||||||
|
private final DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
||||||
|
private final MailboxClient ownClient =
|
||||||
|
context.mock(MailboxClient.class, "ownClient");
|
||||||
|
private final MailboxClient contactClient =
|
||||||
|
context.mock(MailboxClient.class, "contactClient");
|
||||||
|
|
||||||
|
private final MailboxClientManager manager =
|
||||||
|
new MailboxClientManager(eventExecutor, dbExecutor, db,
|
||||||
|
contactManager, pluginManager, mailboxSettingsManager,
|
||||||
|
mailboxUpdateManager, mailboxClientFactory,
|
||||||
|
reachabilityMonitor);
|
||||||
|
|
||||||
|
private final Contact contact = getContact();
|
||||||
|
private final List<MailboxVersion> incompatibleVersions =
|
||||||
|
singletonList(new MailboxVersion(999, 0));
|
||||||
|
private final MailboxProperties ownProperties =
|
||||||
|
getMailboxProperties(true, CLIENT_SUPPORTS);
|
||||||
|
private final MailboxProperties localProperties =
|
||||||
|
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||||
|
private final MailboxProperties remoteProperties =
|
||||||
|
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||||
|
private final MailboxProperties remotePropertiesForNewMailbox =
|
||||||
|
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||||
|
private final MailboxUpdate localUpdateWithoutMailbox =
|
||||||
|
new MailboxUpdate(CLIENT_SUPPORTS);
|
||||||
|
private final MailboxUpdate remoteUpdateWithoutMailbox =
|
||||||
|
new MailboxUpdate(CLIENT_SUPPORTS);
|
||||||
|
private final MailboxUpdate remoteUpdateWithIncompatibleClientVersions =
|
||||||
|
new MailboxUpdate(incompatibleVersions);
|
||||||
|
private final MailboxUpdateWithMailbox localUpdateWithMailbox =
|
||||||
|
new MailboxUpdateWithMailbox(CLIENT_SUPPORTS, localProperties);
|
||||||
|
private final MailboxUpdateWithMailbox remoteUpdateWithMailbox =
|
||||||
|
new MailboxUpdateWithMailbox(CLIENT_SUPPORTS, remoteProperties);
|
||||||
|
private final MailboxUpdateWithMailbox remoteUpdateWithNewMailbox =
|
||||||
|
new MailboxUpdateWithMailbox(CLIENT_SUPPORTS,
|
||||||
|
remotePropertiesForNewMailbox);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadsMailboxUpdatesAtStartupWhenOffline() throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We're offline so there's nothing
|
||||||
|
// else to do.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox,
|
||||||
|
remoteUpdateWithoutMailbox, null);
|
||||||
|
expectCheckPluginState(ENABLING);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// At shutdown there should be no clients to destroy. The manager
|
||||||
|
// should destroy the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadsMailboxUpdatesAtStartupWhenOnline() throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We're online but we don't have a
|
||||||
|
// mailbox and neither does the contact, so there's nothing else to do.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox,
|
||||||
|
remoteUpdateWithoutMailbox, null);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// At shutdown there should be no clients to destroy. The manager
|
||||||
|
// should destroy the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAssignsContactToOurMailboxIfContactHasNoMailbox()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox but the contact
|
||||||
|
// doesn't.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for our own
|
||||||
|
// mailbox and assign the contact to it for upload and download.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithoutMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
expectAssignContactToOwnMailboxForUpload();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our own
|
||||||
|
// mailbox and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotAssignContactToOurMailboxIfContactHasNotSentUpdate()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox but the contact
|
||||||
|
// has never sent us an update, so the remote update is null.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for our own
|
||||||
|
// mailbox. We don't know what API versions the contact supports,
|
||||||
|
// if any, so the contact should not be assigned to our mailbox.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox, null, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our own
|
||||||
|
// mailbox and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotAssignContactToOurMailboxIfContactHasIncompatibleClientVersions()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox but the contact
|
||||||
|
// doesn't. The contact's client API versions are incompatible with
|
||||||
|
// our mailbox.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for our own
|
||||||
|
// mailbox. The contact's client API versions are incompatible with
|
||||||
|
// our mailbox, so the contact should not be assigned to our mailbox.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithIncompatibleClientVersions, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our own
|
||||||
|
// mailbox and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAssignsContactToContactMailboxIfWeHaveNoMailbox()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We don't have a mailbox but the
|
||||||
|
// contact does.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for the
|
||||||
|
// contact's mailbox and assign the contact to it for upload and
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox,
|
||||||
|
remoteUpdateWithMailbox, null);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForDownload(remoteProperties);
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAssignsContactToBothMailboxesIfWeBothHaveMailboxes()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox and so does the
|
||||||
|
// contact.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create clients for the
|
||||||
|
// contact's mailbox and our mailbox. The manager should assign the
|
||||||
|
// contact to the contact's mailbox for upload and our mailbox for
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox, the client for our own mailbox, and the reachability
|
||||||
|
// monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatesClientsWhenTorBecomesActive() throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox but the contact
|
||||||
|
// doesn't. We're offline so there's nothing else to do.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithoutMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ENABLING);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When we come online, the manager should create a client for our own
|
||||||
|
// mailbox and assign the contact to it for upload and download.
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
expectAssignContactToOwnMailboxForUpload();
|
||||||
|
manager.eventOccurred(new TransportActiveEvent(ID));
|
||||||
|
|
||||||
|
// When we go offline, the manager should destroy the client for our
|
||||||
|
// own mailbox.
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
manager.eventOccurred(new TransportInactiveEvent(ID));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAssignsContactToOurMailboxWhenPaired() throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We're online but we don't have a
|
||||||
|
// mailbox and neither does the contact, so there's nothing else to do.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox,
|
||||||
|
remoteUpdateWithoutMailbox, null);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When we pair a mailbox, the manager should create a client for our
|
||||||
|
// mailbox and assign the contact to our mailbox for upload and
|
||||||
|
// download.
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForUpload();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.eventOccurred(new MailboxPairedEvent(ownProperties,
|
||||||
|
singletonMap(contact.getId(), localUpdateWithMailbox)));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our mailbox
|
||||||
|
// and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReassignsContactToOurMailboxWhenPaired() throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. The contact has a mailbox but we
|
||||||
|
// don't.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for the
|
||||||
|
// contact's mailbox and assign the contact to it for upload and
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox,
|
||||||
|
remoteUpdateWithMailbox, null);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForDownload(remoteProperties);
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When we pair a mailbox, the manager should create a client for our
|
||||||
|
// mailbox and reassign the contact to our mailbox for download.
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectDeassignContactFromContactMailboxForDownload();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.eventOccurred(new MailboxPairedEvent(ownProperties,
|
||||||
|
singletonMap(contact.getId(), localUpdateWithMailbox)));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox, the client for our own mailbox, and the reachability
|
||||||
|
// monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotAssignContactWhenPairedIfContactHasNotSentUpdate()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We don't have a mailbox and the
|
||||||
|
// contact has never sent us an update, so the remote update is null.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox, null, null);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When we pair a mailbox, the manager should create a client for our
|
||||||
|
// mailbox. We don't know whether the contact can use our mailbox, so
|
||||||
|
// the contact should not be assigned to our mailbox.
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
manager.eventOccurred(new MailboxPairedEvent(ownProperties,
|
||||||
|
singletonMap(contact.getId(), localUpdateWithMailbox)));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our mailbox
|
||||||
|
// and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotAssignContactWhenPairedIfContactHasIncompatibleClientVersions()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We don't have a mailbox and neither
|
||||||
|
// does the contact. The contact's client API versions are
|
||||||
|
// incompatible with our mailbox.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox,
|
||||||
|
remoteUpdateWithIncompatibleClientVersions, null);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When we pair a mailbox, the manager should create a client for our
|
||||||
|
// mailbox. The contact's client API versions are incompatible with
|
||||||
|
// our mailbox, so the contact should not be assigned to our mailbox.
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
manager.eventOccurred(new MailboxPairedEvent(ownProperties,
|
||||||
|
singletonMap(contact.getId(), localUpdateWithMailbox)));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our mailbox
|
||||||
|
// and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReassignsContactToContactMailboxWhenUnpaired()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox and so does the
|
||||||
|
// contact.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create clients for the
|
||||||
|
// contact's mailbox and our mailbox. The manager should assign the
|
||||||
|
// contact to the contact's mailbox for upload and our mailbox for
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When we unpair our mailbox, the manager should destroy the client
|
||||||
|
// for our mailbox and reassign the contact to the contact's mailbox
|
||||||
|
// for download.
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectAssignContactToContactMailboxForDownload(remoteProperties);
|
||||||
|
manager.eventOccurred(new MailboxUnpairedEvent(
|
||||||
|
singletonMap(contact.getId(), localUpdateWithoutMailbox)));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeassignsContactForUploadAndDownloadWhenContactRemoved()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox but the contact
|
||||||
|
// doesn't.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for our mailbox.
|
||||||
|
// The manager should assign the contact to our mailbox for upload and
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithoutMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForUpload();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When the contact is removed, the manager should deassign the contact
|
||||||
|
// from our mailbox for upload and download.
|
||||||
|
expectDeassignContactFromOwnMailboxForUpload();
|
||||||
|
expectDeassignContactFromOwnMailboxForDownload();
|
||||||
|
manager.eventOccurred(new ContactRemovedEvent(contact.getId()));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our mailbox
|
||||||
|
// and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeassignsContactForDownloadWhenContactRemoved()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox and so does the
|
||||||
|
// contact.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create clients for the
|
||||||
|
// contact's mailbox and our mailbox. The manager should assign the
|
||||||
|
// contact to the contact's mailbox for upload and our mailbox for
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When the contact is removed, the manager should destroy the client
|
||||||
|
// for the contact's mailbox and deassign the contact from our mailbox
|
||||||
|
// for download.
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDeassignContactFromOwnMailboxForDownload();
|
||||||
|
manager.eventOccurred(new ContactRemovedEvent(contact.getId()));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our mailbox
|
||||||
|
// and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAssignsContactToContactMailboxWhenContactPairsMailbox()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We're online but we don't have a
|
||||||
|
// mailbox and neither does the contact, so there's nothing else to do.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox,
|
||||||
|
remoteUpdateWithoutMailbox, null);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When the contact pairs a mailbox, the manager should create a client
|
||||||
|
// for the contact's mailbox and assign the contact to the contact's
|
||||||
|
// mailbox for upload and download.
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectAssignContactToContactMailboxForDownload(remoteProperties);
|
||||||
|
manager.eventOccurred(new RemoteMailboxUpdateEvent(contact.getId(),
|
||||||
|
remoteUpdateWithMailbox));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReassignsContactForUploadWhenContactPairsMailbox()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox but the contact
|
||||||
|
// doesn't.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for our mailbox.
|
||||||
|
// The manager should assign the contact to our mailbox for upload and
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithoutMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForUpload();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When the contact pairs a mailbox, the manager should create a client
|
||||||
|
// for the contact's mailbox and reassign the contact to the contact's
|
||||||
|
// mailbox for upload.
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectDeassignContactFromOwnMailboxForUpload();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
manager.eventOccurred(new RemoteMailboxUpdateEvent(contact.getId(),
|
||||||
|
remoteUpdateWithMailbox));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox, the client for our own mailbox, and the reachability
|
||||||
|
// monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReassignsContactForUploadWhenContactUnpairsMailbox()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox and so does the
|
||||||
|
// contact.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create clients for the
|
||||||
|
// contact's mailbox and our mailbox. The manager should assign the
|
||||||
|
// contact to the contact's mailbox for upload and our mailbox for
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When the contact unpairs their mailbox, the manager should destroy
|
||||||
|
// the client for the contact's mailbox and reassign the contact to
|
||||||
|
// our mailbox for upload.
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForUpload();
|
||||||
|
manager.eventOccurred(new RemoteMailboxUpdateEvent(contact.getId(),
|
||||||
|
remoteUpdateWithoutMailbox));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our mailbox
|
||||||
|
// and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReassignsContactForUploadWhenContactReplacesMailbox()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox and so does the
|
||||||
|
// contact.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create clients for the
|
||||||
|
// contact's mailbox and our mailbox. The manager should assign the
|
||||||
|
// contact to the contact's mailbox for upload and our mailbox for
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When the contact replaces their mailbox, the manager should replace
|
||||||
|
// the client for the contact's mailbox and assign the contact to
|
||||||
|
// the contact's new mailbox for upload.
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(
|
||||||
|
remotePropertiesForNewMailbox);
|
||||||
|
manager.eventOccurred(new RemoteMailboxUpdateEvent(contact.getId(),
|
||||||
|
remoteUpdateWithNewMailbox));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox, the client for our own mailbox, and the reachability
|
||||||
|
// monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReassignsContactWhenContactReplacesMailbox()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We don't have a mailbox but the
|
||||||
|
// contact does.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for the
|
||||||
|
// contact's mailbox and assign the contact to the contact's mailbox
|
||||||
|
// for upload and download.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox,
|
||||||
|
remoteUpdateWithMailbox, null);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectAssignContactToContactMailboxForDownload(remoteProperties);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When the contact replaces their mailbox, the manager should replace
|
||||||
|
// the client for the contact's mailbox and assign the contact to
|
||||||
|
// the contact's new mailbox for upload and download.
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(
|
||||||
|
remotePropertiesForNewMailbox);
|
||||||
|
expectAssignContactToContactMailboxForDownload(
|
||||||
|
remotePropertiesForNewMailbox);
|
||||||
|
manager.eventOccurred(new RemoteMailboxUpdateEvent(contact.getId(),
|
||||||
|
remoteUpdateWithNewMailbox));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotReassignContactWhenRemotePropertiesAreUnchanged()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We don't have a mailbox but the
|
||||||
|
// contact does.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for the
|
||||||
|
// contact's mailbox and assign the contact to the contact's mailbox
|
||||||
|
// for upload and download.
|
||||||
|
expectLoadUpdates(localUpdateWithoutMailbox,
|
||||||
|
remoteUpdateWithMailbox, null);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectAssignContactToContactMailboxForDownload(remoteProperties);
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When the contact sends an update with unchanged properties, the
|
||||||
|
// clients and assignments should not be affected.
|
||||||
|
manager.eventOccurred(new RemoteMailboxUpdateEvent(contact.getId(),
|
||||||
|
remoteUpdateWithMailbox));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAssignsContactToOurMailboxWhenClientVersionsBecomeCompatible()
|
||||||
|
throws Exception {
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. We have a mailbox but the contact
|
||||||
|
// doesn't. The contact's client API versions are incompatible with
|
||||||
|
// our mailbox.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create a client for our own
|
||||||
|
// mailbox. The contact's client API versions are incompatible with
|
||||||
|
// our mailbox, so the contact should not be assigned to our mailbox.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithIncompatibleClientVersions, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When the contact sends an update indicating that their client API
|
||||||
|
// versions are now compatible with our mailbox, the manager should
|
||||||
|
// assign the contact to our mailbox for upload and download.
|
||||||
|
expectAssignContactToOwnMailboxForUpload();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.eventOccurred(new RemoteMailboxUpdateEvent(contact.getId(),
|
||||||
|
remoteUpdateWithoutMailbox));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for our own
|
||||||
|
// mailbox and the reachability monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRecreatesClientsWhenOwnMailboxServerVersionsChange()
|
||||||
|
throws Exception {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
List<MailboxVersion> compatibleVersions =
|
||||||
|
new ArrayList<>(CLIENT_SUPPORTS);
|
||||||
|
compatibleVersions.add(new MailboxVersion(999, 0));
|
||||||
|
MailboxStatus mailboxStatus =
|
||||||
|
new MailboxStatus(now, now, 0, compatibleVersions);
|
||||||
|
|
||||||
|
// At startup the manager should load the local and remote updates
|
||||||
|
// and our own mailbox properties. The contact has a mailbox, so the
|
||||||
|
// remote update contains the properties received from the contact.
|
||||||
|
// We also have a mailbox, so the local update contains the properties
|
||||||
|
// we sent to the contact.
|
||||||
|
//
|
||||||
|
// We're online, so the manager should create clients for the
|
||||||
|
// contact's mailbox and our mailbox. The manager should assign the
|
||||||
|
// contact to the contact's mailbox for upload and our mailbox for
|
||||||
|
// download.
|
||||||
|
expectLoadUpdates(localUpdateWithMailbox,
|
||||||
|
remoteUpdateWithMailbox, ownProperties);
|
||||||
|
expectCheckPluginState(ACTIVE);
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.startService();
|
||||||
|
|
||||||
|
// When we learn that our mailbox's API versions have changed, the
|
||||||
|
// manager should destroy and recreate the clients for our own mailbox
|
||||||
|
// and the contact's mailbox and assign the contact to the new clients.
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectCreateClientForContactMailbox();
|
||||||
|
expectAssignContactToContactMailboxForUpload(remoteProperties);
|
||||||
|
expectCreateClientForOwnMailbox();
|
||||||
|
expectAssignContactToOwnMailboxForDownload();
|
||||||
|
manager.eventOccurred(
|
||||||
|
new OwnMailboxConnectionStatusEvent(mailboxStatus));
|
||||||
|
|
||||||
|
// At shutdown the manager should destroy the client for the contact's
|
||||||
|
// mailbox, the client for our own mailbox, and the reachability
|
||||||
|
// monitor.
|
||||||
|
expectRunTaskOnEventExecutor();
|
||||||
|
expectDestroyClientForContactMailbox();
|
||||||
|
expectDestroyClientForOwnMailbox();
|
||||||
|
expectDestroyReachabilityMonitor();
|
||||||
|
manager.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectLoadUpdates(MailboxUpdate local,
|
||||||
|
@Nullable MailboxUpdate remote,
|
||||||
|
@Nullable MailboxProperties own) throws Exception {
|
||||||
|
Transaction txn = new Transaction(null, true);
|
||||||
|
|
||||||
|
context.checking(new DbExpectations() {{
|
||||||
|
oneOf(reachabilityMonitor).start();
|
||||||
|
oneOf(dbExecutor).execute(with(any(Runnable.class)));
|
||||||
|
will(new RunAction());
|
||||||
|
oneOf(db).transaction(with(true), withDbRunnable(txn));
|
||||||
|
oneOf(contactManager).getContacts(txn);
|
||||||
|
will(returnValue(singletonList(contact)));
|
||||||
|
oneOf(mailboxUpdateManager).getLocalUpdate(txn, contact.getId());
|
||||||
|
will(returnValue(local));
|
||||||
|
oneOf(mailboxUpdateManager).getRemoteUpdate(txn, contact.getId());
|
||||||
|
will(returnValue(remote));
|
||||||
|
oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn);
|
||||||
|
will(returnValue(own));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectCheckPluginState(State state) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(pluginManager).getPlugin(ID);
|
||||||
|
will(returnValue(plugin));
|
||||||
|
oneOf(plugin).getState();
|
||||||
|
will(returnValue(state));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectCreateClientForOwnMailbox() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(mailboxClientFactory).createOwnMailboxClient(
|
||||||
|
reachabilityMonitor, ownProperties);
|
||||||
|
will(returnValue(ownClient));
|
||||||
|
oneOf(ownClient).start();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectCreateClientForContactMailbox() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(mailboxClientFactory)
|
||||||
|
.createContactMailboxClient(reachabilityMonitor);
|
||||||
|
will(returnValue(contactClient));
|
||||||
|
oneOf(contactClient).start();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectAssignContactToOwnMailboxForDownload() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(ownClient).assignContactForDownload(contact.getId(),
|
||||||
|
ownProperties,
|
||||||
|
requireNonNull(localProperties.getOutboxId()));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectAssignContactToOwnMailboxForUpload() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(ownClient).assignContactForUpload(contact.getId(),
|
||||||
|
ownProperties,
|
||||||
|
requireNonNull(localProperties.getInboxId()));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectAssignContactToContactMailboxForDownload(
|
||||||
|
MailboxProperties remoteProperties) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(contactClient).assignContactForDownload(contact.getId(),
|
||||||
|
remoteProperties,
|
||||||
|
requireNonNull(remoteProperties.getInboxId()));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectAssignContactToContactMailboxForUpload(
|
||||||
|
MailboxProperties remoteProperties) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(contactClient).assignContactForUpload(contact.getId(),
|
||||||
|
remoteProperties,
|
||||||
|
requireNonNull(remoteProperties.getOutboxId()));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectDeassignContactFromOwnMailboxForUpload() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(ownClient).deassignContactForUpload(contact.getId());
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectDeassignContactFromOwnMailboxForDownload() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(ownClient).deassignContactForDownload(contact.getId());
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectDeassignContactFromContactMailboxForDownload() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(contactClient).deassignContactForDownload(contact.getId());
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectRunTaskOnEventExecutor() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(eventExecutor).execute(with(any(Runnable.class)));
|
||||||
|
will(new RunAction());
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectDestroyClientForOwnMailbox() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(ownClient).destroy();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectDestroyClientForContactMailbox() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(contactClient).destroy();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectDestroyReachabilityMonitor() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(reachabilityMonitor).destroy();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTIN
|
|||||||
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_UPLOADS_NAMESPACE;
|
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_UPLOADS_NAMESPACE;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getEvent;
|
import static org.briarproject.bramble.test.TestUtils.getEvent;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.hasEvent;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@@ -52,6 +53,7 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final MailboxProperties properties = new MailboxProperties(onion,
|
private final MailboxProperties properties = new MailboxProperties(onion,
|
||||||
token, serverSupports);
|
token, serverSupports);
|
||||||
private final int[] serverSupportsInts = {1, 0, 1, 1};
|
private final int[] serverSupportsInts = {1, 0, 1, 1};
|
||||||
|
private final Settings pairedSettings;
|
||||||
private final ContactId contactId1 = new ContactId(random.nextInt());
|
private final ContactId contactId1 = new ContactId(random.nextInt());
|
||||||
private final ContactId contactId2 = new ContactId(random.nextInt());
|
private final ContactId contactId2 = new ContactId(random.nextInt());
|
||||||
private final ContactId contactId3 = new ContactId(random.nextInt());
|
private final ContactId contactId3 = new ContactId(random.nextInt());
|
||||||
@@ -60,6 +62,14 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final long lastSuccess = now - 2345;
|
private final long lastSuccess = now - 2345;
|
||||||
private final int attempts = 123;
|
private final int attempts = 123;
|
||||||
|
|
||||||
|
public MailboxSettingsManagerImplTest() {
|
||||||
|
pairedSettings = new Settings();
|
||||||
|
pairedSettings.put(SETTINGS_KEY_ONION, onion);
|
||||||
|
pairedSettings.put(SETTINGS_KEY_TOKEN, token.toString());
|
||||||
|
pairedSettings.putIntArray(SETTINGS_KEY_SERVER_SUPPORTS,
|
||||||
|
serverSupportsInts);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReturnsNullPropertiesIfSettingsAreEmpty() throws Exception {
|
public void testReturnsNullPropertiesIfSettingsAreEmpty() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
@@ -76,14 +86,10 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReturnsProperties() throws Exception {
|
public void testReturnsProperties() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
Settings settings = new Settings();
|
|
||||||
settings.put(SETTINGS_KEY_ONION, onion);
|
|
||||||
settings.put(SETTINGS_KEY_TOKEN, token.toString());
|
|
||||||
settings.putIntArray(SETTINGS_KEY_SERVER_SUPPORTS, serverSupportsInts);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE);
|
oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE);
|
||||||
will(returnValue(settings));
|
will(returnValue(pairedSettings));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
MailboxProperties properties = manager.getOwnMailboxProperties(txn);
|
MailboxProperties properties = manager.getOwnMailboxProperties(txn);
|
||||||
@@ -97,16 +103,11 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testStoresProperties() throws Exception {
|
public void testStoresProperties() throws Exception {
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Settings expectedSettings = new Settings();
|
|
||||||
expectedSettings.put(SETTINGS_KEY_ONION, onion);
|
|
||||||
expectedSettings.put(SETTINGS_KEY_TOKEN, token.toString());
|
|
||||||
expectedSettings.putIntArray(SETTINGS_KEY_SERVER_SUPPORTS,
|
|
||||||
serverSupportsInts);
|
|
||||||
|
|
||||||
manager.registerMailboxHook(hook);
|
manager.registerMailboxHook(hook);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(settingsManager).mergeSettings(txn, expectedSettings,
|
oneOf(settingsManager).mergeSettings(txn, pairedSettings,
|
||||||
SETTINGS_NAMESPACE);
|
SETTINGS_NAMESPACE);
|
||||||
oneOf(hook).mailboxPaired(txn, properties);
|
oneOf(hook).mailboxPaired(txn, properties);
|
||||||
}});
|
}});
|
||||||
@@ -182,6 +183,8 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
serverSupportsInts);
|
serverSupportsInts);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE);
|
||||||
|
will(returnValue(pairedSettings));
|
||||||
oneOf(settingsManager).mergeSettings(txn, expectedSettings,
|
oneOf(settingsManager).mergeSettings(txn, expectedSettings,
|
||||||
SETTINGS_NAMESPACE);
|
SETTINGS_NAMESPACE);
|
||||||
}});
|
}});
|
||||||
@@ -196,22 +199,36 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertFalse(status.hasProblem(now));
|
assertFalse(status.hasProblem(now));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotRecordSuccessIfNotPaired() throws Exception {
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE);
|
||||||
|
will(returnValue(new Settings()));
|
||||||
|
}});
|
||||||
|
|
||||||
|
manager.recordSuccessfulConnection(txn, now, serverSupports);
|
||||||
|
assertFalse(hasEvent(txn, OwnMailboxConnectionStatusEvent.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecordsFailureOnFirstAttempt() throws Exception {
|
public void testRecordsFailureOnFirstAttempt() throws Exception {
|
||||||
testRecordsFailure(new Settings(), 0);
|
testRecordsFailure(pairedSettings, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecordsFailureOnLaterAttempt() throws Exception {
|
public void testRecordsFailureOnLaterAttempt() throws Exception {
|
||||||
Settings oldSettings = new Settings();
|
Settings oldSettings = new Settings();
|
||||||
|
oldSettings.putAll(pairedSettings);
|
||||||
oldSettings.putLong(SETTINGS_KEY_LAST_ATTEMPT, lastAttempt);
|
oldSettings.putLong(SETTINGS_KEY_LAST_ATTEMPT, lastAttempt);
|
||||||
oldSettings.putLong(SETTINGS_KEY_LAST_SUCCESS, lastSuccess);
|
oldSettings.putLong(SETTINGS_KEY_LAST_SUCCESS, lastSuccess);
|
||||||
oldSettings.putInt(SETTINGS_KEY_ATTEMPTS, attempts);
|
oldSettings.putInt(SETTINGS_KEY_ATTEMPTS, attempts);
|
||||||
testRecordsFailure(oldSettings, attempts);
|
testRecordsFailure(oldSettings, attempts, lastSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testRecordsFailure(Settings oldSettings, int oldAttempts)
|
private void testRecordsFailure(Settings oldSettings, int oldAttempts,
|
||||||
throws Exception {
|
long lastSuccess) throws Exception {
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
Settings expectedSettings = new Settings();
|
Settings expectedSettings = new Settings();
|
||||||
expectedSettings.putLong(SETTINGS_KEY_LAST_ATTEMPT, now);
|
expectedSettings.putLong(SETTINGS_KEY_LAST_ATTEMPT, now);
|
||||||
@@ -225,6 +242,25 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
manager.recordFailedConnectionAttempt(txn, now);
|
manager.recordFailedConnectionAttempt(txn, now);
|
||||||
|
OwnMailboxConnectionStatusEvent e =
|
||||||
|
getEvent(txn, OwnMailboxConnectionStatusEvent.class);
|
||||||
|
MailboxStatus status = e.getStatus();
|
||||||
|
assertEquals(now, status.getTimeOfLastAttempt());
|
||||||
|
assertEquals(lastSuccess, status.getTimeOfLastSuccess());
|
||||||
|
assertEquals(oldAttempts + 1, status.getAttemptsSinceSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotRecordFailureIfNotPaired() throws Exception {
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(settingsManager).getSettings(txn, SETTINGS_NAMESPACE);
|
||||||
|
will(returnValue(new Settings()));
|
||||||
|
}});
|
||||||
|
|
||||||
|
manager.recordFailedConnectionAttempt(txn, now);
|
||||||
|
assertFalse(hasEvent(txn, OwnMailboxConnectionStatusEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
|||||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||||
import org.briarproject.bramble.api.mailbox.event.MailboxPairedEvent;
|
import org.briarproject.bramble.api.mailbox.event.MailboxPairedEvent;
|
||||||
import org.briarproject.bramble.api.mailbox.event.MailboxUnpairedEvent;
|
import org.briarproject.bramble.api.mailbox.event.MailboxUnpairedEvent;
|
||||||
import org.briarproject.bramble.api.mailbox.event.MailboxUpdateSentEvent;
|
import org.briarproject.bramble.api.mailbox.event.MailboxUpdateSentToNewContactEvent;
|
||||||
import org.briarproject.bramble.api.mailbox.event.RemoteMailboxUpdateEvent;
|
import org.briarproject.bramble.api.mailbox.event.RemoteMailboxUpdateEvent;
|
||||||
import org.briarproject.bramble.api.sync.Group;
|
import org.briarproject.bramble.api.sync.Group;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
@@ -38,8 +38,10 @@ import java.util.Random;
|
|||||||
|
|
||||||
import static java.util.Collections.singleton;
|
import static java.util.Collections.singleton;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.CLIENT_ID;
|
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.CLIENT_ID;
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.GROUP_KEY_SENT_CLIENT_SUPPORTS;
|
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.GROUP_KEY_SENT_CLIENT_SUPPORTS;
|
||||||
|
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.GROUP_KEY_SENT_SERVER_SUPPORTS;
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.MAJOR_VERSION;
|
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.MAJOR_VERSION;
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.MSG_KEY_LOCAL;
|
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.MSG_KEY_LOCAL;
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.MSG_KEY_VERSION;
|
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.MSG_KEY_VERSION;
|
||||||
@@ -89,7 +91,10 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final BdfList someClientSupports;
|
private final BdfList someClientSupports;
|
||||||
private final List<MailboxVersion> newerClientSupportsList;
|
private final List<MailboxVersion> newerClientSupportsList;
|
||||||
private final BdfList newerClientSupports;
|
private final BdfList newerClientSupports;
|
||||||
|
private final List<MailboxVersion> someServerSupportsList;
|
||||||
private final BdfList someServerSupports;
|
private final BdfList someServerSupports;
|
||||||
|
private final List<MailboxVersion> newerServerSupportsList;
|
||||||
|
private final BdfList newerServerSupports;
|
||||||
private final BdfList emptyServerSupports = new BdfList();
|
private final BdfList emptyServerSupports = new BdfList();
|
||||||
private final MailboxProperties updateProps;
|
private final MailboxProperties updateProps;
|
||||||
private final MailboxUpdateWithMailbox updateWithMailbox;
|
private final MailboxUpdateWithMailbox updateWithMailbox;
|
||||||
@@ -110,11 +115,17 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
newerClientSupportsList.get(0).getMajor(),
|
newerClientSupportsList.get(0).getMajor(),
|
||||||
newerClientSupportsList.get(0).getMinor()));
|
newerClientSupportsList.get(0).getMinor()));
|
||||||
|
|
||||||
List<MailboxVersion> someServerSupportsList =
|
someServerSupportsList = singletonList(new MailboxVersion(
|
||||||
singletonList(new MailboxVersion(rnd.nextInt(), rnd.nextInt()));
|
rnd.nextInt(), rnd.nextInt()));
|
||||||
someServerSupports = BdfList.of(BdfList.of(
|
someServerSupports = BdfList.of(BdfList.of(
|
||||||
someServerSupportsList.get(0).getMajor(),
|
someServerSupportsList.get(0).getMajor(),
|
||||||
someServerSupportsList.get(0).getMinor()));
|
someServerSupportsList.get(0).getMinor()));
|
||||||
|
newerServerSupportsList = singletonList(new MailboxVersion(
|
||||||
|
someServerSupportsList.get(0).getMajor(),
|
||||||
|
someServerSupportsList.get(0).getMinor() + 1));
|
||||||
|
newerServerSupports = BdfList.of(BdfList.of(
|
||||||
|
newerServerSupportsList.get(0).getMajor(),
|
||||||
|
newerServerSupportsList.get(0).getMinor()));
|
||||||
|
|
||||||
updateNoMailbox = new MailboxUpdate(someClientSupportsList);
|
updateNoMailbox = new MailboxUpdate(someClientSupportsList);
|
||||||
|
|
||||||
@@ -187,8 +198,7 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
t.onDatabaseOpened(txn);
|
t.onDatabaseOpened(txn);
|
||||||
|
|
||||||
MailboxUpdateSentEvent e = getEvent(txn, MailboxUpdateSentEvent.class);
|
assertFalse(hasEvent(txn, MailboxUpdateSentToNewContactEvent.class));
|
||||||
assertNoMailboxPropertiesSent(e, someClientSupportsList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -243,8 +253,7 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
t.onDatabaseOpened(txn);
|
t.onDatabaseOpened(txn);
|
||||||
|
|
||||||
MailboxUpdateSentEvent e = getEvent(txn, MailboxUpdateSentEvent.class);
|
assertFalse(hasEvent(txn, MailboxUpdateSentToNewContactEvent.class));
|
||||||
assertMailboxPropertiesSent(e, someClientSupportsList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -295,8 +304,7 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
t.onDatabaseOpened(txn1);
|
t.onDatabaseOpened(txn1);
|
||||||
|
|
||||||
MailboxUpdateSentEvent e = getEvent(txn1, MailboxUpdateSentEvent.class);
|
assertFalse(hasEvent(txn1, MailboxUpdateSentToNewContactEvent.class));
|
||||||
assertNoMailboxPropertiesSent(e, someClientSupportsList);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(db).containsGroup(txn2, localGroup.getId());
|
oneOf(db).containsGroup(txn2, localGroup.getId());
|
||||||
@@ -311,7 +319,7 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
t = createInstance(someClientSupportsList);
|
t = createInstance(someClientSupportsList);
|
||||||
t.onDatabaseOpened(txn2);
|
t.onDatabaseOpened(txn2);
|
||||||
|
|
||||||
assertFalse(hasEvent(txn2, MailboxUpdateSentEvent.class));
|
assertFalse(hasEvent(txn2, MailboxUpdateSentToNewContactEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -363,9 +371,7 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
t.onDatabaseOpened(txn1);
|
t.onDatabaseOpened(txn1);
|
||||||
|
|
||||||
MailboxUpdateSentEvent e1 =
|
assertFalse(hasEvent(txn1, MailboxUpdateSentToNewContactEvent.class));
|
||||||
getEvent(txn1, MailboxUpdateSentEvent.class);
|
|
||||||
assertNoMailboxPropertiesSent(e1, someClientSupportsList);
|
|
||||||
|
|
||||||
BdfDictionary metaDictionary = BdfDictionary.of(
|
BdfDictionary metaDictionary = BdfDictionary.of(
|
||||||
new BdfEntry(MSG_KEY_VERSION, 1),
|
new BdfEntry(MSG_KEY_VERSION, 1),
|
||||||
@@ -427,9 +433,7 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
t = createInstance(newerClientSupportsList);
|
t = createInstance(newerClientSupportsList);
|
||||||
t.onDatabaseOpened(txn2);
|
t.onDatabaseOpened(txn2);
|
||||||
|
|
||||||
MailboxUpdateSentEvent e2 =
|
assertFalse(hasEvent(txn2, MailboxUpdateSentToNewContactEvent.class));
|
||||||
getEvent(txn2, MailboxUpdateSentEvent.class);
|
|
||||||
assertNoMailboxPropertiesSent(e2, newerClientSupportsList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -466,7 +470,8 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
t.addingContact(txn, contact);
|
t.addingContact(txn, contact);
|
||||||
|
|
||||||
MailboxUpdateSentEvent e = getEvent(txn, MailboxUpdateSentEvent.class);
|
MailboxUpdateSentToNewContactEvent
|
||||||
|
e = getEvent(txn, MailboxUpdateSentToNewContactEvent.class);
|
||||||
assertNoMailboxPropertiesSent(e, someClientSupportsList);
|
assertNoMailboxPropertiesSent(e, someClientSupportsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,7 +515,8 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
t.addingContact(txn, contact);
|
t.addingContact(txn, contact);
|
||||||
|
|
||||||
MailboxUpdateSentEvent e = getEvent(txn, MailboxUpdateSentEvent.class);
|
MailboxUpdateSentToNewContactEvent
|
||||||
|
e = getEvent(txn, MailboxUpdateSentToNewContactEvent.class);
|
||||||
assertMailboxPropertiesSent(e, someClientSupportsList);
|
assertMailboxPropertiesSent(e, someClientSupportsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -687,25 +693,33 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
new BdfEntry(MSG_KEY_VERSION, 3),
|
new BdfEntry(MSG_KEY_VERSION, 3),
|
||||||
new BdfEntry(MSG_KEY_LOCAL, false)
|
new BdfEntry(MSG_KEY_LOCAL, false)
|
||||||
));
|
));
|
||||||
|
BdfDictionary groupMetadata = new BdfDictionary();
|
||||||
|
groupMetadata.put(GROUP_KEY_SENT_SERVER_SUPPORTS, someServerSupports);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(db).getContacts(txn);
|
oneOf(db).getContacts(txn);
|
||||||
will(returnValue(contacts));
|
will(returnValue(contacts));
|
||||||
|
// Generate mailbox properties for contact
|
||||||
oneOf(crypto).generateUniqueId();
|
oneOf(crypto).generateUniqueId();
|
||||||
will(returnValue(updateProps.getAuthToken()));
|
will(returnValue(updateProps.getAuthToken()));
|
||||||
oneOf(crypto).generateUniqueId();
|
oneOf(crypto).generateUniqueId();
|
||||||
will(returnValue(updateProps.getInboxId()));
|
will(returnValue(updateProps.getInboxId()));
|
||||||
oneOf(crypto).generateUniqueId();
|
oneOf(crypto).generateUniqueId();
|
||||||
will(returnValue(updateProps.getOutboxId()));
|
will(returnValue(updateProps.getOutboxId()));
|
||||||
|
// Find latest update
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact);
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
contactGroupId);
|
contactGroupId);
|
||||||
will(returnValue(messageMetadata));
|
will(returnValue(messageMetadata));
|
||||||
|
// Replace latest update with new update
|
||||||
expectStoreMessage(txn, contactGroupId, 2, someClientSupports,
|
expectStoreMessage(txn, contactGroupId, 2, someClientSupports,
|
||||||
someServerSupports, propsDict);
|
someServerSupports, propsDict);
|
||||||
oneOf(db).removeMessage(txn, latestId);
|
oneOf(db).removeMessage(txn, latestId);
|
||||||
|
// Store sent server-supported versions
|
||||||
|
oneOf(clientHelper).mergeGroupMetadata(txn, localGroup.getId(),
|
||||||
|
groupMetadata);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
@@ -722,7 +736,7 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertEquals(updateWithMailbox.getMailboxProperties(),
|
assertEquals(updateWithMailbox.getMailboxProperties(),
|
||||||
u.getMailboxProperties());
|
u.getMailboxProperties());
|
||||||
|
|
||||||
assertFalse(hasEvent(txn, MailboxUpdateSentEvent.class));
|
assertFalse(hasEvent(txn, MailboxUpdateSentToNewContactEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -741,19 +755,26 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
new BdfEntry(MSG_KEY_VERSION, 3),
|
new BdfEntry(MSG_KEY_VERSION, 3),
|
||||||
new BdfEntry(MSG_KEY_LOCAL, false)
|
new BdfEntry(MSG_KEY_LOCAL, false)
|
||||||
));
|
));
|
||||||
|
BdfDictionary groupMetadata = new BdfDictionary();
|
||||||
|
groupMetadata.put(GROUP_KEY_SENT_SERVER_SUPPORTS, NULL_VALUE);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(db).getContacts(txn);
|
oneOf(db).getContacts(txn);
|
||||||
will(returnValue(contacts));
|
will(returnValue(contacts));
|
||||||
|
// Find latest update
|
||||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
MAJOR_VERSION, contact);
|
MAJOR_VERSION, contact);
|
||||||
will(returnValue(contactGroup));
|
will(returnValue(contactGroup));
|
||||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
contactGroupId);
|
contactGroupId);
|
||||||
will(returnValue(messageMetadata));
|
will(returnValue(messageMetadata));
|
||||||
|
// Replace latest update with new update
|
||||||
expectStoreMessage(txn, contactGroupId, 2, someClientSupports,
|
expectStoreMessage(txn, contactGroupId, 2, someClientSupports,
|
||||||
emptyServerSupports, emptyPropsDict);
|
emptyServerSupports, emptyPropsDict);
|
||||||
oneOf(db).removeMessage(txn, latestId);
|
oneOf(db).removeMessage(txn, latestId);
|
||||||
|
// Remove sent server-supported versions
|
||||||
|
oneOf(clientHelper).mergeGroupMetadata(txn, localGroup.getId(),
|
||||||
|
groupMetadata);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
@@ -765,7 +786,81 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
MailboxUpdate u = localUpdates.get(contact.getId());
|
MailboxUpdate u = localUpdates.get(contact.getId());
|
||||||
assertFalse(u.hasMailbox());
|
assertFalse(u.hasMailbox());
|
||||||
|
|
||||||
assertFalse(hasEvent(txn, MailboxUpdateSentEvent.class));
|
assertFalse(hasEvent(txn, MailboxUpdateSentToNewContactEvent.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStoresLocalUpdateWhenServerSupportsChange()
|
||||||
|
throws Exception {
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
Map<MessageId, BdfDictionary> messageMetadata = new LinkedHashMap<>();
|
||||||
|
MessageId latestId = new MessageId(getRandomId());
|
||||||
|
messageMetadata.put(latestId, BdfDictionary.of(
|
||||||
|
new BdfEntry(MSG_KEY_VERSION, 1),
|
||||||
|
new BdfEntry(MSG_KEY_LOCAL, true)
|
||||||
|
));
|
||||||
|
BdfList body = BdfList.of(1, someClientSupports, someServerSupports,
|
||||||
|
propsDict);
|
||||||
|
BdfDictionary oldGroupMetadata = new BdfDictionary();
|
||||||
|
oldGroupMetadata.put(GROUP_KEY_SENT_SERVER_SUPPORTS,
|
||||||
|
someServerSupports);
|
||||||
|
BdfDictionary newGroupMetadata = new BdfDictionary();
|
||||||
|
newGroupMetadata.put(GROUP_KEY_SENT_SERVER_SUPPORTS,
|
||||||
|
newerServerSupports);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Load sent server-supported versions
|
||||||
|
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||||
|
localGroup.getId());
|
||||||
|
will(returnValue(oldGroupMetadata));
|
||||||
|
oneOf(clientHelper).parseMailboxVersionList(someServerSupports);
|
||||||
|
will(returnValue(someServerSupportsList));
|
||||||
|
// Update sent server-supported versions
|
||||||
|
oneOf(clientHelper).mergeGroupMetadata(txn, localGroup.getId(),
|
||||||
|
newGroupMetadata);
|
||||||
|
oneOf(db).getContacts(txn);
|
||||||
|
will(returnValue(contacts));
|
||||||
|
// Find latest update
|
||||||
|
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||||
|
MAJOR_VERSION, contact);
|
||||||
|
will(returnValue(contactGroup));
|
||||||
|
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||||
|
contactGroupId);
|
||||||
|
will(returnValue(messageMetadata));
|
||||||
|
// Load and parse latest update
|
||||||
|
oneOf(clientHelper).getMessageAsList(txn, latestId);
|
||||||
|
will(returnValue(body));
|
||||||
|
oneOf(clientHelper).parseAndValidateMailboxUpdate(
|
||||||
|
someClientSupports, someServerSupports, propsDict);
|
||||||
|
will(returnValue(updateWithMailbox));
|
||||||
|
// Replace latest update with new update
|
||||||
|
expectStoreMessage(txn, contactGroupId, 2, someClientSupports,
|
||||||
|
newerServerSupports, propsDict);
|
||||||
|
oneOf(db).removeMessage(txn, latestId);
|
||||||
|
}});
|
||||||
|
|
||||||
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
|
t.serverSupportedVersionsReceived(txn, newerServerSupportsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotStoreLocalUpdateWhenServerSupportsAreUnchanged()
|
||||||
|
throws Exception {
|
||||||
|
Transaction txn = new Transaction(null, false);
|
||||||
|
BdfDictionary groupMetadata = new BdfDictionary();
|
||||||
|
groupMetadata.put(GROUP_KEY_SENT_SERVER_SUPPORTS, someServerSupports);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Load sent server-supported versions
|
||||||
|
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||||
|
localGroup.getId());
|
||||||
|
will(returnValue(groupMetadata));
|
||||||
|
oneOf(clientHelper).parseMailboxVersionList(someServerSupports);
|
||||||
|
will(returnValue(someServerSupportsList));
|
||||||
|
}});
|
||||||
|
|
||||||
|
MailboxUpdateManagerImpl t = createInstance(someClientSupportsList);
|
||||||
|
t.serverSupportedVersionsReceived(txn, someServerSupportsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -948,7 +1043,8 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertNoMailboxPropertiesSent(MailboxUpdateSentEvent e,
|
private void assertNoMailboxPropertiesSent(
|
||||||
|
MailboxUpdateSentToNewContactEvent e,
|
||||||
List<MailboxVersion> clientSupports) {
|
List<MailboxVersion> clientSupports) {
|
||||||
assertEquals(contact.getId(), e.getContactId());
|
assertEquals(contact.getId(), e.getContactId());
|
||||||
MailboxUpdate u = e.getMailboxUpdate();
|
MailboxUpdate u = e.getMailboxUpdate();
|
||||||
@@ -956,7 +1052,8 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertFalse(u.hasMailbox());
|
assertFalse(u.hasMailbox());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertMailboxPropertiesSent(MailboxUpdateSentEvent e,
|
private void assertMailboxPropertiesSent(
|
||||||
|
MailboxUpdateSentToNewContactEvent e,
|
||||||
List<MailboxVersion> clientSupports) {
|
List<MailboxVersion> clientSupports) {
|
||||||
assertEquals(contact.getId(), e.getContactId());
|
assertEquals(contact.getId(), e.getContactId());
|
||||||
MailboxUpdate u = e.getMailboxUpdate();
|
MailboxUpdate u = e.getMailboxUpdate();
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Cancellable;
|
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.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
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.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||||
import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
|
import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
|
||||||
@@ -25,10 +29,13 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyMap;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
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.CLIENT_SUPPORTS;
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.MAX_LATENCY;
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.MAX_LATENCY;
|
||||||
@@ -50,6 +57,8 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
private final TaskScheduler taskScheduler =
|
private final TaskScheduler taskScheduler =
|
||||||
context.mock(TaskScheduler.class);
|
context.mock(TaskScheduler.class);
|
||||||
private final EventBus eventBus = context.mock(EventBus.class);
|
private final EventBus eventBus = context.mock(EventBus.class);
|
||||||
|
private final ConnectionRegistry connectionRegistry =
|
||||||
|
context.mock(ConnectionRegistry.class);
|
||||||
private final ConnectivityChecker connectivityChecker =
|
private final ConnectivityChecker connectivityChecker =
|
||||||
context.mock(ConnectivityChecker.class);
|
context.mock(ConnectivityChecker.class);
|
||||||
private final MailboxApiCaller mailboxApiCaller =
|
private final MailboxApiCaller mailboxApiCaller =
|
||||||
@@ -72,6 +81,9 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
private final MessageId ackedId = new MessageId(getRandomId());
|
private final MessageId ackedId = new MessageId(getRandomId());
|
||||||
private final MessageId sentId = new MessageId(getRandomId());
|
private final MessageId sentId = new MessageId(getRandomId());
|
||||||
private final MessageId newMessageId = new MessageId(getRandomId());
|
private final MessageId newMessageId = new MessageId(getRandomId());
|
||||||
|
private final GroupId groupId = new GroupId(getRandomId());
|
||||||
|
private final Map<ContactId, Boolean> groupVisibility =
|
||||||
|
singletonMap(contactId, true);
|
||||||
|
|
||||||
private File testDir, tempFile;
|
private File testDir, tempFile;
|
||||||
private MailboxUploadWorker worker;
|
private MailboxUploadWorker worker;
|
||||||
@@ -81,8 +93,9 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
testDir = getTestDirectory();
|
testDir = getTestDirectory();
|
||||||
tempFile = new File(testDir, "temp");
|
tempFile = new File(testDir, "temp");
|
||||||
worker = new MailboxUploadWorker(ioExecutor, db, clock, taskScheduler,
|
worker = new MailboxUploadWorker(ioExecutor, db, clock, taskScheduler,
|
||||||
eventBus, connectivityChecker, mailboxApiCaller, mailboxApi,
|
eventBus, connectionRegistry, connectivityChecker,
|
||||||
mailboxFileManager, mailboxProperties, folderId, contactId);
|
mailboxApiCaller, mailboxApi, mailboxFileManager,
|
||||||
|
mailboxProperties, folderId, contactId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -93,8 +106,11 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testChecksForDataWhenStartedAndRemovesObserverWhenDestroyed()
|
public void testChecksForDataWhenStartedAndRemovesObserverWhenDestroyed()
|
||||||
throws Exception {
|
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();
|
expectRunTaskOnIoExecutor();
|
||||||
|
expectCheckConnectionRegistry(false);
|
||||||
expectCheckForDataToSendNoDataWaiting();
|
expectCheckForDataToSendNoDataWaiting();
|
||||||
|
|
||||||
worker.start();
|
worker.start();
|
||||||
@@ -106,15 +122,59 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
worker.destroy();
|
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
|
@Test
|
||||||
public void testChecksConnectivityWhenStartedIfDataIsReady()
|
public void testChecksConnectivityWhenStartedIfDataIsReady()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Transaction recordTxn = new Transaction(null, false);
|
Transaction recordTxn = new Transaction(null, false);
|
||||||
|
|
||||||
// When the worker is started it should check for data to send. As
|
// When the worker is started it should check the connection registry.
|
||||||
// there's data ready to send immediately, the worker should start a
|
// We're not connected to the contact, so the worker should check for
|
||||||
// connectivity check
|
// data to send. As there's data ready to send immediately, the worker
|
||||||
|
// should start a connectivity check
|
||||||
expectRunTaskOnIoExecutor();
|
expectRunTaskOnIoExecutor();
|
||||||
|
expectCheckConnectionRegistry(false);
|
||||||
expectCheckForDataToSendAndStartConnectivityCheck();
|
expectCheckForDataToSendAndStartConnectivityCheck();
|
||||||
|
|
||||||
worker.start();
|
worker.start();
|
||||||
@@ -149,7 +209,9 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
worker.onConnectivityCheckSucceeded();
|
worker.onConnectivityCheckSucceeded();
|
||||||
|
|
||||||
// When the upload task runs, it should upload the file, record
|
// 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() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(mailboxApi).addFile(mailboxProperties, folderId, tempFile);
|
oneOf(mailboxApi).addFile(mailboxProperties, folderId, tempFile);
|
||||||
oneOf(db).transaction(with(false), withDbRunnable(recordTxn));
|
oneOf(db).transaction(with(false), withDbRunnable(recordTxn));
|
||||||
@@ -157,6 +219,7 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
oneOf(db).setMessagesSent(recordTxn, contactId,
|
oneOf(db).setMessagesSent(recordTxn, contactId,
|
||||||
singletonList(sentId), MAX_LATENCY);
|
singletonList(sentId), MAX_LATENCY);
|
||||||
}});
|
}});
|
||||||
|
expectCheckConnectionRegistry(false);
|
||||||
expectCheckForDataToSendNoDataWaiting();
|
expectCheckForDataToSendNoDataWaiting();
|
||||||
|
|
||||||
assertFalse(upload.get().callApi());
|
assertFalse(upload.get().callApi());
|
||||||
@@ -172,11 +235,41 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCancelsApiCallWhenDestroyed() throws Exception {
|
public void testDoesNotWriteFileIfContactConnectsDuringConnectivityCheck()
|
||||||
// When the worker is started it should check for data to send. As
|
throws Exception {
|
||||||
// there's data ready to send immediately, the worker should start a
|
// When the worker is started it should check the connection registry.
|
||||||
// connectivity check
|
// 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();
|
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();
|
expectCheckForDataToSendAndStartConnectivityCheck();
|
||||||
|
|
||||||
worker.start();
|
worker.start();
|
||||||
@@ -212,9 +305,7 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// When the worker is destroyed it should remove the connectivity
|
// When the worker is destroyed it should remove the connectivity
|
||||||
// observer and event listener and cancel the upload task
|
// observer and event listener and cancel the upload task
|
||||||
context.checking(new Expectations() {{
|
expectCancelTask(apiCall);
|
||||||
oneOf(apiCall).cancel();
|
|
||||||
}});
|
|
||||||
expectRemoveObserverAndListener();
|
expectRemoveObserverAndListener();
|
||||||
|
|
||||||
worker.destroy();
|
worker.destroy();
|
||||||
@@ -230,16 +321,21 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testSchedulesWakeupWhenStartedIfDataIsNotReady()
|
public void testSchedulesWakeupWhenStartedIfDataIsNotReady()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// When the worker is started it should check for data to send. As
|
// When the worker is started it should check the connection registry.
|
||||||
// the data isn't ready to send immediately, the worker should
|
// We're not connected to the contact, so the worker should check for
|
||||||
// schedule a wakeup
|
// data to send. As the data isn't ready to send immediately, the
|
||||||
|
// worker should schedule a wakeup
|
||||||
expectRunTaskOnIoExecutor();
|
expectRunTaskOnIoExecutor();
|
||||||
AtomicReference<Runnable> wakeup = new AtomicReference<>();
|
AtomicReference<Runnable> wakeup = new AtomicReference<>();
|
||||||
|
expectCheckConnectionRegistry(false);
|
||||||
expectCheckForDataToSendAndScheduleWakeup(wakeup);
|
expectCheckForDataToSendAndScheduleWakeup(wakeup);
|
||||||
|
|
||||||
worker.start();
|
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();
|
expectCheckForDataToSendNoDataWaiting();
|
||||||
|
|
||||||
wakeup.get().run();
|
wakeup.get().run();
|
||||||
@@ -252,21 +348,51 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCancelsWakeupIfDestroyedBeforeWakingUp() throws Exception {
|
public void testCancelsWakeupIfContactConnectsBeforeWakingUp()
|
||||||
|
throws Exception {
|
||||||
// When the worker is started it should check for data to send. As
|
// When the worker is started it should check for data to send. As
|
||||||
// the data isn't ready to send immediately, the worker should
|
// the data isn't ready to send immediately, the worker should
|
||||||
// schedule a wakeup
|
// schedule a wakeup
|
||||||
expectRunTaskOnIoExecutor();
|
expectRunTaskOnIoExecutor();
|
||||||
AtomicReference<Runnable> wakeup = new AtomicReference<>();
|
AtomicReference<Runnable> 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<Runnable> wakeup = new AtomicReference<>();
|
||||||
expectCheckForDataToSendAndScheduleWakeup(wakeup);
|
expectCheckForDataToSendAndScheduleWakeup(wakeup);
|
||||||
|
|
||||||
worker.start();
|
worker.start();
|
||||||
|
|
||||||
// When the worker is destroyed it should cancel the wakeup and
|
// When the worker is destroyed it should cancel the wakeup and
|
||||||
// remove the connectivity observer and event listener
|
// remove the connectivity observer and event listener
|
||||||
context.checking(new Expectations() {{
|
expectCancelTask(wakeupTask);
|
||||||
oneOf(wakeupTask).cancel();
|
|
||||||
}});
|
|
||||||
expectRemoveObserverAndListener();
|
expectRemoveObserverAndListener();
|
||||||
|
|
||||||
worker.destroy();
|
worker.destroy();
|
||||||
@@ -279,10 +405,12 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testCancelsWakeupIfEventIsReceivedBeforeWakingUp()
|
public void testCancelsWakeupIfEventIsReceivedBeforeWakingUp()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// When the worker is started it should check for data to send. As
|
// When the worker is started it should check the connection registry.
|
||||||
// the data isn't ready to send immediately, the worker should
|
// We're not connected to the contact, so the worker should check for
|
||||||
// schedule a wakeup
|
// data to send. As the data isn't ready to send immediately, the
|
||||||
|
// worker should schedule a wakeup
|
||||||
expectRunTaskOnIoExecutor();
|
expectRunTaskOnIoExecutor();
|
||||||
|
expectCheckConnectionRegistry(false);
|
||||||
AtomicReference<Runnable> wakeup = new AtomicReference<>();
|
AtomicReference<Runnable> wakeup = new AtomicReference<>();
|
||||||
expectCheckForDataToSendAndScheduleWakeup(wakeup);
|
expectCheckForDataToSendAndScheduleWakeup(wakeup);
|
||||||
|
|
||||||
@@ -293,11 +421,10 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
// wakeup task and schedule a check for new data after a short delay
|
// wakeup task and schedule a check for new data after a short delay
|
||||||
AtomicReference<Runnable> check = new AtomicReference<>();
|
AtomicReference<Runnable> check = new AtomicReference<>();
|
||||||
expectScheduleCheck(check, CHECK_DELAY_MS);
|
expectScheduleCheck(check, CHECK_DELAY_MS);
|
||||||
context.checking(new Expectations() {{
|
expectCancelTask(wakeupTask);
|
||||||
oneOf(wakeupTask).cancel();
|
|
||||||
}});
|
|
||||||
|
|
||||||
worker.eventOccurred(new MessageSharedEvent(newMessageId));
|
worker.eventOccurred(new MessageSharedEvent(newMessageId, groupId,
|
||||||
|
groupVisibility));
|
||||||
|
|
||||||
// If the wakeup task runs anyway (cancellation came too late), it
|
// If the wakeup task runs anyway (cancellation came too late), it
|
||||||
// should return early when it finds the state has changed
|
// should return early when it finds the state has changed
|
||||||
@@ -306,9 +433,13 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
// Before the check task runs, the worker receives another event that
|
// Before the check task runs, the worker receives another event that
|
||||||
// indicates new data may be available. The event should be ignored,
|
// indicates new data may be available. The event should be ignored,
|
||||||
// as a check for new data has already been scheduled
|
// 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();
|
expectCheckForDataToSendNoDataWaiting();
|
||||||
|
|
||||||
check.get().run();
|
check.get().run();
|
||||||
@@ -322,8 +453,11 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCancelsCheckWhenDestroyed() throws Exception {
|
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();
|
expectRunTaskOnIoExecutor();
|
||||||
|
expectCheckConnectionRegistry(false);
|
||||||
expectCheckForDataToSendNoDataWaiting();
|
expectCheckForDataToSendNoDataWaiting();
|
||||||
|
|
||||||
worker.start();
|
worker.start();
|
||||||
@@ -334,13 +468,12 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
AtomicReference<Runnable> check = new AtomicReference<>();
|
AtomicReference<Runnable> check = new AtomicReference<>();
|
||||||
expectScheduleCheck(check, CHECK_DELAY_MS);
|
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
|
// When the worker is destroyed it should cancel the check and
|
||||||
// remove the connectivity observer and event listener
|
// remove the connectivity observer and event listener
|
||||||
context.checking(new Expectations() {{
|
expectCancelTask(checkTask);
|
||||||
oneOf(checkTask).cancel();
|
|
||||||
}});
|
|
||||||
expectRemoveObserverAndListener();
|
expectRemoveObserverAndListener();
|
||||||
|
|
||||||
worker.destroy();
|
worker.destroy();
|
||||||
@@ -350,13 +483,100 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
check.get().run();
|
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<Runnable> 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 remove the connectivity
|
||||||
|
// observer and event listener
|
||||||
|
expectRemoveObserverAndListener();
|
||||||
|
|
||||||
|
worker.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotScheduleCheckIfGroupIsVisible() 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 group is visible to the contact but not shared, so
|
||||||
|
// the worker should not schedule a check for new data
|
||||||
|
worker.eventOccurred(new MessageSharedEvent(newMessageId, groupId,
|
||||||
|
singletonMap(contactId, false)));
|
||||||
|
|
||||||
|
// When the worker is destroyed it should remove the connectivity
|
||||||
|
// observer and event listener
|
||||||
|
expectRemoveObserverAndListener();
|
||||||
|
|
||||||
|
worker.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotScheduleCheckIfGroupIsInvisible() 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 group is not visible to the contact, so the worker
|
||||||
|
// should not schedule a check for new data
|
||||||
|
worker.eventOccurred(new MessageSharedEvent(newMessageId, groupId,
|
||||||
|
emptyMap()));
|
||||||
|
|
||||||
|
// When the worker is destroyed it should remove the connectivity
|
||||||
|
// observer and event listener
|
||||||
|
expectRemoveObserverAndListener();
|
||||||
|
|
||||||
|
worker.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRetriesAfterDelayIfExceptionOccursWhileWritingFile()
|
public void testRetriesAfterDelayIfExceptionOccursWhileWritingFile()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// When the worker is started it should check for data to send. As
|
// When the worker is started it should check the connection registry.
|
||||||
// there's data ready to send immediately, the worker should start a
|
// We're not connected to the contact, so the worker should check for
|
||||||
// connectivity check
|
// data to send. As there's data ready to send immediately, the worker
|
||||||
|
// should start a connectivity check
|
||||||
expectRunTaskOnIoExecutor();
|
expectRunTaskOnIoExecutor();
|
||||||
|
expectCheckConnectionRegistry(false);
|
||||||
expectCheckForDataToSendAndStartConnectivityCheck();
|
expectCheckForDataToSendAndStartConnectivityCheck();
|
||||||
|
|
||||||
worker.start();
|
worker.start();
|
||||||
@@ -375,7 +595,10 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
worker.onConnectivityCheckSucceeded();
|
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();
|
expectCheckForDataToSendNoDataWaiting();
|
||||||
|
|
||||||
check.get().run();
|
check.get().run();
|
||||||
@@ -387,6 +610,13 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
worker.destroy();
|
worker.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expectCheckConnectionRegistry(boolean connected) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(connectionRegistry).isConnected(contactId);
|
||||||
|
will(returnValue(connected));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
private void expectRunTaskOnIoExecutor() {
|
private void expectRunTaskOnIoExecutor() {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(ioExecutor).execute(with(any(Runnable.class)));
|
oneOf(ioExecutor).execute(with(any(Runnable.class)));
|
||||||
@@ -456,6 +686,12 @@ public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expectCancelTask(Cancellable task) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(task).cancel();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
private void expectRemoveObserverAndListener() {
|
private void expectRemoveObserverAndListener() {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(connectivityChecker).removeObserver(worker);
|
oneOf(connectivityChecker).removeObserver(worker);
|
||||||
|
|||||||
@@ -1,13 +1,22 @@
|
|||||||
package org.briarproject.bramble.mailbox;
|
package org.briarproject.bramble.mailbox;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Cancellable;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||||
|
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
|
import org.jmock.lib.action.DoAllAction;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
||||||
|
import static org.briarproject.bramble.mailbox.OwnMailboxClient.CONNECTIVITY_CHECK_INTERVAL_MS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
@@ -20,6 +29,9 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
context.mock(ConnectivityChecker.class);
|
context.mock(ConnectivityChecker.class);
|
||||||
private final TorReachabilityMonitor reachabilityMonitor =
|
private final TorReachabilityMonitor reachabilityMonitor =
|
||||||
context.mock(TorReachabilityMonitor.class);
|
context.mock(TorReachabilityMonitor.class);
|
||||||
|
private final TaskScheduler taskScheduler =
|
||||||
|
context.mock(TaskScheduler.class);
|
||||||
|
private final Executor ioExecutor = context.mock(Executor.class);
|
||||||
private final MailboxWorker contactListWorker =
|
private final MailboxWorker contactListWorker =
|
||||||
context.mock(MailboxWorker.class, "contactListWorker");
|
context.mock(MailboxWorker.class, "contactListWorker");
|
||||||
private final MailboxWorker uploadWorker1 =
|
private final MailboxWorker uploadWorker1 =
|
||||||
@@ -28,6 +40,8 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
context.mock(MailboxWorker.class, "uploadWorker2");
|
context.mock(MailboxWorker.class, "uploadWorker2");
|
||||||
private final MailboxWorker downloadWorker =
|
private final MailboxWorker downloadWorker =
|
||||||
context.mock(MailboxWorker.class, "downloadWorker");
|
context.mock(MailboxWorker.class, "downloadWorker");
|
||||||
|
private final Cancellable connectivityCheck =
|
||||||
|
context.mock(Cancellable.class);
|
||||||
|
|
||||||
private final MailboxProperties properties =
|
private final MailboxProperties properties =
|
||||||
getMailboxProperties(true, CLIENT_SUPPORTS);
|
getMailboxProperties(true, CLIENT_SUPPORTS);
|
||||||
@@ -40,12 +54,13 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
public OwnMailboxClientTest() {
|
public OwnMailboxClientTest() {
|
||||||
expectCreateContactListWorker();
|
expectCreateContactListWorker();
|
||||||
client = new OwnMailboxClient(workerFactory, connectivityChecker,
|
client = new OwnMailboxClient(workerFactory, connectivityChecker,
|
||||||
reachabilityMonitor, properties);
|
reachabilityMonitor, taskScheduler, ioExecutor, properties);
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartAndDestroyWithNoContactsAssigned() {
|
public void testStartAndDestroyWithNoContactsAssigned() {
|
||||||
|
expectStartConnectivityCheck();
|
||||||
expectStartWorker(contactListWorker);
|
expectStartWorker(contactListWorker);
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
@@ -56,6 +71,7 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAssignContactForUploadAndDestroyClient() {
|
public void testAssignContactForUploadAndDestroyClient() {
|
||||||
|
expectStartConnectivityCheck();
|
||||||
expectStartWorker(contactListWorker);
|
expectStartWorker(contactListWorker);
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
@@ -74,6 +90,7 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAssignAndDeassignContactForUpload() {
|
public void testAssignAndDeassignContactForUpload() {
|
||||||
|
expectStartConnectivityCheck();
|
||||||
expectStartWorker(contactListWorker);
|
expectStartWorker(contactListWorker);
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
@@ -95,6 +112,7 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAssignAndDeassignTwoContactsForUpload() {
|
public void testAssignAndDeassignTwoContactsForUpload() {
|
||||||
|
expectStartConnectivityCheck();
|
||||||
expectStartWorker(contactListWorker);
|
expectStartWorker(contactListWorker);
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
@@ -129,6 +147,7 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAssignContactForDownloadAndDestroyClient() {
|
public void testAssignContactForDownloadAndDestroyClient() {
|
||||||
|
expectStartConnectivityCheck();
|
||||||
expectStartWorker(contactListWorker);
|
expectStartWorker(contactListWorker);
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
@@ -147,6 +166,7 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAssignAndDeassignTwoContactsForDownload() {
|
public void testAssignAndDeassignTwoContactsForDownload() {
|
||||||
|
expectStartConnectivityCheck();
|
||||||
expectStartWorker(contactListWorker);
|
expectStartWorker(contactListWorker);
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
@@ -175,6 +195,68 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
client.destroy();
|
client.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCancelsConnectivityCheckWhenClientIsDestroyed() {
|
||||||
|
expectStartConnectivityCheck();
|
||||||
|
expectStartWorker(contactListWorker);
|
||||||
|
client.start();
|
||||||
|
|
||||||
|
// When the first connectivity check succeeds, the worker should
|
||||||
|
// schedule a second check
|
||||||
|
AtomicReference<Runnable> task = new AtomicReference<>();
|
||||||
|
expectScheduleConnectivityCheck(task);
|
||||||
|
client.onConnectivityCheckSucceeded();
|
||||||
|
|
||||||
|
// When the task runs, the worker should check the mailbox's
|
||||||
|
// connectivity
|
||||||
|
expectStartConnectivityCheck();
|
||||||
|
task.get().run();
|
||||||
|
|
||||||
|
// When the second connectivity check succeeds, the worker should
|
||||||
|
// schedule a third check
|
||||||
|
expectScheduleConnectivityCheck(task);
|
||||||
|
client.onConnectivityCheckSucceeded();
|
||||||
|
|
||||||
|
// When the client is destroyed, the scheduled check should be cancelled
|
||||||
|
expectDestroyWorker(contactListWorker);
|
||||||
|
expectDestroyConnectivityChecker();
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(connectivityCheck).cancel();
|
||||||
|
}});
|
||||||
|
client.destroy();
|
||||||
|
|
||||||
|
// If the task runs anyway (cancellation came too late), it should
|
||||||
|
// return when it finds that the client has been destroyed
|
||||||
|
task.get().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIgnoresConnectivityResultWhenClientIsDestroyed() {
|
||||||
|
expectStartConnectivityCheck();
|
||||||
|
expectStartWorker(contactListWorker);
|
||||||
|
client.start();
|
||||||
|
|
||||||
|
// When the first connectivity check succeeds, the worker should
|
||||||
|
// schedule a second check
|
||||||
|
AtomicReference<Runnable> task = new AtomicReference<>();
|
||||||
|
expectScheduleConnectivityCheck(task);
|
||||||
|
client.onConnectivityCheckSucceeded();
|
||||||
|
|
||||||
|
// When the task runs, the worker should check the mailbox's
|
||||||
|
// connectivity
|
||||||
|
expectStartConnectivityCheck();
|
||||||
|
task.get().run();
|
||||||
|
|
||||||
|
// Before the connectivity check succeeds, the client is destroyed
|
||||||
|
expectDestroyWorker(contactListWorker);
|
||||||
|
expectDestroyConnectivityChecker();
|
||||||
|
client.destroy();
|
||||||
|
|
||||||
|
// If the connectivity check succeeds despite the connectivity checker
|
||||||
|
// having been destroyed, the client should not schedule another check
|
||||||
|
client.onConnectivityCheckSucceeded();
|
||||||
|
}
|
||||||
|
|
||||||
private void expectCreateContactListWorker() {
|
private void expectCreateContactListWorker() {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(workerFactory).createContactListWorkerForOwnMailbox(
|
oneOf(workerFactory).createContactListWorkerForOwnMailbox(
|
||||||
@@ -206,6 +288,25 @@ public class OwnMailboxClientTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expectStartConnectivityCheck() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(connectivityChecker).checkConnectivity(properties, client);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectScheduleConnectivityCheck(
|
||||||
|
AtomicReference<Runnable> task) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(taskScheduler).schedule(with(any(Runnable.class)),
|
||||||
|
with(ioExecutor), with(CONNECTIVITY_CHECK_INTERVAL_MS),
|
||||||
|
with(TimeUnit.MILLISECONDS));
|
||||||
|
will(new DoAllAction(
|
||||||
|
new CaptureArgumentAction<>(task, Runnable.class, 0),
|
||||||
|
returnValue(connectivityCheck)
|
||||||
|
));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
private void expectDestroyWorker(MailboxWorker worker) {
|
private void expectDestroyWorker(MailboxWorker worker) {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(worker).destroy();
|
oneOf(worker).destroy();
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ import org.briarproject.bramble.event.DefaultEventExecutorModule;
|
|||||||
import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule;
|
import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule;
|
||||||
import org.briarproject.bramble.system.TimeTravelModule;
|
import org.briarproject.bramble.system.TimeTravelModule;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfigModule;
|
import org.briarproject.bramble.test.TestDatabaseConfigModule;
|
||||||
|
import org.briarproject.bramble.test.TestDnsModule;
|
||||||
import org.briarproject.bramble.test.TestFeatureFlagModule;
|
import org.briarproject.bramble.test.TestFeatureFlagModule;
|
||||||
import org.briarproject.bramble.test.TestMailboxDirectoryModule;
|
import org.briarproject.bramble.test.TestMailboxDirectoryModule;
|
||||||
import org.briarproject.bramble.test.TestSecureRandomModule;
|
import org.briarproject.bramble.test.TestSecureRandomModule;
|
||||||
|
import org.briarproject.bramble.test.TestSocksModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
@@ -27,12 +29,14 @@ import dagger.Component;
|
|||||||
DefaultEventExecutorModule.class,
|
DefaultEventExecutorModule.class,
|
||||||
DefaultWakefulIoExecutorModule.class,
|
DefaultWakefulIoExecutorModule.class,
|
||||||
TestDatabaseConfigModule.class,
|
TestDatabaseConfigModule.class,
|
||||||
|
TestDnsModule.class,
|
||||||
TestFeatureFlagModule.class,
|
TestFeatureFlagModule.class,
|
||||||
TestMailboxDirectoryModule.class,
|
TestMailboxDirectoryModule.class,
|
||||||
RemovableDriveIntegrationTestModule.class,
|
RemovableDriveIntegrationTestModule.class,
|
||||||
RemovableDriveModule.class,
|
RemovableDriveModule.class,
|
||||||
TestSecureRandomModule.class,
|
TestSecureRandomModule.class,
|
||||||
TimeTravelModule.class
|
TimeTravelModule.class,
|
||||||
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
interface RemovableDriveIntegrationTestComponent
|
interface RemovableDriveIntegrationTestComponent
|
||||||
extends BrambleCoreEagerSingletons {
|
extends BrambleCoreEagerSingletons {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package org.briarproject.bramble.sync;
|
|||||||
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
|
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
|
||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
||||||
|
import org.briarproject.bramble.test.TestDnsModule;
|
||||||
|
import org.briarproject.bramble.test.TestSocksModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
@@ -11,7 +13,9 @@ import dagger.Component;
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
BrambleCoreIntegrationTestModule.class,
|
BrambleCoreIntegrationTestModule.class,
|
||||||
BrambleCoreModule.class
|
BrambleCoreModule.class,
|
||||||
|
TestDnsModule.class,
|
||||||
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
interface SyncIntegrationTestComponent extends
|
interface SyncIntegrationTestComponent extends
|
||||||
BrambleCoreIntegrationTestEagerSingletons {
|
BrambleCoreIntegrationTestEagerSingletons {
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import dagger.Component;
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
BrambleCoreIntegrationTestModule.class,
|
BrambleCoreIntegrationTestModule.class,
|
||||||
BrambleCoreModule.class
|
BrambleCoreModule.class,
|
||||||
|
TestDnsModule.class,
|
||||||
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
public interface BrambleIntegrationTestComponent
|
public interface BrambleIntegrationTestComponent
|
||||||
extends BrambleCoreIntegrationTestEagerSingletons {
|
extends BrambleCoreIntegrationTestEagerSingletons {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.test;
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
@@ -9,6 +9,8 @@ import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
|||||||
import org.briarproject.bramble.api.transport.KeyManager;
|
import org.briarproject.bramble.api.transport.KeyManager;
|
||||||
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
||||||
import org.briarproject.bramble.test.BrambleIntegrationTestComponent;
|
import org.briarproject.bramble.test.BrambleIntegrationTestComponent;
|
||||||
|
import org.briarproject.bramble.test.TestDnsModule;
|
||||||
|
import org.briarproject.bramble.test.TestSocksModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
@@ -17,7 +19,9 @@ import dagger.Component;
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
BrambleCoreIntegrationTestModule.class,
|
BrambleCoreIntegrationTestModule.class,
|
||||||
BrambleCoreModule.class
|
BrambleCoreModule.class,
|
||||||
|
TestDnsModule.class,
|
||||||
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
interface TransportKeyAgreementTestComponent
|
interface TransportKeyAgreementTestComponent
|
||||||
extends BrambleIntegrationTestComponent {
|
extends BrambleIntegrationTestComponent {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ apply plugin: 'idea'
|
|||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
apply from: '../dagger.gradle'
|
apply from: '../dagger.gradle'
|
||||||
|
apply plugin: 'checkstyle'
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
tor
|
tor
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble;
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.io.DnsModule;
|
||||||
import org.briarproject.bramble.network.JavaNetworkModule;
|
import org.briarproject.bramble.network.JavaNetworkModule;
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
||||||
import org.briarproject.bramble.socks.SocksModule;
|
import org.briarproject.bramble.socks.SocksModule;
|
||||||
@@ -9,6 +10,7 @@ import dagger.Module;
|
|||||||
|
|
||||||
@Module(includes = {
|
@Module(includes = {
|
||||||
CircumventionModule.class,
|
CircumventionModule.class,
|
||||||
|
DnsModule.class,
|
||||||
JavaNetworkModule.class,
|
JavaNetworkModule.class,
|
||||||
JavaSystemModule.class,
|
JavaSystemModule.class,
|
||||||
SocksModule.class
|
SocksModule.class
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
|||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
|
import org.briarproject.bramble.api.plugin.TorControlPort;
|
||||||
|
import org.briarproject.bramble.api.plugin.TorSocksPort;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
@@ -42,8 +44,6 @@ import static java.util.Collections.singletonList;
|
|||||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
import static java.util.logging.Logger.getLogger;
|
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.ACTIVE;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT;
|
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT;
|
|
||||||
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4;
|
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.DEFAULT_OBFS4;
|
||||||
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK;
|
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.MEEK;
|
||||||
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4;
|
import static org.briarproject.bramble.plugin.tor.CircumventionProvider.BridgeType.NON_DEFAULT_OBFS4;
|
||||||
@@ -89,9 +89,6 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
private final static long MEEK_TIMEOUT = MINUTES.toMillis(6);
|
private final static long MEEK_TIMEOUT = MINUTES.toMillis(6);
|
||||||
private final static int UNREACHABLE_BRIDGES_ALLOWED = 6;
|
private final static int UNREACHABLE_BRIDGES_ALLOWED = 6;
|
||||||
private final static int ATTEMPTS_PER_BRIDGE = 5;
|
private final static int ATTEMPTS_PER_BRIDGE = 5;
|
||||||
// Use different ports from Briar Desktop to avoid conflicts
|
|
||||||
private final static int SOCKS_PORT = DEFAULT_SOCKS_PORT + 10;
|
|
||||||
private final static int CONTROL_PORT = DEFAULT_CONTROL_PORT + 10;
|
|
||||||
|
|
||||||
private final static Logger LOG = getLogger(BridgeTest.class.getName());
|
private final static Logger LOG = getLogger(BridgeTest.class.getName());
|
||||||
|
|
||||||
@@ -115,6 +112,12 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
Clock clock;
|
Clock clock;
|
||||||
@Inject
|
@Inject
|
||||||
CryptoComponent crypto;
|
CryptoComponent crypto;
|
||||||
|
@Inject
|
||||||
|
@TorSocksPort
|
||||||
|
int torSocksPort;
|
||||||
|
@Inject
|
||||||
|
@TorControlPort
|
||||||
|
int torControlPort;
|
||||||
|
|
||||||
private final File torDir = getTestDirectory();
|
private final File torDir = getTestDirectory();
|
||||||
private final Params params;
|
private final Params params;
|
||||||
@@ -167,8 +170,8 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
factory = new UnixTorPluginFactory(ioExecutor, wakefulIoExecutor,
|
factory = new UnixTorPluginFactory(ioExecutor, wakefulIoExecutor,
|
||||||
networkManager, locationUtils, eventBus, torSocketFactory,
|
networkManager, locationUtils, eventBus, torSocketFactory,
|
||||||
backoffFactory, resourceProvider, bridgeProvider,
|
backoffFactory, resourceProvider, bridgeProvider,
|
||||||
batteryManager, clock, crypto, torDir,
|
batteryManager, clock, crypto, torDir, torSocksPort,
|
||||||
SOCKS_PORT, CONTROL_PORT);
|
torControlPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import dagger.Component;
|
|||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
BrambleCoreIntegrationTestModule.class,
|
BrambleCoreIntegrationTestModule.class,
|
||||||
BrambleCoreModule.class,
|
BrambleCoreModule.class,
|
||||||
BrambleJavaModule.class
|
BrambleJavaModule.class,
|
||||||
|
TestTorPortsModule.class
|
||||||
})
|
})
|
||||||
public interface BrambleJavaIntegrationTestComponent
|
public interface BrambleJavaIntegrationTestComponent
|
||||||
extends BrambleCoreIntegrationTestEagerSingletons {
|
extends BrambleCoreIntegrationTestEagerSingletons {
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.plugin.TorControlPort;
|
||||||
|
import org.briarproject.bramble.api.plugin.TorSocksPort;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_CONTROL_PORT;
|
||||||
|
import static org.briarproject.bramble.api.plugin.TorConstants.DEFAULT_SOCKS_PORT;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
class TestTorPortsModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@TorSocksPort
|
||||||
|
int provideTorSocksPort() {
|
||||||
|
return DEFAULT_SOCKS_PORT + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@TorControlPort
|
||||||
|
int provideTorControlPort() {
|
||||||
|
return DEFAULT_CONTROL_PORT + 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
|
apply plugin: 'checkstyle'
|
||||||
|
// Need to manually apply this as the Java plugin is not applied to this module hence this is not
|
||||||
|
// done automatically.
|
||||||
|
apply from: "${rootProject.rootDir}/gradle/checkstyle.gradle"
|
||||||
|
|
||||||
def getStdout = { command, defaultValue ->
|
def getStdout = { command, defaultValue ->
|
||||||
def stdout = new ByteArrayOutputStream()
|
def stdout = new ByteArrayOutputStream()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.briar.android.mailbox;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
@@ -23,6 +24,7 @@ import androidx.lifecycle.ViewModelProvider;
|
|||||||
|
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -215,6 +217,8 @@ public class MailboxActivity extends BriarActivity {
|
|||||||
dialog -> supportFinishAfterTransition());
|
dialog -> supportFinishAfterTransition());
|
||||||
builder.show();
|
builder.show();
|
||||||
} else {
|
} else {
|
||||||
|
Toast.makeText(this, R.string.mailbox_status_unlink_success,
|
||||||
|
LENGTH_LONG).show();
|
||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package org.briarproject.briar.android.reporting;
|
package org.briarproject.briar.android.reporting;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -10,6 +13,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
@@ -17,6 +21,9 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
|
import org.briarproject.briar.android.settings.AboutFragment;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -27,14 +34,19 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
import static android.widget.Toast.LENGTH_SHORT;
|
import static android.widget.Toast.LENGTH_SHORT;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class ReportFormFragment extends BaseFragment {
|
public class ReportFormFragment extends BaseFragment {
|
||||||
|
|
||||||
public final static String TAG = ReportFormFragment.class.getName();
|
public final static String TAG = ReportFormFragment.class.getName();
|
||||||
|
private static final Logger LOG = getLogger(TAG);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ViewModelProvider.Factory viewModelFactory;
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
@@ -43,6 +55,7 @@ public class ReportFormFragment extends BaseFragment {
|
|||||||
|
|
||||||
private EditText userCommentView;
|
private EditText userCommentView;
|
||||||
private EditText userEmailView;
|
private EditText userEmailView;
|
||||||
|
private TextView privacyPolicy;
|
||||||
private CheckBox includeDebugReport;
|
private CheckBox includeDebugReport;
|
||||||
private Button chevron;
|
private Button chevron;
|
||||||
private RecyclerView list;
|
private RecyclerView list;
|
||||||
@@ -73,6 +86,7 @@ public class ReportFormFragment extends BaseFragment {
|
|||||||
|
|
||||||
userCommentView = v.findViewById(R.id.user_comment);
|
userCommentView = v.findViewById(R.id.user_comment);
|
||||||
userEmailView = v.findViewById(R.id.user_email);
|
userEmailView = v.findViewById(R.id.user_email);
|
||||||
|
privacyPolicy = v.findViewById(R.id.PrivacyPolicy);
|
||||||
includeDebugReport = v.findViewById(R.id.include_debug_report);
|
includeDebugReport = v.findViewById(R.id.include_debug_report);
|
||||||
chevron = v.findViewById(R.id.chevron);
|
chevron = v.findViewById(R.id.chevron);
|
||||||
list = v.findViewById(R.id.list);
|
list = v.findViewById(R.id.list);
|
||||||
@@ -90,6 +104,19 @@ public class ReportFormFragment extends BaseFragment {
|
|||||||
userCommentView.setHint(R.string.describe_crash);
|
userCommentView.setHint(R.string.describe_crash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
privacyPolicy.setOnClickListener(View -> {
|
||||||
|
String url = "https://briarproject.org/privacy-policy/";
|
||||||
|
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||||
|
i.setData(Uri.parse(url));
|
||||||
|
try {
|
||||||
|
startActivity(i);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
Toast.makeText(requireContext(),
|
||||||
|
R.string.error_start_activity, LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
chevron.setOnClickListener(view -> {
|
chevron.setOnClickListener(view -> {
|
||||||
boolean show = chevron.getText().equals(getString(R.string.show));
|
boolean show = chevron.getText().equals(getString(R.string.show));
|
||||||
viewModel.showReportData(show);
|
viewModel.showReportData(show);
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public class AboutFragment extends Fragment {
|
|||||||
private TextView briarWebsite;
|
private TextView briarWebsite;
|
||||||
private TextView briarSourceCode;
|
private TextView briarSourceCode;
|
||||||
private TextView briarChangelog;
|
private TextView briarChangelog;
|
||||||
|
private TextView briarPrivacyPolicy;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
@@ -61,6 +62,8 @@ public class AboutFragment extends Fragment {
|
|||||||
briarWebsite = requireActivity().findViewById(R.id.BriarWebsite);
|
briarWebsite = requireActivity().findViewById(R.id.BriarWebsite);
|
||||||
briarSourceCode = requireActivity().findViewById(R.id.BriarSourceCode);
|
briarSourceCode = requireActivity().findViewById(R.id.BriarSourceCode);
|
||||||
briarChangelog = requireActivity().findViewById(R.id.BriarChangelog);
|
briarChangelog = requireActivity().findViewById(R.id.BriarChangelog);
|
||||||
|
briarPrivacyPolicy =
|
||||||
|
requireActivity().findViewById(R.id.BriarPrivacyPolicy);
|
||||||
briarWebsite.setOnClickListener(View -> {
|
briarWebsite.setOnClickListener(View -> {
|
||||||
String url = "https://briarproject.org/";
|
String url = "https://briarproject.org/";
|
||||||
goToUrl(url);
|
goToUrl(url);
|
||||||
@@ -74,6 +77,11 @@ public class AboutFragment extends Fragment {
|
|||||||
"https://code.briarproject.org/briar/briar/-/wikis/changelog";
|
"https://code.briarproject.org/briar/briar/-/wikis/changelog";
|
||||||
goToUrl(url);
|
goToUrl(url);
|
||||||
});
|
});
|
||||||
|
briarPrivacyPolicy.setOnClickListener(View -> {
|
||||||
|
String url =
|
||||||
|
"https://briarproject.org/privacy-policy/";
|
||||||
|
goToUrl(url);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void goToUrl(String url) {
|
private void goToUrl(String url) {
|
||||||
|
|||||||
@@ -16,48 +16,48 @@ import androidx.annotation.UiThread;
|
|||||||
|
|
||||||
public class QrCodeView extends FrameLayout {
|
public class QrCodeView extends FrameLayout {
|
||||||
|
|
||||||
private final ImageView qrCodeImageView;
|
private final ImageView qrCodeImageView;
|
||||||
private boolean fullscreen = false;
|
private boolean fullscreen = false;
|
||||||
private FullscreenListener listener;
|
private FullscreenListener listener;
|
||||||
|
|
||||||
public QrCodeView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
public QrCodeView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
LayoutInflater inflater = (LayoutInflater) context
|
LayoutInflater inflater = (LayoutInflater) context
|
||||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
inflater.inflate(R.layout.qr_code_view, this, true);
|
inflater.inflate(R.layout.qr_code_view, this, true);
|
||||||
qrCodeImageView = findViewById(R.id.qr_code);
|
qrCodeImageView = findViewById(R.id.qr_code);
|
||||||
ImageView fullscreenButton = findViewById(R.id.fullscreen_button);
|
ImageView fullscreenButton = findViewById(R.id.fullscreen_button);
|
||||||
fullscreenButton.setOnClickListener(v -> {
|
fullscreenButton.setOnClickListener(v -> {
|
||||||
fullscreen = !fullscreen;
|
fullscreen = !fullscreen;
|
||||||
if (!fullscreen) {
|
if (!fullscreen) {
|
||||||
fullscreenButton.setImageResource(
|
fullscreenButton.setImageResource(
|
||||||
R.drawable.ic_fullscreen_black_48dp);
|
R.drawable.ic_fullscreen_black_48dp);
|
||||||
} else {
|
} else {
|
||||||
fullscreenButton.setImageResource(
|
fullscreenButton.setImageResource(
|
||||||
R.drawable.ic_fullscreen_exit_black_48dp);
|
R.drawable.ic_fullscreen_exit_black_48dp);
|
||||||
}
|
}
|
||||||
if (listener != null)
|
if (listener != null)
|
||||||
listener.setFullscreen(fullscreen);
|
listener.setFullscreen(fullscreen);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public void setQrCode(Bitmap qrCode) {
|
public void setQrCode(Bitmap qrCode) {
|
||||||
qrCodeImageView.setImageBitmap(qrCode);
|
qrCodeImageView.setImageBitmap(qrCode);
|
||||||
// Simple fade-in animation
|
// Simple fade-in animation
|
||||||
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
|
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
|
||||||
anim.setDuration(200);
|
anim.setDuration(200);
|
||||||
qrCodeImageView.startAnimation(anim);
|
qrCodeImageView.startAnimation(anim);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public void setFullscreenListener(FullscreenListener listener) {
|
public void setFullscreenListener(FullscreenListener listener) {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface FullscreenListener {
|
public interface FullscreenListener {
|
||||||
void setFullscreen(boolean fullscreen);
|
void setFullscreen(boolean fullscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,15 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/BriarSourceCode" />
|
app:layout_constraintTop_toBottomOf="@+id/BriarSourceCode" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/BriarPrivacyPolicy"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/briar_privacy_policy"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/BriarChangelog" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/TranslatorThanks"
|
android:id="@+id/TranslatorThanks"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -68,6 +77,6 @@
|
|||||||
android:text="@string/translator_thanks"
|
android:text="@string/translator_thanks"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/BriarChangelog" />
|
app:layout_constraintTop_toBottomOf="@+id/BriarPrivacyPolicy" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -56,6 +56,18 @@
|
|||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/PrivacyPolicy"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/margin_large"
|
||||||
|
android:layout_marginRight="@dimen/margin_large"
|
||||||
|
android:layout_marginTop="@dimen/margin_large"
|
||||||
|
android:text="@string/privacy_policy"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/user_email_layout" />
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/include_debug_report"
|
android:id="@+id/include_debug_report"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@@ -74,9 +86,10 @@
|
|||||||
style="@style/BriarButtonFlat.Positive"
|
style="@style/BriarButtonFlat.Positive"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
android:text="@string/show"
|
android:text="@string/show"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/user_email_layout" />
|
app:layout_constraintTop_toBottomOf="@+id/PrivacyPolicy" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/list"
|
android:id="@+id/list"
|
||||||
|
|||||||
@@ -665,6 +665,7 @@
|
|||||||
<string name="mailbox_status_unlink_dialog_warning">If you unlink your Mailbox, you won\'t be able to receive messages while Briar is offline.</string>
|
<string name="mailbox_status_unlink_dialog_warning">If you unlink your Mailbox, you won\'t be able to receive messages while Briar is offline.</string>
|
||||||
<string name="mailbox_status_unlink_no_wipe_title">Your Mailbox has been unlinked</string>
|
<string name="mailbox_status_unlink_no_wipe_title">Your Mailbox has been unlinked</string>
|
||||||
<string name="mailbox_status_unlink_no_wipe_message">Next time you have access to your Mailbox device, please open the Mailbox app and tap the \"Unlink\" button to complete the process.\n\nIf you no longer have access to your Mailbox device, don\'t worry. Your data is encrypted so it will remain secure even if you don\'t complete the process.</string>
|
<string name="mailbox_status_unlink_no_wipe_message">Next time you have access to your Mailbox device, please open the Mailbox app and tap the \"Unlink\" button to complete the process.\n\nIf you no longer have access to your Mailbox device, don\'t worry. Your data is encrypted so it will remain secure even if you don\'t complete the process.</string>
|
||||||
|
<string name="mailbox_status_unlink_success">Your Mailbox has been unlinked</string>
|
||||||
|
|
||||||
<string name="mailbox_error_notification_channel_title">Briar Mailbox problem</string>
|
<string name="mailbox_error_notification_channel_title">Briar Mailbox problem</string>
|
||||||
<string name="mailbox_error_notification_title">Briar Mailbox is unavailable</string>
|
<string name="mailbox_error_notification_title">Briar Mailbox is unavailable</string>
|
||||||
@@ -699,6 +700,7 @@
|
|||||||
<string name="briar_website">\u2022 <a href="">Website</a></string>
|
<string name="briar_website">\u2022 <a href="">Website</a></string>
|
||||||
<string name="briar_source_code">\u2022 <a href="">Source code</a></string>
|
<string name="briar_source_code">\u2022 <a href="">Source code</a></string>
|
||||||
<string name="briar_changelog">\u2022 <a href="">Changelog</a></string>
|
<string name="briar_changelog">\u2022 <a href="">Changelog</a></string>
|
||||||
|
<string name="briar_privacy_policy">\u2022 <a href="">Privacy Policy</a></string>
|
||||||
<!-- Here translators can add their names or Transifex usernames(eg "Thanks to all the contributors at the Localization Lab, especially Tom, Matthew and Jerry") -->
|
<!-- Here translators can add their names or Transifex usernames(eg "Thanks to all the contributors at the Localization Lab, especially Tom, Matthew and Jerry") -->
|
||||||
<string name="translator_thanks">Thanks to all the contributors at the Localization Lab</string>
|
<string name="translator_thanks">Thanks to all the contributors at the Localization Lab</string>
|
||||||
|
|
||||||
@@ -736,6 +738,7 @@
|
|||||||
<string name="describe_crash">Describe what happened (optional)</string>
|
<string name="describe_crash">Describe what happened (optional)</string>
|
||||||
<string name="enter_feedback">Enter your feedback</string>
|
<string name="enter_feedback">Enter your feedback</string>
|
||||||
<string name="optional_contact_email">Your email address (optional)</string>
|
<string name="optional_contact_email">Your email address (optional)</string>
|
||||||
|
<string name="privacy_policy">By sending us data you agree to our <a href="">privacy policy</a></string>
|
||||||
<string name="include_debug_report_crash">Include anonymous data about the crash</string>
|
<string name="include_debug_report_crash">Include anonymous data about the crash</string>
|
||||||
<string name="include_debug_report_feedback">Include anonymous data about this device</string>
|
<string name="include_debug_report_feedback">Include anonymous data about this device</string>
|
||||||
<string name="dev_report_user_info">User information</string>
|
<string name="dev_report_user_info">User information</string>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ targetCompatibility = 1.8
|
|||||||
apply plugin: 'ru.vyarus.animalsniffer'
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
|
apply plugin: 'checkstyle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-api', configuration: 'default')
|
implementation project(path: ':bramble-api', configuration: 'default')
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ apply plugin: 'idea'
|
|||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
apply from: '../dagger.gradle'
|
apply from: '../dagger.gradle'
|
||||||
|
apply plugin: 'checkstyle'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':briar-api', configuration: 'default')
|
implementation project(path: ':briar-api', configuration: 'default')
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import org.briarproject.briar.avatar.AvatarModule;
|
|||||||
import org.briarproject.briar.blog.BlogModule;
|
import org.briarproject.briar.blog.BlogModule;
|
||||||
import org.briarproject.briar.client.BriarClientModule;
|
import org.briarproject.briar.client.BriarClientModule;
|
||||||
import org.briarproject.briar.conversation.ConversationModule;
|
import org.briarproject.briar.conversation.ConversationModule;
|
||||||
import org.briarproject.briar.feed.DnsModule;
|
|
||||||
import org.briarproject.briar.feed.FeedModule;
|
import org.briarproject.briar.feed.FeedModule;
|
||||||
import org.briarproject.briar.forum.ForumModule;
|
import org.briarproject.briar.forum.ForumModule;
|
||||||
import org.briarproject.briar.identity.IdentityModule;
|
import org.briarproject.briar.identity.IdentityModule;
|
||||||
@@ -26,7 +25,6 @@ import dagger.Module;
|
|||||||
BlogModule.class,
|
BlogModule.class,
|
||||||
BriarClientModule.class,
|
BriarClientModule.class,
|
||||||
ConversationModule.class,
|
ConversationModule.class,
|
||||||
DnsModule.class,
|
|
||||||
FeedModule.class,
|
FeedModule.class,
|
||||||
ForumModule.class,
|
ForumModule.class,
|
||||||
GroupInvitationModule.class,
|
GroupInvitationModule.class,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.BrambleCoreModule;
|
|||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
||||||
|
import org.briarproject.bramble.test.TestDnsModule;
|
||||||
import org.briarproject.bramble.test.TestSocksModule;
|
import org.briarproject.bramble.test.TestSocksModule;
|
||||||
import org.briarproject.briar.api.blog.BlogManager;
|
import org.briarproject.briar.api.blog.BlogManager;
|
||||||
import org.briarproject.briar.api.feed.FeedManager;
|
import org.briarproject.briar.api.feed.FeedManager;
|
||||||
@@ -12,7 +13,6 @@ import org.briarproject.briar.avatar.AvatarModule;
|
|||||||
import org.briarproject.briar.blog.BlogModule;
|
import org.briarproject.briar.blog.BlogModule;
|
||||||
import org.briarproject.briar.client.BriarClientModule;
|
import org.briarproject.briar.client.BriarClientModule;
|
||||||
import org.briarproject.briar.identity.IdentityModule;
|
import org.briarproject.briar.identity.IdentityModule;
|
||||||
import org.briarproject.briar.test.TestDnsModule;
|
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ import dagger.Component;
|
|||||||
FeedModule.class,
|
FeedModule.class,
|
||||||
IdentityModule.class,
|
IdentityModule.class,
|
||||||
TestDnsModule.class,
|
TestDnsModule.class,
|
||||||
TestSocksModule.class,
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
interface FeedManagerIntegrationTestComponent
|
interface FeedManagerIntegrationTestComponent
|
||||||
extends BrambleCoreIntegrationTestEagerSingletons {
|
extends BrambleCoreIntegrationTestEagerSingletons {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.briarproject.briar.introduction;
|
|||||||
|
|
||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
||||||
|
import org.briarproject.bramble.test.TestDnsModule;
|
||||||
|
import org.briarproject.bramble.test.TestSocksModule;
|
||||||
import org.briarproject.briar.attachment.AttachmentModule;
|
import org.briarproject.briar.attachment.AttachmentModule;
|
||||||
import org.briarproject.briar.autodelete.AutoDeleteModule;
|
import org.briarproject.briar.autodelete.AutoDeleteModule;
|
||||||
import org.briarproject.briar.avatar.AvatarModule;
|
import org.briarproject.briar.avatar.AvatarModule;
|
||||||
@@ -36,7 +38,9 @@ import dagger.Component;
|
|||||||
IntroductionModule.class,
|
IntroductionModule.class,
|
||||||
MessagingModule.class,
|
MessagingModule.class,
|
||||||
PrivateGroupModule.class,
|
PrivateGroupModule.class,
|
||||||
SharingModule.class
|
SharingModule.class,
|
||||||
|
TestDnsModule.class,
|
||||||
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
interface IntroductionIntegrationTestComponent
|
interface IntroductionIntegrationTestComponent
|
||||||
extends BriarIntegrationTestComponent {
|
extends BriarIntegrationTestComponent {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package org.briarproject.briar.messaging;
|
|||||||
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
|
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
|
||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
||||||
|
import org.briarproject.bramble.test.TestDnsModule;
|
||||||
|
import org.briarproject.bramble.test.TestSocksModule;
|
||||||
import org.briarproject.briar.autodelete.AutoDeleteModule;
|
import org.briarproject.briar.autodelete.AutoDeleteModule;
|
||||||
import org.briarproject.briar.avatar.AvatarModule;
|
import org.briarproject.briar.avatar.AvatarModule;
|
||||||
import org.briarproject.briar.client.BriarClientModule;
|
import org.briarproject.briar.client.BriarClientModule;
|
||||||
@@ -24,7 +26,9 @@ import dagger.Component;
|
|||||||
ConversationModule.class,
|
ConversationModule.class,
|
||||||
ForumModule.class,
|
ForumModule.class,
|
||||||
IdentityModule.class,
|
IdentityModule.class,
|
||||||
MessagingModule.class
|
MessagingModule.class,
|
||||||
|
TestDnsModule.class,
|
||||||
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
interface MessageSizeIntegrationTestComponent
|
interface MessageSizeIntegrationTestComponent
|
||||||
extends BrambleCoreIntegrationTestEagerSingletons {
|
extends BrambleCoreIntegrationTestEagerSingletons {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import org.briarproject.bramble.api.event.EventBus;
|
|||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
||||||
|
import org.briarproject.bramble.test.TestDnsModule;
|
||||||
|
import org.briarproject.bramble.test.TestSocksModule;
|
||||||
import org.briarproject.briar.api.messaging.MessagingManager;
|
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
|
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
|
||||||
import org.briarproject.briar.autodelete.AutoDeleteModule;
|
import org.briarproject.briar.autodelete.AutoDeleteModule;
|
||||||
@@ -25,7 +27,9 @@ import dagger.Component;
|
|||||||
BrambleCoreModule.class,
|
BrambleCoreModule.class,
|
||||||
BriarClientModule.class,
|
BriarClientModule.class,
|
||||||
ConversationModule.class,
|
ConversationModule.class,
|
||||||
MessagingModule.class
|
MessagingModule.class,
|
||||||
|
TestDnsModule.class,
|
||||||
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
interface SimplexMessagingIntegrationTestComponent
|
interface SimplexMessagingIntegrationTestComponent
|
||||||
extends BrambleCoreIntegrationTestEagerSingletons {
|
extends BrambleCoreIntegrationTestEagerSingletons {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
|||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
|
||||||
import org.briarproject.bramble.test.BrambleIntegrationTestComponent;
|
import org.briarproject.bramble.test.BrambleIntegrationTestComponent;
|
||||||
|
import org.briarproject.bramble.test.TestDnsModule;
|
||||||
|
import org.briarproject.bramble.test.TestSocksModule;
|
||||||
import org.briarproject.bramble.test.TimeTravel;
|
import org.briarproject.bramble.test.TimeTravel;
|
||||||
import org.briarproject.briar.api.attachment.AttachmentReader;
|
import org.briarproject.briar.api.attachment.AttachmentReader;
|
||||||
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
|
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
|
||||||
@@ -61,7 +63,9 @@ import dagger.Component;
|
|||||||
IntroductionModule.class,
|
IntroductionModule.class,
|
||||||
MessagingModule.class,
|
MessagingModule.class,
|
||||||
PrivateGroupModule.class,
|
PrivateGroupModule.class,
|
||||||
SharingModule.class
|
SharingModule.class,
|
||||||
|
TestDnsModule.class,
|
||||||
|
TestSocksModule.class
|
||||||
})
|
})
|
||||||
public interface BriarIntegrationTestComponent
|
public interface BriarIntegrationTestComponent
|
||||||
extends BrambleIntegrationTestComponent {
|
extends BrambleIntegrationTestComponent {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.briar.headless
|
|||||||
import dagger.Component
|
import dagger.Component
|
||||||
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
||||||
import org.briarproject.bramble.BrambleCoreModule
|
import org.briarproject.bramble.BrambleCoreModule
|
||||||
|
import org.briarproject.bramble.BrambleJavaModule
|
||||||
import org.briarproject.briar.BriarCoreEagerSingletons
|
import org.briarproject.briar.BriarCoreEagerSingletons
|
||||||
import org.briarproject.briar.BriarCoreModule
|
import org.briarproject.briar.BriarCoreModule
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
@@ -11,6 +12,7 @@ import javax.inject.Singleton
|
|||||||
@Component(
|
@Component(
|
||||||
modules = [
|
modules = [
|
||||||
BrambleCoreModule::class,
|
BrambleCoreModule::class,
|
||||||
|
BrambleJavaModule::class,
|
||||||
BriarCoreModule::class,
|
BriarCoreModule::class,
|
||||||
HeadlessModule::class
|
HeadlessModule::class
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -18,16 +18,12 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
|
|||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
|
||||||
import org.briarproject.bramble.battery.DefaultBatteryManagerModule
|
import org.briarproject.bramble.battery.DefaultBatteryManagerModule
|
||||||
import org.briarproject.bramble.event.DefaultEventExecutorModule
|
import org.briarproject.bramble.event.DefaultEventExecutorModule
|
||||||
import org.briarproject.bramble.network.JavaNetworkModule
|
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionModule
|
|
||||||
import org.briarproject.bramble.plugin.tor.UnixTorPluginFactory
|
import org.briarproject.bramble.plugin.tor.UnixTorPluginFactory
|
||||||
import org.briarproject.bramble.plugin.tor.WindowsTorPluginFactory
|
import org.briarproject.bramble.plugin.tor.WindowsTorPluginFactory
|
||||||
import org.briarproject.bramble.socks.SocksModule
|
|
||||||
import org.briarproject.bramble.system.ClockModule
|
import org.briarproject.bramble.system.ClockModule
|
||||||
import org.briarproject.bramble.system.DefaultTaskSchedulerModule
|
import org.briarproject.bramble.system.DefaultTaskSchedulerModule
|
||||||
import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule
|
import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule
|
||||||
import org.briarproject.bramble.system.DesktopSecureRandomModule
|
import org.briarproject.bramble.system.DesktopSecureRandomModule
|
||||||
import org.briarproject.bramble.system.JavaSystemModule
|
|
||||||
import org.briarproject.bramble.util.OsUtils.isLinux
|
import org.briarproject.bramble.util.OsUtils.isLinux
|
||||||
import org.briarproject.bramble.util.OsUtils.isMac
|
import org.briarproject.bramble.util.OsUtils.isMac
|
||||||
import org.briarproject.bramble.util.OsUtils.isWindows
|
import org.briarproject.bramble.util.OsUtils.isWindows
|
||||||
@@ -43,7 +39,6 @@ import javax.inject.Singleton
|
|||||||
@Module(
|
@Module(
|
||||||
includes = [
|
includes = [
|
||||||
AccountModule::class,
|
AccountModule::class,
|
||||||
CircumventionModule::class,
|
|
||||||
ClockModule::class,
|
ClockModule::class,
|
||||||
DefaultBatteryManagerModule::class,
|
DefaultBatteryManagerModule::class,
|
||||||
DefaultEventExecutorModule::class,
|
DefaultEventExecutorModule::class,
|
||||||
@@ -54,10 +49,7 @@ import javax.inject.Singleton
|
|||||||
HeadlessContactModule::class,
|
HeadlessContactModule::class,
|
||||||
HeadlessEventModule::class,
|
HeadlessEventModule::class,
|
||||||
HeadlessForumModule::class,
|
HeadlessForumModule::class,
|
||||||
HeadlessMessagingModule::class,
|
HeadlessMessagingModule::class
|
||||||
JavaNetworkModule::class,
|
|
||||||
JavaSystemModule::class,
|
|
||||||
SocksModule::class
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
internal class HeadlessModule(private val appDir: File) {
|
internal class HeadlessModule(private val appDir: File) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.briar.headless
|
|||||||
import dagger.Component
|
import dagger.Component
|
||||||
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
import org.briarproject.bramble.BrambleCoreEagerSingletons
|
||||||
import org.briarproject.bramble.BrambleCoreModule
|
import org.briarproject.bramble.BrambleCoreModule
|
||||||
|
import org.briarproject.bramble.BrambleJavaModule
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent
|
import org.briarproject.bramble.api.crypto.CryptoComponent
|
||||||
import org.briarproject.briar.BriarCoreEagerSingletons
|
import org.briarproject.briar.BriarCoreEagerSingletons
|
||||||
import org.briarproject.briar.BriarCoreModule
|
import org.briarproject.briar.BriarCoreModule
|
||||||
@@ -12,6 +13,7 @@ import javax.inject.Singleton
|
|||||||
@Component(
|
@Component(
|
||||||
modules = [
|
modules = [
|
||||||
BrambleCoreModule::class,
|
BrambleCoreModule::class,
|
||||||
|
BrambleJavaModule::class,
|
||||||
BriarCoreModule::class,
|
BriarCoreModule::class,
|
||||||
HeadlessTestModule::class
|
HeadlessTestModule::class
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -15,13 +15,9 @@ import org.briarproject.bramble.api.plugin.TransportId
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory
|
||||||
import org.briarproject.bramble.event.DefaultEventExecutorModule
|
import org.briarproject.bramble.event.DefaultEventExecutorModule
|
||||||
import org.briarproject.bramble.network.JavaNetworkModule
|
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionModule
|
|
||||||
import org.briarproject.bramble.socks.SocksModule
|
|
||||||
import org.briarproject.bramble.system.ClockModule
|
import org.briarproject.bramble.system.ClockModule
|
||||||
import org.briarproject.bramble.system.DefaultTaskSchedulerModule
|
import org.briarproject.bramble.system.DefaultTaskSchedulerModule
|
||||||
import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule
|
import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule
|
||||||
import org.briarproject.bramble.system.JavaSystemModule
|
|
||||||
import org.briarproject.bramble.test.TestFeatureFlagModule
|
import org.briarproject.bramble.test.TestFeatureFlagModule
|
||||||
import org.briarproject.bramble.test.TestSecureRandomModule
|
import org.briarproject.bramble.test.TestSecureRandomModule
|
||||||
import org.briarproject.briar.api.test.TestAvatarCreator
|
import org.briarproject.briar.api.test.TestAvatarCreator
|
||||||
@@ -36,15 +32,11 @@ import javax.inject.Singleton
|
|||||||
|
|
||||||
@Module(
|
@Module(
|
||||||
includes = [
|
includes = [
|
||||||
JavaNetworkModule::class,
|
|
||||||
JavaSystemModule::class,
|
|
||||||
AccountModule::class,
|
AccountModule::class,
|
||||||
CircumventionModule::class,
|
|
||||||
ClockModule::class,
|
ClockModule::class,
|
||||||
DefaultEventExecutorModule::class,
|
DefaultEventExecutorModule::class,
|
||||||
DefaultTaskSchedulerModule::class,
|
DefaultTaskSchedulerModule::class,
|
||||||
DefaultWakefulIoExecutorModule::class,
|
DefaultWakefulIoExecutorModule::class,
|
||||||
SocksModule::class,
|
|
||||||
TestFeatureFlagModule::class,
|
TestFeatureFlagModule::class,
|
||||||
TestSecureRandomModule::class,
|
TestSecureRandomModule::class,
|
||||||
HeadlessBlogModule::class,
|
HeadlessBlogModule::class,
|
||||||
|
|||||||
19
config/checkstyle/checkstyle.xml
Normal file
19
config/checkstyle/checkstyle.xml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE module PUBLIC
|
||||||
|
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||||
|
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||||
|
<module name="Checker">
|
||||||
|
<property name="tabWidth" value="4"/>
|
||||||
|
<property name="charset" value="UTF-8"/>
|
||||||
|
<module name="LineLength">
|
||||||
|
<property name="fileExtensions" value="java"/>
|
||||||
|
<property name="max" value="1000"/>
|
||||||
|
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
|
||||||
|
</module>
|
||||||
|
<module name="TreeWalker">
|
||||||
|
<module name="RegexpSinglelineJava">
|
||||||
|
<property name="format" value="^\t* +\t*\S"/>
|
||||||
|
<property name="message" value="Line has leading space characters; indentation should be performed with tabs only."/>
|
||||||
|
<property name="ignoreComments" value="true"/>
|
||||||
|
</module>
|
||||||
|
</module>
|
||||||
|
</module>
|
||||||
29
gradle/checkstyle.gradle
Normal file
29
gradle/checkstyle.gradle
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
task checkstyleMain(type: Checkstyle) {
|
||||||
|
source 'src/main/java'
|
||||||
|
include '**/*.java'
|
||||||
|
classpath = files()
|
||||||
|
reports {
|
||||||
|
xml {
|
||||||
|
destination file("build/reports/checkstyle/main.xml")
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
destination file("build/reports/checkstyle/main.html")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check.dependsOn it
|
||||||
|
}
|
||||||
|
|
||||||
|
task checkstyleTest(type: Checkstyle) {
|
||||||
|
source 'src/test/java'
|
||||||
|
include '**/*.java'
|
||||||
|
classpath = files()
|
||||||
|
reports {
|
||||||
|
xml {
|
||||||
|
destination file("build/reports/checkstyle/test.xml")
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
destination file("build/reports/checkstyle/test.html")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check.dependsOn it
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user