mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Merge branch '2229-mailbox-client' into 'master'
Add connectivity check tasks, refactor mailbox properties See merge request briar/briar!1650
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
package org.briarproject.bramble.api;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface Supplier<T> {
|
||||
|
||||
T get();
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
@Immutable
|
||||
@@ -14,13 +15,36 @@ public class MailboxProperties {
|
||||
private final MailboxAuthToken authToken;
|
||||
private final boolean owner;
|
||||
private final List<MailboxVersion> serverSupports;
|
||||
@Nullable
|
||||
private final MailboxFolderId inboxId; // Null for own mailbox
|
||||
@Nullable
|
||||
private final MailboxFolderId outboxId; // Null for own mailbox
|
||||
|
||||
/**
|
||||
* Constructor for properties used by the mailbox's owner.
|
||||
*/
|
||||
public MailboxProperties(String baseUrl, MailboxAuthToken authToken,
|
||||
boolean owner, List<MailboxVersion> serverSupports) {
|
||||
List<MailboxVersion> serverSupports) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.authToken = authToken;
|
||||
this.owner = owner;
|
||||
this.owner = true;
|
||||
this.serverSupports = serverSupports;
|
||||
this.inboxId = null;
|
||||
this.outboxId = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for properties used by a contact of the mailbox's owner.
|
||||
*/
|
||||
public MailboxProperties(String baseUrl, MailboxAuthToken authToken,
|
||||
List<MailboxVersion> serverSupports, MailboxFolderId inboxId,
|
||||
MailboxFolderId outboxId) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.authToken = authToken;
|
||||
this.owner = false;
|
||||
this.serverSupports = serverSupports;
|
||||
this.inboxId = inboxId;
|
||||
this.outboxId = outboxId;
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
@@ -43,4 +67,14 @@ public class MailboxProperties {
|
||||
public List<MailboxVersion> getServerSupports() {
|
||||
return serverSupports;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MailboxFolderId getInboxId() {
|
||||
return inboxId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MailboxFolderId getOutboxId() {
|
||||
return outboxId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,48 +9,22 @@ import javax.annotation.concurrent.Immutable;
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
public class MailboxUpdateWithMailbox extends MailboxUpdate {
|
||||
private final List<MailboxVersion> serverSupports;
|
||||
private final String onion;
|
||||
private final MailboxAuthToken authToken;
|
||||
private final MailboxFolderId inboxId;
|
||||
private final MailboxFolderId outboxId;
|
||||
|
||||
private final MailboxProperties properties;
|
||||
|
||||
public MailboxUpdateWithMailbox(List<MailboxVersion> clientSupports,
|
||||
List<MailboxVersion> serverSupports, String onion,
|
||||
MailboxAuthToken authToken, MailboxFolderId inboxId,
|
||||
MailboxFolderId outboxId
|
||||
) {
|
||||
MailboxProperties properties) {
|
||||
super(clientSupports, true);
|
||||
this.serverSupports = serverSupports;
|
||||
this.onion = onion;
|
||||
this.authToken = authToken;
|
||||
this.inboxId = inboxId;
|
||||
this.outboxId = outboxId;
|
||||
if (properties.isOwner()) throw new IllegalArgumentException();
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public MailboxUpdateWithMailbox(MailboxUpdateWithMailbox o,
|
||||
List<MailboxVersion> newClientSupports) {
|
||||
this(newClientSupports, o.serverSupports, o.onion, o.authToken,
|
||||
o.inboxId, o.outboxId);
|
||||
this(newClientSupports, o.getMailboxProperties());
|
||||
}
|
||||
|
||||
public String getOnion() {
|
||||
return onion;
|
||||
}
|
||||
|
||||
public MailboxAuthToken getAuthToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
public MailboxFolderId getInboxId() {
|
||||
return inboxId;
|
||||
}
|
||||
|
||||
public MailboxFolderId getOutboxId() {
|
||||
return outboxId;
|
||||
}
|
||||
|
||||
public List<MailboxVersion> getServerSupports() {
|
||||
return serverSupports;
|
||||
public MailboxProperties getMailboxProperties() {
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,12 @@ import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.Identity;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.bramble.api.sync.ClientId;
|
||||
@@ -223,6 +226,19 @@ public class TestUtils {
|
||||
getAgreementPublicKey(), verified);
|
||||
}
|
||||
|
||||
public static MailboxProperties getMailboxProperties(boolean owner,
|
||||
List<MailboxVersion> serverSupports) {
|
||||
String baseUrl = "http://" + getRandomString(56) + ".onion"; // TODO
|
||||
MailboxAuthToken authToken = new MailboxAuthToken(getRandomId());
|
||||
if (owner) {
|
||||
return new MailboxProperties(baseUrl, authToken, serverSupports);
|
||||
}
|
||||
MailboxFolderId inboxId = new MailboxFolderId(getRandomId());
|
||||
MailboxFolderId outboxId = new MailboxFolderId(getRandomId());
|
||||
return new MailboxProperties(baseUrl, authToken, serverSupports,
|
||||
inboxId, outboxId);
|
||||
}
|
||||
|
||||
public static void writeBytes(File file, byte[] bytes)
|
||||
throws IOException {
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
@@ -275,7 +291,7 @@ public class TestUtils {
|
||||
return Math.sqrt(getVariance(samples));
|
||||
}
|
||||
|
||||
public static boolean isOptionalTestEnabled(Class testClass) {
|
||||
public static boolean isOptionalTestEnabled(Class<?> testClass) {
|
||||
String optionalTests = System.getenv("OPTIONAL_TESTS");
|
||||
return optionalTests != null &&
|
||||
asList(optionalTests.split(",")).contains(testClass.getName());
|
||||
@@ -292,11 +308,8 @@ public class TestUtils {
|
||||
MailboxUpdateWithMailbox am = (MailboxUpdateWithMailbox) a;
|
||||
MailboxUpdateWithMailbox bm = (MailboxUpdateWithMailbox) b;
|
||||
return am.getClientSupports().equals(bm.getClientSupports()) &&
|
||||
am.getServerSupports().equals(bm.getServerSupports()) &&
|
||||
am.getOnion().equals(bm.getOnion()) &&
|
||||
am.getAuthToken().equals(bm.getAuthToken()) &&
|
||||
am.getInboxId().equals(bm.getInboxId()) &&
|
||||
am.getOutboxId().equals(bm.getOutboxId());
|
||||
mailboxPropertiesEqual(am.getMailboxProperties(),
|
||||
bm.getMailboxProperties());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||
@@ -455,9 +456,11 @@ class ClientHelperImpl implements ClientHelper {
|
||||
checkLength(inboxId, UniqueId.LENGTH);
|
||||
byte[] outboxId = properties.getRaw(PROP_KEY_OUTBOXID);
|
||||
checkLength(outboxId, UniqueId.LENGTH);
|
||||
return new MailboxUpdateWithMailbox(clientSupportsList,
|
||||
serverSupportsList, onion, new MailboxAuthToken(authToken),
|
||||
String baseUrl = "http://" + onion + ".onion"; // TODO
|
||||
MailboxProperties props = new MailboxProperties(baseUrl,
|
||||
new MailboxAuthToken(authToken), serverSupportsList,
|
||||
new MailboxFolderId(inboxId), new MailboxFolderId(outboxId));
|
||||
return new MailboxUpdateWithMailbox(clientSupportsList, props);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||
|
||||
/**
|
||||
* An interface for calling an API endpoint with the option to retry the call.
|
||||
*/
|
||||
interface ApiCall {
|
||||
|
||||
/**
|
||||
* This method makes a synchronous call to an API endpoint and returns
|
||||
* true if the call should be retried, in which case the method may be
|
||||
* called again on the same {@link ApiCall} instance after a delay.
|
||||
*
|
||||
* @return True if the API call needs to be retried, or false if the API
|
||||
* call succeeded or {@link TolerableFailureException failed tolerably}.
|
||||
*/
|
||||
@IoExecutor
|
||||
boolean callApi();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/**
|
||||
* An interface for checking whether a mailbox is reachable.
|
||||
*/
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
interface ConnectivityChecker {
|
||||
|
||||
/**
|
||||
* Destroys the checker. Any current connectivity check is cancelled.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Starts a connectivity check if needed and calls the given observer when
|
||||
* the check succeeds. If a check is already running then the observer is
|
||||
* called when the check succeeds. If a connectivity check has recently
|
||||
* succeeded then the observer is called immediately.
|
||||
*/
|
||||
void checkConnectivity(MailboxProperties properties,
|
||||
ConnectivityObserver o);
|
||||
|
||||
interface ConnectivityObserver {
|
||||
void onConnectivityCheckSucceeded();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.GuardedBy;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
abstract class ConnectivityCheckerImpl implements ConnectivityChecker {
|
||||
|
||||
/**
|
||||
* If no more than this much time has elapsed since the last connectivity
|
||||
* check succeeded, consider the result to be fresh and don't check again.
|
||||
* <p>
|
||||
* Package access for testing.
|
||||
*/
|
||||
static final long CONNECTIVITY_CHECK_FRESHNESS_MS = 10_000;
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
protected final Clock clock;
|
||||
private final MailboxApiCaller mailboxApiCaller;
|
||||
|
||||
@GuardedBy("lock")
|
||||
private boolean destroyed = false;
|
||||
|
||||
@GuardedBy("lock")
|
||||
@Nullable
|
||||
private Cancellable connectivityCheck = null;
|
||||
|
||||
@GuardedBy("lock")
|
||||
private long lastConnectivityCheckSucceeded = 0;
|
||||
|
||||
@GuardedBy("lock")
|
||||
private final List<ConnectivityObserver> connectivityObservers =
|
||||
new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates an {@link ApiCall} for checking whether the mailbox is
|
||||
* reachable. The {@link ApiCall} should call
|
||||
* {@link #onConnectivityCheckSucceeded(long)} if the check succeeds.
|
||||
*/
|
||||
abstract ApiCall createConnectivityCheckTask(MailboxProperties properties);
|
||||
|
||||
ConnectivityCheckerImpl(Clock clock, MailboxApiCaller mailboxApiCaller) {
|
||||
this.clock = clock;
|
||||
this.mailboxApiCaller = mailboxApiCaller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
synchronized (lock) {
|
||||
destroyed = true;
|
||||
connectivityObservers.clear();
|
||||
if (connectivityCheck != null) {
|
||||
connectivityCheck.cancel();
|
||||
connectivityCheck = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkConnectivity(MailboxProperties properties,
|
||||
ConnectivityObserver o) {
|
||||
boolean callNow = false;
|
||||
synchronized (lock) {
|
||||
if (destroyed) return;
|
||||
if (connectivityCheck == null) {
|
||||
// No connectivity check is running
|
||||
long now = clock.currentTimeMillis();
|
||||
if (now - lastConnectivityCheckSucceeded
|
||||
> CONNECTIVITY_CHECK_FRESHNESS_MS) {
|
||||
// The last connectivity check is stale, start a new one
|
||||
connectivityObservers.add(o);
|
||||
ApiCall task =
|
||||
createConnectivityCheckTask(properties);
|
||||
connectivityCheck = mailboxApiCaller.retryWithBackoff(task);
|
||||
} else {
|
||||
// The last connectivity check is fresh
|
||||
callNow = true;
|
||||
}
|
||||
} else {
|
||||
// A connectivity check is running, wait for it to succeed
|
||||
connectivityObservers.add(o);
|
||||
}
|
||||
}
|
||||
if (callNow) o.onConnectivityCheckSucceeded();
|
||||
}
|
||||
|
||||
protected void onConnectivityCheckSucceeded(long now) {
|
||||
List<ConnectivityObserver> observers;
|
||||
synchronized (lock) {
|
||||
if (destroyed) return;
|
||||
connectivityCheck = null;
|
||||
lastConnectivityCheckSucceeded = now;
|
||||
observers = new ArrayList<>(connectivityObservers);
|
||||
connectivityObservers.clear();
|
||||
}
|
||||
for (ConnectivityObserver o : observers) {
|
||||
o.onConnectivityCheckSucceeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class ContactMailboxConnectivityChecker extends ConnectivityCheckerImpl {
|
||||
|
||||
private final MailboxApi mailboxApi;
|
||||
|
||||
ContactMailboxConnectivityChecker(Clock clock,
|
||||
MailboxApiCaller mailboxApiCaller, MailboxApi mailboxApi) {
|
||||
super(clock, mailboxApiCaller);
|
||||
this.mailboxApi = mailboxApi;
|
||||
}
|
||||
|
||||
@Override
|
||||
ApiCall createConnectivityCheckTask(MailboxProperties properties) {
|
||||
if (properties.isOwner()) throw new IllegalArgumentException();
|
||||
return new SimpleApiCall() {
|
||||
@Override
|
||||
void tryToCallApi() throws IOException, ApiException {
|
||||
if (!mailboxApi.checkStatus(properties)) {
|
||||
throw new ApiException();
|
||||
}
|
||||
// Call the observers and cache the result
|
||||
onConnectivityCheckSucceeded(clock.currentTimeMillis());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.Supplier;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
@@ -23,15 +21,12 @@ interface MailboxApiCaller {
|
||||
long MAX_RETRY_INTERVAL_MS = DAYS.toMillis(1);
|
||||
|
||||
/**
|
||||
* Asynchronously calls the given supplier, automatically retrying at
|
||||
* increasing intervals until the supplier returns false. The returned
|
||||
* {@link Cancellable} can be used to cancel any future retries.
|
||||
* Asynchronously calls the given API call on the {@link IoExecutor},
|
||||
* automatically retrying at increasing intervals until the API call
|
||||
* returns false or retries are cancelled.
|
||||
*
|
||||
* @param supplier A wrapper for an API call. The supplier's
|
||||
* {@link Supplier#get() get()} method will be called on the
|
||||
* {@link IoExecutor}. It should return true if the API call needs to be
|
||||
* retried, or false if the API call succeeded or
|
||||
* {@link TolerableFailureException failed tolerably}.
|
||||
* @return A {@link Cancellable} that can be used to cancel any future
|
||||
* retries.
|
||||
*/
|
||||
Cancellable retryWithBackoff(Supplier<Boolean> supplier);
|
||||
Cancellable retryWithBackoff(ApiCall apiCall);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.Supplier;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||
@@ -31,15 +30,15 @@ class MailboxApiCallerImpl implements MailboxApiCaller {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cancellable retryWithBackoff(Supplier<Boolean> supplier) {
|
||||
Task task = new Task(supplier);
|
||||
public Cancellable retryWithBackoff(ApiCall apiCall) {
|
||||
Task task = new Task(apiCall);
|
||||
task.start();
|
||||
return task;
|
||||
}
|
||||
|
||||
private class Task implements Cancellable {
|
||||
|
||||
private final Supplier<Boolean> supplier;
|
||||
private final ApiCall apiCall;
|
||||
private final Object lock = new Object();
|
||||
|
||||
@GuardedBy("lock")
|
||||
@@ -52,8 +51,8 @@ class MailboxApiCallerImpl implements MailboxApiCaller {
|
||||
@GuardedBy("lock")
|
||||
private long retryIntervalMs = MIN_RETRY_INTERVAL_MS;
|
||||
|
||||
private Task(Supplier<Boolean> supplier) {
|
||||
this.supplier = supplier;
|
||||
private Task(ApiCall apiCall) {
|
||||
this.apiCall = apiCall;
|
||||
}
|
||||
|
||||
private void start() {
|
||||
@@ -68,8 +67,8 @@ class MailboxApiCallerImpl implements MailboxApiCaller {
|
||||
synchronized (lock) {
|
||||
if (cancelled) return;
|
||||
}
|
||||
// The supplier returns true if we should retry
|
||||
if (supplier.get()) {
|
||||
// The call returns true if we should retry
|
||||
if (apiCall.callApi()) {
|
||||
synchronized (lock) {
|
||||
if (cancelled) return;
|
||||
scheduledTask = taskScheduler.schedule(this::callApi,
|
||||
|
||||
@@ -95,7 +95,7 @@ class MailboxApiImpl implements MailboxApi {
|
||||
}
|
||||
return new MailboxProperties(properties.getBaseUrl(),
|
||||
MailboxAuthToken.fromString(tokenNode.textValue()),
|
||||
true, parseServerSupports(node));
|
||||
parseServerSupports(node));
|
||||
} catch (JacksonException | InvalidMailboxIdException e) {
|
||||
throw new ApiException();
|
||||
}
|
||||
@@ -127,7 +127,6 @@ class MailboxApiImpl implements MailboxApi {
|
||||
@Override
|
||||
public boolean checkStatus(MailboxProperties properties)
|
||||
throws IOException, ApiException {
|
||||
if (!properties.isOwner()) throw new IllegalArgumentException();
|
||||
Response response = sendGetRequest(properties, "/status");
|
||||
if (response.code() == 401) throw new ApiException();
|
||||
return response.isSuccessful();
|
||||
|
||||
@@ -177,11 +177,10 @@ class MailboxPairingTaskImpl implements MailboxPairingTask {
|
||||
LOG.info("QR code is valid");
|
||||
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
|
||||
String onion = crypto.encodeOnion(onionPubKey);
|
||||
String baseUrl = "http://" + onion + ".onion";
|
||||
String baseUrl = "http://" + onion + ".onion"; // TODO
|
||||
byte[] tokenBytes = Arrays.copyOfRange(bytes, 33, 65);
|
||||
MailboxAuthToken setupToken = new MailboxAuthToken(tokenBytes);
|
||||
return new MailboxProperties(baseUrl, setupToken, true,
|
||||
new ArrayList<>());
|
||||
return new MailboxProperties(baseUrl, setupToken, new ArrayList<>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
||||
|
||||
// Package access for testing
|
||||
static final String SETTINGS_NAMESPACE = "mailbox";
|
||||
// TODO: This currently stores the base URL, not the 56-char onion address
|
||||
static final String SETTINGS_KEY_ONION = "onion";
|
||||
static final String SETTINGS_KEY_TOKEN = "token";
|
||||
static final String SETTINGS_KEY_SERVER_SUPPORTS = "serverSupports";
|
||||
@@ -70,7 +71,7 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
||||
}
|
||||
try {
|
||||
MailboxAuthToken tokenId = MailboxAuthToken.fromString(token);
|
||||
return new MailboxProperties(onion, tokenId, true, serverSupports);
|
||||
return new MailboxProperties(onion, tokenId, serverSupports);
|
||||
} catch (InvalidMailboxIdException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
|
||||
@@ -242,11 +242,14 @@ class MailboxUpdateManagerImpl implements MailboxUpdateManager,
|
||||
private void createAndSendUpdateWithMailbox(Transaction txn, Contact c,
|
||||
List<MailboxVersion> serverSupports, String ownOnion)
|
||||
throws DbException {
|
||||
MailboxUpdate u = new MailboxUpdateWithMailbox(
|
||||
clientSupports, serverSupports, ownOnion,
|
||||
String baseUrl = "http://" + ownOnion + ".onion"; // TODO
|
||||
MailboxProperties properties = new MailboxProperties(baseUrl,
|
||||
new MailboxAuthToken(crypto.generateUniqueId().getBytes()),
|
||||
serverSupports,
|
||||
new MailboxFolderId(crypto.generateUniqueId().getBytes()),
|
||||
new MailboxFolderId(crypto.generateUniqueId().getBytes()));
|
||||
MailboxUpdate u =
|
||||
new MailboxUpdateWithMailbox(clientSupports, properties);
|
||||
Group g = getContactGroup(c);
|
||||
storeMessageReplaceLatest(txn, g.getId(), u);
|
||||
}
|
||||
@@ -325,11 +328,12 @@ class MailboxUpdateManagerImpl implements MailboxUpdateManager,
|
||||
BdfList serverSupports = new BdfList();
|
||||
if (u.hasMailbox()) {
|
||||
MailboxUpdateWithMailbox um = (MailboxUpdateWithMailbox) u;
|
||||
serverSupports = encodeSupportsList(um.getServerSupports());
|
||||
dict.put(PROP_KEY_ONION, um.getOnion());
|
||||
dict.put(PROP_KEY_AUTHTOKEN, um.getAuthToken().getBytes());
|
||||
dict.put(PROP_KEY_INBOXID, um.getInboxId().getBytes());
|
||||
dict.put(PROP_KEY_OUTBOXID, um.getOutboxId().getBytes());
|
||||
MailboxProperties properties = um.getMailboxProperties();
|
||||
serverSupports = encodeSupportsList(properties.getServerSupports());
|
||||
dict.put(PROP_KEY_ONION, properties.getOnion());
|
||||
dict.put(PROP_KEY_AUTHTOKEN, properties.getAuthToken());
|
||||
dict.put(PROP_KEY_INBOXID, properties.getInboxId());
|
||||
dict.put(PROP_KEY_OUTBOXID, properties.getOutboxId());
|
||||
}
|
||||
return BdfList.of(version, encodeSupportsList(u.getClientSupports()),
|
||||
serverSupports, dict);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
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.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class OwnMailboxConnectivityChecker extends ConnectivityCheckerImpl {
|
||||
|
||||
private static final Logger LOG =
|
||||
getLogger(OwnMailboxConnectivityChecker.class.getName());
|
||||
|
||||
private final MailboxApi mailboxApi;
|
||||
private final TransactionManager db;
|
||||
private final MailboxSettingsManager mailboxSettingsManager;
|
||||
|
||||
OwnMailboxConnectivityChecker(Clock clock,
|
||||
MailboxApiCaller mailboxApiCaller,
|
||||
MailboxApi mailboxApi,
|
||||
TransactionManager db,
|
||||
MailboxSettingsManager mailboxSettingsManager) {
|
||||
super(clock, mailboxApiCaller);
|
||||
this.mailboxApi = mailboxApi;
|
||||
this.db = db;
|
||||
this.mailboxSettingsManager = mailboxSettingsManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
ApiCall createConnectivityCheckTask(MailboxProperties properties) {
|
||||
if (!properties.isOwner()) throw new IllegalArgumentException();
|
||||
return () -> {
|
||||
try {
|
||||
return checkConnectivityAndStoreResult(properties);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
return true; // Retry
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean checkConnectivityAndStoreResult(
|
||||
MailboxProperties properties) throws DbException {
|
||||
try {
|
||||
if (!mailboxApi.checkStatus(properties)) throw new ApiException();
|
||||
LOG.info("Own mailbox is reachable");
|
||||
long now = clock.currentTimeMillis();
|
||||
db.transaction(false, txn -> mailboxSettingsManager
|
||||
.recordSuccessfulConnection(txn, now));
|
||||
// Call the observers and cache the result
|
||||
onConnectivityCheckSucceeded(now);
|
||||
return false; // Don't retry
|
||||
} catch (IOException | ApiException e) {
|
||||
LOG.warning("Own mailbox is unreachable");
|
||||
logException(LOG, WARNING, e);
|
||||
long now = clock.currentTimeMillis();
|
||||
db.transaction(false, txn -> mailboxSettingsManager
|
||||
.recordFailedConnectionAttempt(txn, now));
|
||||
}
|
||||
return true; // Retry
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Supplier;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||
@@ -17,17 +16,17 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
* Convenience class for making simple API calls that don't return values.
|
||||
*/
|
||||
@NotNullByDefault
|
||||
public abstract class SimpleApiCall implements Supplier<Boolean> {
|
||||
public abstract class SimpleApiCall implements ApiCall {
|
||||
|
||||
private static final Logger LOG = getLogger(SimpleApiCall.class.getName());
|
||||
|
||||
abstract void callApi()
|
||||
abstract void tryToCallApi()
|
||||
throws IOException, ApiException, TolerableFailureException;
|
||||
|
||||
@Override
|
||||
public Boolean get() {
|
||||
public boolean callApi() {
|
||||
try {
|
||||
callApi();
|
||||
tryToCallApi();
|
||||
return false; // Succeeded, don't retry
|
||||
} catch (IOException | ApiException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
|
||||
@@ -21,8 +21,7 @@ import org.briarproject.bramble.api.db.Metadata;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||
@@ -52,6 +51,7 @@ import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.PROP_KEY
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.PROP_KEY_ONION;
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxUpdateManager.PROP_KEY_OUTBOXID;
|
||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
@@ -111,22 +111,18 @@ public class ClientHelperImplTest extends BrambleMockTestCase {
|
||||
someServerSupports = BdfList.of(BdfList.of(1, 0));
|
||||
validMailboxUpdateWithMailbox = new MailboxUpdateWithMailbox(
|
||||
singletonList(new MailboxVersion(1, 0)),
|
||||
singletonList(new MailboxVersion(1, 0)),
|
||||
"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd",
|
||||
new MailboxAuthToken(getRandomId()),
|
||||
new MailboxFolderId(getRandomId()),
|
||||
new MailboxFolderId(getRandomId()));
|
||||
getMailboxProperties(false,
|
||||
singletonList(new MailboxVersion(1, 0))));
|
||||
}
|
||||
|
||||
private BdfDictionary getValidMailboxUpdateWithMailboxDict() {
|
||||
BdfDictionary dict = new BdfDictionary();
|
||||
dict.put(PROP_KEY_ONION, validMailboxUpdateWithMailbox.getOnion());
|
||||
dict.put(PROP_KEY_AUTHTOKEN, validMailboxUpdateWithMailbox
|
||||
.getAuthToken().getBytes());
|
||||
dict.put(PROP_KEY_INBOXID, validMailboxUpdateWithMailbox.getInboxId()
|
||||
.getBytes());
|
||||
dict.put(PROP_KEY_OUTBOXID, validMailboxUpdateWithMailbox.getOutboxId()
|
||||
.getBytes());
|
||||
MailboxProperties properties =
|
||||
validMailboxUpdateWithMailbox.getMailboxProperties();
|
||||
dict.put(PROP_KEY_ONION, properties.getOnion());
|
||||
dict.put(PROP_KEY_AUTHTOKEN, properties.getAuthToken());
|
||||
dict.put(PROP_KEY_INBOXID, properties.getInboxId());
|
||||
dict.put(PROP_KEY_OUTBOXID, properties.getOutboxId());
|
||||
return dict;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.mailbox.ConnectivityChecker.ConnectivityObserver;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.jmock.Expectations;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static org.briarproject.bramble.mailbox.ConnectivityCheckerImpl.CONNECTIVITY_CHECK_FRESHNESS_MS;
|
||||
import static org.briarproject.bramble.mailbox.MailboxApi.CLIENT_SUPPORTS;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
|
||||
public class ConnectivityCheckerImplTest extends BrambleMockTestCase {
|
||||
|
||||
private final Clock clock = context.mock(Clock.class);
|
||||
private final MailboxApiCaller mailboxApiCaller =
|
||||
context.mock(MailboxApiCaller.class);
|
||||
private final ApiCall apiCall = context.mock(ApiCall.class);
|
||||
private final Cancellable task = context.mock(Cancellable.class);
|
||||
private final ConnectivityObserver observer1 =
|
||||
context.mock(ConnectivityObserver.class, "1");
|
||||
private final ConnectivityObserver observer2 =
|
||||
context.mock(ConnectivityObserver.class, "2");
|
||||
|
||||
private final MailboxProperties properties =
|
||||
getMailboxProperties(true, CLIENT_SUPPORTS);
|
||||
private final long now = System.currentTimeMillis();
|
||||
|
||||
@Test
|
||||
public void testFirstObserverStartsCheck() {
|
||||
ConnectivityCheckerImpl checker = createChecker();
|
||||
|
||||
// When checkConnectivity() is called a check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(apiCall);
|
||||
will(returnValue(task));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer1);
|
||||
|
||||
// When the check succeeds the observer should be called
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(observer1).onConnectivityCheckSucceeded();
|
||||
}});
|
||||
|
||||
checker.onConnectivityCheckSucceeded(now);
|
||||
|
||||
// The observer should not be called again when subsequent checks
|
||||
// succeed
|
||||
checker.onConnectivityCheckSucceeded(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObserverIsAddedToExistingCheck() {
|
||||
ConnectivityCheckerImpl checker = createChecker();
|
||||
|
||||
// When checkConnectivity() is called a check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(apiCall);
|
||||
will(returnValue(task));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer1);
|
||||
|
||||
// When checkConnectivity() is called again before the first check
|
||||
// succeeds, the observer should be added to the existing check
|
||||
checker.checkConnectivity(properties, observer2);
|
||||
|
||||
// When the check succeeds both observers should be called
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(observer1).onConnectivityCheckSucceeded();
|
||||
oneOf(observer2).onConnectivityCheckSucceeded();
|
||||
}});
|
||||
|
||||
checker.onConnectivityCheckSucceeded(now);
|
||||
|
||||
// The observers should not be called again when subsequent checks
|
||||
// succeed
|
||||
checker.onConnectivityCheckSucceeded(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFreshResultIsReused() {
|
||||
ConnectivityCheckerImpl checker = createChecker();
|
||||
|
||||
// When checkConnectivity() is called a check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(apiCall);
|
||||
will(returnValue(task));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer1);
|
||||
|
||||
// When the check succeeds the observer should be called
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(observer1).onConnectivityCheckSucceeded();
|
||||
}});
|
||||
|
||||
checker.onConnectivityCheckSucceeded(now);
|
||||
|
||||
// When checkConnectivity() is called again within
|
||||
// CONNECTIVITY_CHECK_FRESHNESS_MS the observer should be called with
|
||||
// the result of the recent check
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now + CONNECTIVITY_CHECK_FRESHNESS_MS));
|
||||
oneOf(observer2).onConnectivityCheckSucceeded();
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStaleResultIsNotReused() {
|
||||
ConnectivityCheckerImpl checker = createChecker();
|
||||
|
||||
// When checkConnectivity() is called a check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(apiCall);
|
||||
will(returnValue(task));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer1);
|
||||
|
||||
// When the check succeeds the observer should be called
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(observer1).onConnectivityCheckSucceeded();
|
||||
}});
|
||||
|
||||
checker.onConnectivityCheckSucceeded(now);
|
||||
|
||||
// When checkConnectivity() is called again after more than
|
||||
// CONNECTIVITY_CHECK_FRESHNESS_MS another check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now + CONNECTIVITY_CHECK_FRESHNESS_MS + 1));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(apiCall);
|
||||
will(returnValue(task));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer2);
|
||||
|
||||
// When the check succeeds the observer should be called
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(observer2).onConnectivityCheckSucceeded();
|
||||
}});
|
||||
|
||||
checker.onConnectivityCheckSucceeded(
|
||||
now + CONNECTIVITY_CHECK_FRESHNESS_MS + 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckIsCancelledWhenCheckerIsDestroyed() {
|
||||
ConnectivityCheckerImpl checker = createChecker();
|
||||
|
||||
// When checkConnectivity() is called a check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(apiCall);
|
||||
will(returnValue(task));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer1);
|
||||
|
||||
// When the checker is destroyed the check should be cancelled
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(task).cancel();
|
||||
}});
|
||||
|
||||
checker.destroy();
|
||||
|
||||
// If the check runs anyway (cancellation came too late) the observer
|
||||
// should not be called
|
||||
checker.onConnectivityCheckSucceeded(now);
|
||||
}
|
||||
|
||||
private ConnectivityCheckerImpl createChecker() {
|
||||
|
||||
return new ConnectivityCheckerImpl(clock, mailboxApiCaller) {
|
||||
@Override
|
||||
@Nonnull
|
||||
protected ApiCall createConnectivityCheckTask(
|
||||
@Nonnull MailboxProperties properties) {
|
||||
return apiCall;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.mailbox.ConnectivityChecker.ConnectivityObserver;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.action.DoAllAction;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.briarproject.bramble.mailbox.MailboxApi.CLIENT_SUPPORTS;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ContactMailboxConnectivityCheckerTest extends BrambleMockTestCase {
|
||||
|
||||
private final Clock clock = context.mock(Clock.class);
|
||||
private final MailboxApiCaller mailboxApiCaller =
|
||||
context.mock(MailboxApiCaller.class);
|
||||
private final MailboxApi mailboxApi = context.mock(MailboxApi.class);
|
||||
private final Cancellable task = context.mock(Cancellable.class);
|
||||
private final ConnectivityObserver observer =
|
||||
context.mock(ConnectivityObserver.class);
|
||||
|
||||
private final MailboxProperties properties =
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
private final long now = System.currentTimeMillis();
|
||||
|
||||
@Test
|
||||
public void testObserverIsCalledWhenCheckSucceeds() throws Exception {
|
||||
ContactMailboxConnectivityChecker checker = createChecker();
|
||||
AtomicReference<ApiCall> apiCall = new AtomicReference<>(null);
|
||||
|
||||
// When checkConnectivity() is called a check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(apiCall, ApiCall.class, 0),
|
||||
returnValue(task)
|
||||
));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer);
|
||||
|
||||
// When the check succeeds the observer should be called
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApi).checkStatus(properties);
|
||||
will(returnValue(true));
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(observer).onConnectivityCheckSucceeded();
|
||||
}});
|
||||
|
||||
// The call should not be retried
|
||||
assertFalse(apiCall.get().callApi());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObserverIsNotCalledWhenCheckFails() throws Exception {
|
||||
ContactMailboxConnectivityChecker checker = createChecker();
|
||||
AtomicReference<ApiCall> apiCall = new AtomicReference<>(null);
|
||||
|
||||
// When checkConnectivity() is called a check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(apiCall, ApiCall.class, 0),
|
||||
returnValue(task)
|
||||
));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer);
|
||||
|
||||
// When the check fails, the observer should not be called
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApi).checkStatus(properties);
|
||||
will(throwException(new IOException()));
|
||||
}});
|
||||
|
||||
// The call should be retried
|
||||
assertTrue(apiCall.get().callApi());
|
||||
}
|
||||
|
||||
private ContactMailboxConnectivityChecker createChecker() {
|
||||
return new ContactMailboxConnectivityChecker(clock, mailboxApiCaller,
|
||||
mailboxApi);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.Supplier;
|
||||
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||
@@ -23,8 +22,7 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
||||
private final TaskScheduler taskScheduler =
|
||||
context.mock(TaskScheduler.class);
|
||||
private final Executor ioExecutor = context.mock(Executor.class);
|
||||
private final BooleanSupplier supplier =
|
||||
context.mock(BooleanSupplier.class);
|
||||
private final ApiCall apiCall = context.mock(ApiCall.class);
|
||||
private final Cancellable scheduledTask = context.mock(Cancellable.class);
|
||||
|
||||
private final MailboxApiCallerImpl caller =
|
||||
@@ -39,12 +37,12 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
||||
will(new CaptureArgumentAction<>(runnable, Runnable.class, 0));
|
||||
}});
|
||||
|
||||
caller.retryWithBackoff(supplier);
|
||||
caller.retryWithBackoff(apiCall);
|
||||
|
||||
// When the task runs, the supplier should be called. The supplier
|
||||
// When the task runs, the API call should be called. The call
|
||||
// returns false, so no retries should be scheduled
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(supplier).get();
|
||||
oneOf(apiCall).callApi();
|
||||
will(returnValue(false));
|
||||
}});
|
||||
|
||||
@@ -60,12 +58,12 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
||||
will(new CaptureArgumentAction<>(runnable, Runnable.class, 0));
|
||||
}});
|
||||
|
||||
Cancellable returned = caller.retryWithBackoff(supplier);
|
||||
Cancellable returned = caller.retryWithBackoff(apiCall);
|
||||
|
||||
// When the task runs, the supplier should be called. The supplier
|
||||
// When the task runs, the API call should be called. The call
|
||||
// returns true, so a retry should be scheduled
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(supplier).get();
|
||||
oneOf(apiCall).callApi();
|
||||
will(returnValue(true));
|
||||
oneOf(taskScheduler).schedule(with(any(Runnable.class)),
|
||||
with(ioExecutor), with(MIN_RETRY_INTERVAL_MS),
|
||||
@@ -90,7 +88,7 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
||||
returned.cancel();
|
||||
|
||||
// If the scheduled task runs anyway (cancellation came too late),
|
||||
// the supplier should not be called and no further tries should be
|
||||
// the API call should not be called and no further tries should be
|
||||
// scheduled
|
||||
runnable.get().run();
|
||||
}
|
||||
@@ -114,13 +112,13 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
||||
will(new CaptureArgumentAction<>(runnable, Runnable.class, 0));
|
||||
}});
|
||||
|
||||
caller.retryWithBackoff(supplier);
|
||||
caller.retryWithBackoff(apiCall);
|
||||
|
||||
// Each time the task runs, the supplier returns true, so a retry
|
||||
// Each time the task runs, the API call returns true, so a retry
|
||||
// should be scheduled with a longer interval
|
||||
for (long interval : expectedIntervals) {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(supplier).get();
|
||||
oneOf(apiCall).callApi();
|
||||
will(returnValue(true));
|
||||
oneOf(taskScheduler).schedule(with(any(Runnable.class)),
|
||||
with(ioExecutor), with(interval), with(MILLISECONDS));
|
||||
@@ -134,8 +132,4 @@ public class MailboxApiCallerImplTest extends BrambleMockTestCase {
|
||||
runnable.get().run();
|
||||
}
|
||||
}
|
||||
|
||||
// Reify the generic type to mollify jMock
|
||||
private interface BooleanSupplier extends Supplier<Boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,9 @@ import okio.Buffer;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.briarproject.bramble.mailbox.MailboxApi.CLIENT_SUPPORTS;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.mailboxPropertiesEqual;
|
||||
@@ -102,9 +104,9 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
String baseUrl = getBaseUrl(server);
|
||||
List<MailboxVersion> versions = singletonList(new MailboxVersion(1, 0));
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
MailboxProperties properties2 =
|
||||
new MailboxProperties(baseUrl, token2, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token2, new ArrayList<>());
|
||||
|
||||
RecordedRequest request;
|
||||
|
||||
@@ -199,9 +201,9 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
MailboxProperties properties2 =
|
||||
new MailboxProperties(baseUrl, token2, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token2, new ArrayList<>());
|
||||
|
||||
// valid response with valid token
|
||||
mailboxPropertiesEqual(properties2, api.setup(properties));
|
||||
@@ -282,7 +284,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
@Test
|
||||
public void testSetupOnlyForOwner() {
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties("", token, false, new ArrayList<>());
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> api.setup(properties)
|
||||
@@ -298,9 +300,9 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
MailboxProperties properties2 =
|
||||
new MailboxProperties(baseUrl, token2, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token2, new ArrayList<>());
|
||||
|
||||
assertTrue(api.checkStatus(properties));
|
||||
RecordedRequest request1 = server.takeRequest();
|
||||
@@ -318,16 +320,6 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
assertToken(request3, token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatusOnlyForOwner() {
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties("", token, false, new ArrayList<>());
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> api.checkStatus(properties)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWipe() throws Exception {
|
||||
MockWebServer server = new MockWebServer();
|
||||
@@ -338,9 +330,9 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
MailboxProperties properties2 =
|
||||
new MailboxProperties(baseUrl, token2, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token2, new ArrayList<>());
|
||||
|
||||
api.wipeMailbox(properties);
|
||||
RecordedRequest request1 = server.takeRequest();
|
||||
@@ -370,7 +362,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
@Test
|
||||
public void testWipeOnlyForOwner() {
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties("", token, false, new ArrayList<>());
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
api.wipeMailbox(properties));
|
||||
}
|
||||
@@ -384,7 +376,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
|
||||
// contact gets added as expected
|
||||
api.addContact(properties, mailboxContact);
|
||||
@@ -416,7 +408,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
@Test
|
||||
public void testAddContactOnlyForOwner() {
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties("", token, false, new ArrayList<>());
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
api.addContact(properties, mailboxContact));
|
||||
}
|
||||
@@ -431,7 +423,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
|
||||
// contact gets deleted as expected
|
||||
api.deleteContact(properties, contactId);
|
||||
@@ -468,7 +460,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
@Test
|
||||
public void testDeleteContactOnlyForOwner() {
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties("", token, false, new ArrayList<>());
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
api.deleteContact(properties, contactId));
|
||||
}
|
||||
@@ -495,7 +487,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
|
||||
// valid response with two contacts
|
||||
assertEquals(singletonList(contactId), api.getContacts(properties));
|
||||
@@ -560,7 +552,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
@Test
|
||||
public void testGetContactsOnlyForOwner() {
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties("", token, false, new ArrayList<>());
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> api.getContacts(properties)
|
||||
@@ -580,7 +572,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
|
||||
// file gets uploaded as expected
|
||||
api.addFile(properties, contactInboxId, file);
|
||||
@@ -639,7 +631,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
|
||||
// valid response with one file
|
||||
List<MailboxFile> received1 = api.getFiles(properties, contactInboxId);
|
||||
@@ -735,7 +727,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
|
||||
// file gets downloaded as expected
|
||||
api.getFile(properties, contactOutboxId, name, file1);
|
||||
@@ -779,7 +771,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
|
||||
// file gets deleted as expected
|
||||
api.deleteFile(properties, contactInboxId, name);
|
||||
@@ -843,7 +835,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
server.start();
|
||||
String baseUrl = getBaseUrl(server);
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties(baseUrl, token, true, new ArrayList<>());
|
||||
new MailboxProperties(baseUrl, token, new ArrayList<>());
|
||||
|
||||
// valid response with one folders
|
||||
assertEquals(singletonList(id1), api.getFolders(properties));
|
||||
@@ -912,7 +904,7 @@ public class MailboxApiTest extends BrambleTestCase {
|
||||
@Test
|
||||
public void testGetFoldersOnlyForOwner() {
|
||||
MailboxProperties properties =
|
||||
new MailboxProperties("", token, false, new ArrayList<>());
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
api.getFolders(properties));
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public class MailboxIntegrationTest extends BrambleTestCase {
|
||||
|
||||
if (ownerProperties != null) return;
|
||||
MailboxProperties setupProperties = new MailboxProperties(
|
||||
URL_BASE, SETUP_TOKEN, true, new ArrayList<>());
|
||||
URL_BASE, SETUP_TOKEN, new ArrayList<>());
|
||||
ownerProperties = api.setup(setupProperties);
|
||||
}
|
||||
|
||||
@@ -108,13 +108,29 @@ public class MailboxIntegrationTest extends BrambleTestCase {
|
||||
|
||||
// new setup doesn't work as mailbox is stopping
|
||||
MailboxProperties setupProperties = new MailboxProperties(
|
||||
URL_BASE, SETUP_TOKEN, true, new ArrayList<>());
|
||||
URL_BASE, SETUP_TOKEN, new ArrayList<>());
|
||||
assertThrows(ApiException.class, () -> api.setup(setupProperties));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatus() throws Exception {
|
||||
// Owner calls status endpoint
|
||||
assertTrue(api.checkStatus(ownerProperties));
|
||||
|
||||
// Owner adds contact
|
||||
ContactId contactId = new ContactId(1);
|
||||
MailboxContact contact = getMailboxContact(contactId);
|
||||
MailboxProperties contactProperties = new MailboxProperties(
|
||||
ownerProperties.getBaseUrl(), contact.token,
|
||||
new ArrayList<>(), contact.inboxId, contact.outboxId);
|
||||
api.addContact(ownerProperties, contact);
|
||||
|
||||
// Contact calls status endpoint
|
||||
assertTrue(api.checkStatus(contactProperties));
|
||||
|
||||
// Owner deletes contact again to leave clean state for other tests
|
||||
api.deleteContact(ownerProperties, contactId);
|
||||
assertEquals(emptyList(), api.getContacts(ownerProperties));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -151,8 +167,8 @@ public class MailboxIntegrationTest extends BrambleTestCase {
|
||||
ContactId contactId = new ContactId(1);
|
||||
MailboxContact contact = getMailboxContact(contactId);
|
||||
MailboxProperties contactProperties = new MailboxProperties(
|
||||
ownerProperties.getBaseUrl(), contact.token, false,
|
||||
new ArrayList<>());
|
||||
ownerProperties.getBaseUrl(), contact.token,
|
||||
new ArrayList<>(), contact.inboxId, contact.outboxId);
|
||||
api.addContact(ownerProperties, contact);
|
||||
|
||||
// upload a file for our contact
|
||||
|
||||
@@ -57,7 +57,7 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
||||
|
||||
private final String onion = getRandomString(56);
|
||||
private final byte[] onionBytes = getRandomBytes(32);
|
||||
private final String onionAddress = "http://" + onion + ".onion";
|
||||
private final String baseUrl = "http://" + onion + ".onion"; // TODO
|
||||
private final MailboxAuthToken setupToken =
|
||||
new MailboxAuthToken(getRandomId());
|
||||
private final MailboxAuthToken ownerToken =
|
||||
@@ -65,9 +65,9 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
||||
private final String validPayload = getValidPayload();
|
||||
private final long time = System.currentTimeMillis();
|
||||
private final MailboxProperties setupProperties = new MailboxProperties(
|
||||
onionAddress, setupToken, true, new ArrayList<>());
|
||||
baseUrl, setupToken, new ArrayList<>());
|
||||
private final MailboxProperties ownerProperties = new MailboxProperties(
|
||||
onionAddress, ownerToken, true, new ArrayList<>());
|
||||
baseUrl, ownerToken, new ArrayList<>());
|
||||
|
||||
@Test
|
||||
public void testInitialQrCodeReceivedState() {
|
||||
|
||||
@@ -97,7 +97,7 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
||||
expectedSettings.put(SETTINGS_KEY_TOKEN, token.toString());
|
||||
expectedSettings.putIntArray(SETTINGS_KEY_SERVER_SUPPORTS,
|
||||
serverSupportsInts);
|
||||
MailboxProperties properties = new MailboxProperties(onion, token, true,
|
||||
MailboxProperties properties = new MailboxProperties(onion, token,
|
||||
serverSupports);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
|
||||
@@ -11,8 +11,6 @@ import org.briarproject.bramble.api.data.MetadataParser;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.Metadata;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||
@@ -48,6 +46,7 @@ import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||
import static org.briarproject.bramble.api.sync.validation.IncomingMessageHook.DeliveryAction.ACCEPT_DO_NOT_SHARE;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContact;
|
||||
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.hasEvent;
|
||||
@@ -82,6 +81,7 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
||||
private final List<MailboxVersion> someServerSupportsList;
|
||||
private final BdfList someServerSupports;
|
||||
private final BdfList emptyServerSupports = new BdfList();
|
||||
private final MailboxProperties updateProps;
|
||||
private final MailboxUpdateWithMailbox updateWithMailbox;
|
||||
private final MailboxUpdate updateNoMailbox;
|
||||
private final MailboxProperties ownProps;
|
||||
@@ -108,22 +108,16 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
updateNoMailbox = new MailboxUpdate(someClientSupportsList);
|
||||
|
||||
ownProps = new MailboxProperties("http://bar.onion",
|
||||
new MailboxAuthToken(getRandomId()), true,
|
||||
someServerSupportsList);
|
||||
updateProps = getMailboxProperties(false, someServerSupportsList);
|
||||
ownProps = new MailboxProperties(updateProps.getBaseUrl(),
|
||||
updateProps.getAuthToken(), someServerSupportsList);
|
||||
updateWithMailbox = new MailboxUpdateWithMailbox(someClientSupportsList,
|
||||
someServerSupportsList, ownProps.getOnion(),
|
||||
new MailboxAuthToken(getRandomId()),
|
||||
new MailboxFolderId(getRandomId()),
|
||||
new MailboxFolderId(getRandomId()));
|
||||
updateProps);
|
||||
propsDict = new BdfDictionary();
|
||||
propsDict.put(PROP_KEY_ONION, updateWithMailbox.getOnion());
|
||||
propsDict.put(PROP_KEY_AUTHTOKEN, updateWithMailbox.getAuthToken()
|
||||
.getBytes());
|
||||
propsDict.put(PROP_KEY_INBOXID, updateWithMailbox.getInboxId()
|
||||
.getBytes());
|
||||
propsDict.put(PROP_KEY_OUTBOXID, updateWithMailbox.getOutboxId()
|
||||
.getBytes());
|
||||
propsDict.put(PROP_KEY_ONION, updateProps.getOnion());
|
||||
propsDict.put(PROP_KEY_AUTHTOKEN, updateProps.getAuthToken());
|
||||
propsDict.put(PROP_KEY_INBOXID, updateProps.getInboxId());
|
||||
propsDict.put(PROP_KEY_OUTBOXID, updateProps.getOutboxId());
|
||||
}
|
||||
|
||||
private MailboxUpdateManagerImpl createInstance(
|
||||
@@ -219,11 +213,11 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn);
|
||||
will(returnValue(ownProps));
|
||||
oneOf(crypto).generateUniqueId();
|
||||
will(returnValue(updateWithMailbox.getAuthToken()));
|
||||
will(returnValue(updateProps.getAuthToken()));
|
||||
oneOf(crypto).generateUniqueId();
|
||||
will(returnValue(updateWithMailbox.getInboxId()));
|
||||
will(returnValue(updateProps.getInboxId()));
|
||||
oneOf(crypto).generateUniqueId();
|
||||
will(returnValue(updateWithMailbox.getOutboxId()));
|
||||
will(returnValue(updateProps.getOutboxId()));
|
||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||
MAJOR_VERSION, contact);
|
||||
will(returnValue(contactGroup));
|
||||
@@ -478,11 +472,11 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn);
|
||||
will(returnValue(ownProps));
|
||||
oneOf(crypto).generateUniqueId();
|
||||
will(returnValue(updateWithMailbox.getAuthToken()));
|
||||
will(returnValue(updateProps.getAuthToken()));
|
||||
oneOf(crypto).generateUniqueId();
|
||||
will(returnValue(updateWithMailbox.getInboxId()));
|
||||
will(returnValue(updateProps.getInboxId()));
|
||||
oneOf(crypto).generateUniqueId();
|
||||
will(returnValue(updateWithMailbox.getOutboxId()));
|
||||
will(returnValue(updateProps.getOutboxId()));
|
||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||
MAJOR_VERSION, contact);
|
||||
will(returnValue(contactGroup));
|
||||
@@ -668,11 +662,11 @@ public class MailboxUpdateManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(db).getContacts(txn);
|
||||
will(returnValue(contacts));
|
||||
oneOf(crypto).generateUniqueId();
|
||||
will(returnValue(updateWithMailbox.getAuthToken()));
|
||||
will(returnValue(updateProps.getAuthToken()));
|
||||
oneOf(crypto).generateUniqueId();
|
||||
will(returnValue(updateWithMailbox.getInboxId()));
|
||||
will(returnValue(updateProps.getInboxId()));
|
||||
oneOf(crypto).generateUniqueId();
|
||||
will(returnValue(updateWithMailbox.getOutboxId()));
|
||||
will(returnValue(updateProps.getOutboxId()));
|
||||
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
|
||||
MAJOR_VERSION, contact);
|
||||
will(returnValue(contactGroup));
|
||||
|
||||
@@ -6,8 +6,7 @@ import org.briarproject.bramble.api.data.BdfDictionary;
|
||||
import org.briarproject.bramble.api.data.BdfEntry;
|
||||
import org.briarproject.bramble.api.data.BdfList;
|
||||
import org.briarproject.bramble.api.data.MetadataEncoder;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
||||
@@ -24,8 +23,8 @@ import java.util.List;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class MailboxUpdateValidatorTest extends BrambleMockTestCase {
|
||||
@@ -35,7 +34,6 @@ public class MailboxUpdateValidatorTest extends BrambleMockTestCase {
|
||||
private final BdfDictionary bdfDict;
|
||||
private final BdfList emptyServerSupports;
|
||||
private final BdfList someClientSupports;
|
||||
private final List<MailboxVersion> someClientSupportsList;
|
||||
private final BdfList someServerSupports;
|
||||
private final MailboxUpdateWithMailbox updateMailbox;
|
||||
private final MailboxUpdate updateNoMailbox;
|
||||
@@ -49,17 +47,15 @@ public class MailboxUpdateValidatorTest extends BrambleMockTestCase {
|
||||
// {@link ClientHelper#parseAndValidateMailboxUpdate(BdfList, BdfList, BdfDictionary)}
|
||||
emptyServerSupports = new BdfList();
|
||||
someClientSupports = BdfList.of(BdfList.of(1, 0));
|
||||
someClientSupportsList = singletonList(new MailboxVersion(1, 0));
|
||||
List<MailboxVersion> someClientSupportsList =
|
||||
singletonList(new MailboxVersion(1, 0));
|
||||
someServerSupports = BdfList.of(BdfList.of(1, 0));
|
||||
bdfDict = BdfDictionary.of(new BdfEntry("foo", "bar"));
|
||||
|
||||
MailboxProperties props = getMailboxProperties(false,
|
||||
singletonList(new MailboxVersion(1, 0)));
|
||||
updateMailbox = new MailboxUpdateWithMailbox(
|
||||
singletonList(new MailboxVersion(1, 0)),
|
||||
singletonList(new MailboxVersion(1, 0)),
|
||||
"baz",
|
||||
new MailboxAuthToken(getRandomId()),
|
||||
new MailboxFolderId(getRandomId()),
|
||||
new MailboxFolderId(getRandomId()));
|
||||
singletonList(new MailboxVersion(1, 0)), props);
|
||||
updateNoMailbox = new MailboxUpdate(someClientSupportsList);
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
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.system.Clock;
|
||||
import org.briarproject.bramble.mailbox.ConnectivityChecker.ConnectivityObserver;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.action.DoAllAction;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.briarproject.bramble.mailbox.MailboxApi.CLIENT_SUPPORTS;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class OwnMailboxConnectivityCheckerTest extends BrambleMockTestCase {
|
||||
|
||||
private final Clock clock = context.mock(Clock.class);
|
||||
private final MailboxApiCaller mailboxApiCaller =
|
||||
context.mock(MailboxApiCaller.class);
|
||||
private final MailboxApi mailboxApi = context.mock(MailboxApi.class);
|
||||
private final TransactionManager db =
|
||||
context.mock(TransactionManager.class);
|
||||
private final MailboxSettingsManager mailboxSettingsManager =
|
||||
context.mock(MailboxSettingsManager.class);
|
||||
private final Cancellable task = context.mock(Cancellable.class);
|
||||
private final ConnectivityObserver observer =
|
||||
context.mock(ConnectivityObserver.class);
|
||||
|
||||
private final MailboxProperties properties =
|
||||
getMailboxProperties(true, CLIENT_SUPPORTS);
|
||||
private final long now = System.currentTimeMillis();
|
||||
|
||||
@Test
|
||||
public void testObserverIsCalledWhenCheckSucceeds() throws Exception {
|
||||
OwnMailboxConnectivityChecker checker = createChecker();
|
||||
AtomicReference<ApiCall> apiCall = new AtomicReference<>(null);
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
// When checkConnectivity() is called a check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(apiCall, ApiCall.class, 0),
|
||||
returnValue(task)
|
||||
));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer);
|
||||
|
||||
// When the check succeeds, the success should be recorded in the DB
|
||||
// and the observer should be called
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(mailboxApi).checkStatus(properties);
|
||||
will(returnValue(true));
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(mailboxSettingsManager).recordSuccessfulConnection(txn, now);
|
||||
oneOf(observer).onConnectivityCheckSucceeded();
|
||||
}});
|
||||
|
||||
// The call should not be retried
|
||||
assertFalse(apiCall.get().callApi());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObserverIsNotCalledWhenCheckFails() throws Exception {
|
||||
OwnMailboxConnectivityChecker checker = createChecker();
|
||||
AtomicReference<ApiCall> apiCall = new AtomicReference<>(null);
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
// When checkConnectivity() is called a check should be started
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(apiCall, ApiCall.class, 0),
|
||||
returnValue(task)
|
||||
));
|
||||
}});
|
||||
|
||||
checker.checkConnectivity(properties, observer);
|
||||
|
||||
// When the check fails, the failure should be recorded in the DB and
|
||||
// the observer should not be called
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(mailboxApi).checkStatus(properties);
|
||||
will(throwException(new IOException()));
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(mailboxSettingsManager)
|
||||
.recordFailedConnectionAttempt(txn, now);
|
||||
}});
|
||||
|
||||
// The call should be retried
|
||||
assertTrue(apiCall.get().callApi());
|
||||
}
|
||||
|
||||
private OwnMailboxConnectivityChecker createChecker() {
|
||||
return new OwnMailboxConnectivityChecker(clock, mailboxApiCaller,
|
||||
mailboxApi, db, mailboxSettingsManager);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user