mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 13:19:52 +01:00
Compare commits
16 Commits
release-1.
...
screenshot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d5f5d4419 | ||
|
|
8393513871 | ||
|
|
38270fbee8 | ||
|
|
65c0646812 | ||
|
|
0416583e8c | ||
|
|
91f8c801b8 | ||
|
|
a045d7d306 | ||
|
|
a29d5efd93 | ||
|
|
37cd1cdddf | ||
|
|
4f495bb4d3 | ||
|
|
1a70200b65 | ||
|
|
6925dfcbdd | ||
|
|
817df9c75a | ||
|
|
745515457e | ||
|
|
ba5928218a | ||
|
|
74e4a9cbdf |
@@ -16,7 +16,6 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -49,14 +48,13 @@ public abstract class BdfMessageValidator implements MessageValidator {
|
|||||||
throw new InvalidMessageException(
|
throw new InvalidMessageException(
|
||||||
"Timestamp is too far in the future");
|
"Timestamp is too far in the future");
|
||||||
}
|
}
|
||||||
byte[] raw = m.getRaw();
|
byte[] body = m.getBody();
|
||||||
if (raw.length <= MESSAGE_HEADER_LENGTH) {
|
if (body.length == 0) {
|
||||||
throw new InvalidMessageException("Message is too short");
|
throw new InvalidMessageException("Message is too short");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
BdfList body = clientHelper.toList(raw, MESSAGE_HEADER_LENGTH,
|
BdfList bodyList = clientHelper.toList(body);
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
BdfMessageContext result = validateMessage(m, g, bodyList);
|
||||||
BdfMessageContext result = validateMessage(m, g, body);
|
|
||||||
Metadata meta = metadataEncoder.encode(result.getDictionary());
|
Metadata meta = metadataEncoder.encode(result.getDictionary());
|
||||||
return new MessageContext(meta, result.getDependencies());
|
return new MessageContext(meta, result.getDependencies());
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.briarproject.bramble.api.sync;
|
package org.briarproject.bramble.api.sync;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
|
|
||||||
public class Message {
|
public class Message {
|
||||||
@@ -13,17 +13,15 @@ public class Message {
|
|||||||
private final MessageId id;
|
private final MessageId id;
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final byte[] raw;
|
private final byte[] body;
|
||||||
|
|
||||||
public Message(MessageId id, GroupId groupId, long timestamp, byte[] raw) {
|
public Message(MessageId id, GroupId groupId, long timestamp, byte[] body) {
|
||||||
if (raw.length <= MESSAGE_HEADER_LENGTH)
|
if (body.length > MAX_MESSAGE_BODY_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
|
||||||
if (raw.length > MAX_MESSAGE_LENGTH)
|
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.raw = raw;
|
this.body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,14 +49,14 @@ public class Message {
|
|||||||
* Returns the length of the raw message in bytes.
|
* Returns the length of the raw message in bytes.
|
||||||
*/
|
*/
|
||||||
public int getRawLength() {
|
public int getRawLength() {
|
||||||
return raw.length;
|
return MESSAGE_HEADER_LENGTH + body.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the raw message.
|
* Returns the message body.
|
||||||
*/
|
*/
|
||||||
public byte[] getRaw() {
|
public byte[] getBody() {
|
||||||
return raw;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ public interface MessageFactory {
|
|||||||
|
|
||||||
Message createMessage(byte[] raw);
|
Message createMessage(byte[] raw);
|
||||||
|
|
||||||
Message createMessage(MessageId m, byte[] raw);
|
byte[] getRawMessage(Message m);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
|
public class ArrayClock implements Clock {
|
||||||
|
|
||||||
|
private final long[] times;
|
||||||
|
private int index = 0;
|
||||||
|
|
||||||
|
public ArrayClock(long... times) {
|
||||||
|
this.times = times;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long currentTimeMillis() {
|
||||||
|
return times[index++];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sleep(long milliseconds) throws InterruptedException {
|
||||||
|
Thread.sleep(milliseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,7 +33,6 @@ import static org.briarproject.bramble.api.properties.TransportPropertyConstants
|
|||||||
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
|
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
|
|
||||||
public class TestUtils {
|
public class TestUtils {
|
||||||
@@ -132,13 +131,13 @@ public class TestUtils {
|
|||||||
|
|
||||||
public static Message getMessage(GroupId groupId) {
|
public static Message getMessage(GroupId groupId) {
|
||||||
int bodyLength = 1 + random.nextInt(MAX_MESSAGE_BODY_LENGTH);
|
int bodyLength = 1 + random.nextInt(MAX_MESSAGE_BODY_LENGTH);
|
||||||
return getMessage(groupId, MESSAGE_HEADER_LENGTH + bodyLength);
|
return getMessage(groupId, bodyLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message getMessage(GroupId groupId, int rawLength) {
|
public static Message getMessage(GroupId groupId, int bodyLength) {
|
||||||
MessageId id = new MessageId(getRandomId());
|
MessageId id = new MessageId(getRandomId());
|
||||||
byte[] raw = getRandomBytes(rawLength);
|
byte[] body = getRandomBytes(bodyLength);
|
||||||
return new Message(id, groupId, timestamp, raw);
|
return new Message(id, groupId, timestamp, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double getMedian(Collection<? extends Number> samples) {
|
public static double getMedian(Collection<? extends Number> samples) {
|
||||||
|
|||||||
@@ -159,7 +159,8 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
@Override
|
@Override
|
||||||
public boolean createAccount(String name, String password) {
|
public boolean createAccount(String name, String password) {
|
||||||
synchronized (stateChangeLock) {
|
synchronized (stateChangeLock) {
|
||||||
// TODO don't allow creating another account if one already exists
|
if (hasDatabaseKey())
|
||||||
|
throw new AssertionError("Already have a database key");
|
||||||
LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
|
LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
|
||||||
identityManager.registerLocalAuthor(localAuthor);
|
identityManager.registerLocalAuthor(localAuthor);
|
||||||
SecretKey key = crypto.generateSecretKey();
|
SecretKey key = crypto.generateSecretKey();
|
||||||
@@ -182,6 +183,7 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
LOG.info("Deleting account");
|
LOG.info("Deleting account");
|
||||||
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
|
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
|
||||||
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
|
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
|
||||||
|
databaseKey = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_N
|
|||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
||||||
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
||||||
|
|
||||||
@@ -147,9 +146,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public BdfList getMessageAsList(Transaction txn, MessageId m)
|
public BdfList getMessageAsList(Transaction txn, MessageId m)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
byte[] raw = db.getMessage(txn, m).getRaw();
|
return toList(db.getMessage(txn, m).getBody());
|
||||||
return toList(raw, MESSAGE_HEADER_LENGTH,
|
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -361,9 +358,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfList toList(Message m) throws FormatException {
|
public BdfList toList(Message m) throws FormatException {
|
||||||
byte[] raw = m.getRaw();
|
return toList(m.getBody());
|
||||||
return toList(raw, MESSAGE_HEADER_LENGTH,
|
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ interface Database<T> {
|
|||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToOffer(T txn, ContactId c,
|
Collection<MessageId> getMessagesToOffer(T txn, ContactId c,
|
||||||
int maxMessages) throws DbException;
|
int maxMessages, int maxLatency) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of some messages that are eligible to be requested from
|
* Returns the IDs of some messages that are eligible to be requested from
|
||||||
@@ -438,8 +438,8 @@ interface Database<T> {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength)
|
Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength,
|
||||||
throws DbException;
|
int maxLatency) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that need to be validated.
|
* Returns the IDs of any messages that need to be validated.
|
||||||
@@ -482,7 +482,7 @@ interface Database<T> {
|
|||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getRequestedMessagesToSend(T txn, ContactId c,
|
Collection<MessageId> getRequestedMessagesToSend(T txn, ContactId c,
|
||||||
int maxLength) throws DbException;
|
int maxLength, int maxLatency) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all settings in the given namespace.
|
* Returns all settings in the given namespace.
|
||||||
@@ -647,11 +647,11 @@ interface Database<T> {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the transmission count and expiry time of the given message
|
* Updates the transmission count, expiry time and estimated time of arrival
|
||||||
* with respect to the given contact, using the latency of the transport
|
* of the given message with respect to the given contact, using the latency
|
||||||
* over which it was sent.
|
* of the transport over which it was sent.
|
||||||
*/
|
*/
|
||||||
void updateExpiryTime(T txn, ContactId c, MessageId m, int maxLatency)
|
void updateExpiryTimeAndEta(T txn, ContactId c, MessageId m, int maxLatency)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -313,11 +313,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, c, maxLength);
|
Collection<MessageId> ids =
|
||||||
|
db.getMessagesToSend(txn, c, maxLength, maxLatency);
|
||||||
List<Message> messages = new ArrayList<>(ids.size());
|
List<Message> messages = new ArrayList<>(ids.size());
|
||||||
for (MessageId m : ids) {
|
for (MessageId m : ids) {
|
||||||
messages.add(db.getMessage(txn, m));
|
messages.add(db.getMessage(txn, m));
|
||||||
db.updateExpiryTime(txn, c, m, maxLatency);
|
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
|
||||||
}
|
}
|
||||||
if (ids.isEmpty()) return null;
|
if (ids.isEmpty()) return null;
|
||||||
db.lowerRequestedFlag(txn, c, ids);
|
db.lowerRequestedFlag(txn, c, ids);
|
||||||
@@ -333,9 +334,11 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
Collection<MessageId> ids = db.getMessagesToOffer(txn, c, maxMessages);
|
Collection<MessageId> ids =
|
||||||
|
db.getMessagesToOffer(txn, c, maxMessages, maxLatency);
|
||||||
if (ids.isEmpty()) return null;
|
if (ids.isEmpty()) return null;
|
||||||
for (MessageId m : ids) db.updateExpiryTime(txn, c, m, maxLatency);
|
for (MessageId m : ids)
|
||||||
|
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
|
||||||
return new Offer(ids);
|
return new Offer(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,12 +365,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
Collection<MessageId> ids = db.getRequestedMessagesToSend(txn, c,
|
Collection<MessageId> ids =
|
||||||
maxLength);
|
db.getRequestedMessagesToSend(txn, c, maxLength, maxLatency);
|
||||||
List<Message> messages = new ArrayList<>(ids.size());
|
List<Message> messages = new ArrayList<>(ids.size());
|
||||||
for (MessageId m : ids) {
|
for (MessageId m : ids) {
|
||||||
messages.add(db.getMessage(txn, m));
|
messages.add(db.getMessage(txn, m));
|
||||||
db.updateExpiryTime(txn, c, m, maxLatency);
|
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
|
||||||
}
|
}
|
||||||
if (ids.isEmpty()) return null;
|
if (ids.isEmpty()) return null;
|
||||||
db.lowerRequestedFlag(txn, c, ids);
|
db.lowerRequestedFlag(txn, c, ids);
|
||||||
@@ -855,7 +858,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
if (!db.containsMessage(txn, m))
|
if (!db.containsMessage(txn, m))
|
||||||
throw new NoSuchMessageException();
|
throw new NoSuchMessageException();
|
||||||
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);
|
db.setMessageShared(txn, m);
|
||||||
transaction.attach(new MessageSharedEvent(m));
|
transaction.attach(new MessageSharedEvent(m));
|
||||||
}
|
}
|
||||||
@@ -881,7 +885,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
throw new NoSuchMessageException();
|
throw new NoSuchMessageException();
|
||||||
State dependentState = db.getMessageState(txn, dependent.getId());
|
State dependentState = db.getMessageState(txn, dependent.getId());
|
||||||
for (MessageId dependency : dependencies) {
|
for (MessageId dependency : dependencies) {
|
||||||
db.addMessageDependency(txn, dependent, dependency, dependentState);
|
db.addMessageDependency(txn, dependent, dependency,
|
||||||
|
dependentState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,7 +918,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
for (KeySet ks : keys) {
|
for (KeySet ks : keys) {
|
||||||
TransportId t = ks.getTransportKeys().getTransportId();
|
TransportId t = ks.getTransportKeys().getTransportId();
|
||||||
if (db.containsTransport(txn, t)) db.updateTransportKeys(txn, ks);
|
if (db.containsTransport(txn, t))
|
||||||
|
db.updateTransportKeys(txn, ks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@@ -18,8 +19,9 @@ public class DatabaseModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
Database<Connection> provideDatabase(DatabaseConfig config, Clock clock) {
|
Database<Connection> provideDatabase(DatabaseConfig config,
|
||||||
return new H2Database(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new H2Database(config, messageFactory, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
import org.briarproject.bramble.api.db.MigrationListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
@@ -36,9 +37,10 @@ class H2Database extends JdbcDatabase {
|
|||||||
private volatile SecretKey key = null;
|
private volatile SecretKey key = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
H2Database(DatabaseConfig config, Clock clock) {
|
H2Database(DatabaseConfig config, MessageFactory messageFactory,
|
||||||
|
Clock clock) {
|
||||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||||
clock);
|
messageFactory, clock);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
File dir = config.getDatabaseDirectory();
|
File dir = config.getDatabaseDirectory();
|
||||||
String path = new File(dir, "db").getAbsolutePath();
|
String path = new File(dir, "db").getAbsolutePath();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
import org.briarproject.bramble.api.db.MigrationListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
@@ -37,9 +38,10 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
private volatile SecretKey key = null;
|
private volatile SecretKey key = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
HyperSqlDatabase(DatabaseConfig config, Clock clock) {
|
HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory,
|
||||||
|
Clock clock) {
|
||||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||||
clock);
|
messageFactory, clock);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
File dir = config.getDatabaseDirectory();
|
File dir = config.getDatabaseDirectory();
|
||||||
String path = new File(dir, "db").getAbsolutePath();
|
String path = new File(dir, "db").getAbsolutePath();
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.briarproject.bramble.api.sync.Group;
|
|||||||
import org.briarproject.bramble.api.sync.Group.Visibility;
|
import org.briarproject.bramble.api.sync.Group.Visibility;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||||
@@ -37,6 +38,7 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -54,13 +56,13 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.sql.Types.INTEGER;
|
import static java.sql.Types.INTEGER;
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
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;
|
||||||
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
|
||||||
|
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
||||||
@@ -77,7 +79,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
|||||||
abstract class JdbcDatabase implements Database<Connection> {
|
abstract class JdbcDatabase implements Database<Connection> {
|
||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
static final int CODE_SCHEMA_VERSION = 39;
|
static final int CODE_SCHEMA_VERSION = 40;
|
||||||
|
|
||||||
// Rotation period offsets for incoming transport keys
|
// Rotation period offsets for incoming transport keys
|
||||||
private static final int OFFSET_PREV = -1;
|
private static final int OFFSET_PREV = -1;
|
||||||
@@ -217,6 +219,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " requested BOOLEAN NOT NULL,"
|
+ " requested BOOLEAN NOT NULL,"
|
||||||
+ " expiry BIGINT NOT NULL,"
|
+ " expiry BIGINT NOT NULL,"
|
||||||
+ " txCount INT NOT NULL,"
|
+ " txCount INT NOT NULL,"
|
||||||
|
+ " eta BIGINT NOT NULL,"
|
||||||
+ " PRIMARY KEY (messageId, contactId),"
|
+ " PRIMARY KEY (messageId, contactId),"
|
||||||
+ " FOREIGN KEY (messageId)"
|
+ " FOREIGN KEY (messageId)"
|
||||||
+ " REFERENCES messages (messageId)"
|
+ " REFERENCES messages (messageId)"
|
||||||
@@ -305,6 +308,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
// Different database libraries use different names for certain types
|
// Different database libraries use different names for certain types
|
||||||
private final String hashType, secretType, binaryType;
|
private final String hashType, secretType, binaryType;
|
||||||
private final String counterType, stringType;
|
private final String counterType, stringType;
|
||||||
|
private final MessageFactory messageFactory;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
// Locking: connectionsLock
|
// Locking: connectionsLock
|
||||||
@@ -320,12 +324,14 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
private final Condition connectionsChanged = connectionsLock.newCondition();
|
private final Condition connectionsChanged = connectionsLock.newCondition();
|
||||||
|
|
||||||
JdbcDatabase(String hashType, String secretType, String binaryType,
|
JdbcDatabase(String hashType, String secretType, String binaryType,
|
||||||
String counterType, String stringType, Clock clock) {
|
String counterType, String stringType,
|
||||||
|
MessageFactory messageFactory, Clock clock) {
|
||||||
this.hashType = hashType;
|
this.hashType = hashType;
|
||||||
this.secretType = secretType;
|
this.secretType = secretType;
|
||||||
this.binaryType = binaryType;
|
this.binaryType = binaryType;
|
||||||
this.counterType = counterType;
|
this.counterType = counterType;
|
||||||
this.stringType = stringType;
|
this.stringType = stringType;
|
||||||
|
this.messageFactory = messageFactory;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +398,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return singletonList(new Migration38_39());
|
return Arrays.asList(new Migration38_39(), new Migration39_40());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeSchemaVersion(Connection txn, int version)
|
private void storeSchemaVersion(Connection txn, int version)
|
||||||
@@ -727,7 +733,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
ps.setLong(3, m.getTimestamp());
|
ps.setLong(3, m.getTimestamp());
|
||||||
ps.setInt(4, state.getValue());
|
ps.setInt(4, state.getValue());
|
||||||
ps.setBoolean(5, messageShared);
|
ps.setBoolean(5, messageShared);
|
||||||
byte[] raw = m.getRaw();
|
byte[] raw = messageFactory.getRawMessage(m);
|
||||||
ps.setInt(6, raw.length);
|
ps.setInt(6, raw.length);
|
||||||
ps.setBytes(7, raw);
|
ps.setBytes(7, raw);
|
||||||
int affected = ps.executeUpdate();
|
int affected = ps.executeUpdate();
|
||||||
@@ -741,7 +747,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
boolean offered = removeOfferedMessage(txn, c, m.getId());
|
boolean offered = removeOfferedMessage(txn, c, m.getId());
|
||||||
boolean seen = offered || (sender != null && c.equals(sender));
|
boolean seen = offered || (sender != null && c.equals(sender));
|
||||||
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
|
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
|
||||||
m.getRawLength(), state, e.getValue(), messageShared,
|
raw.length, state, e.getValue(), messageShared,
|
||||||
false, seen);
|
false, seen);
|
||||||
}
|
}
|
||||||
// Update denormalised column in messageDependencies if dependency
|
// Update denormalised column in messageDependencies if dependency
|
||||||
@@ -800,8 +806,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
try {
|
try {
|
||||||
String sql = "INSERT INTO statuses (messageId, contactId, groupId,"
|
String sql = "INSERT INTO statuses (messageId, contactId, groupId,"
|
||||||
+ " timestamp, length, state, groupShared, messageShared,"
|
+ " timestamp, length, state, groupShared, messageShared,"
|
||||||
+ " deleted, ack, seen, requested, expiry, txCount)"
|
+ " deleted, ack, seen, requested, expiry, txCount, eta)"
|
||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, 0, 0)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, 0, 0,"
|
||||||
|
+ " 0)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, m.getBytes());
|
ps.setBytes(1, m.getBytes());
|
||||||
ps.setInt(2, c.getInt());
|
ps.setInt(2, c.getInt());
|
||||||
@@ -1501,7 +1508,10 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
if (raw == null) throw new MessageDeletedException();
|
if (raw == null) throw new MessageDeletedException();
|
||||||
return new Message(m, g, timestamp, raw);
|
if (raw.length < MESSAGE_HEADER_LENGTH) throw new AssertionError();
|
||||||
|
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
|
||||||
|
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
|
||||||
|
return new Message(m, g, timestamp, body);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
tryToClose(rs);
|
tryToClose(rs);
|
||||||
tryToClose(ps);
|
tryToClose(ps);
|
||||||
@@ -1861,8 +1871,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getMessagesToOffer(Connection txn,
|
public Collection<MessageId> getMessagesToOffer(Connection txn,
|
||||||
ContactId c, int maxMessages) throws DbException {
|
ContactId c, int maxMessages, int maxLatency) throws DbException {
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
|
long eta = now + maxLatency;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -1871,13 +1882,14 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||||
+ " AND deleted = FALSE"
|
+ " AND deleted = FALSE"
|
||||||
+ " AND seen = FALSE AND requested = FALSE"
|
+ " AND seen = FALSE AND requested = FALSE"
|
||||||
+ " AND expiry < ?"
|
+ " AND (expiry <= ? OR eta > ?)"
|
||||||
+ " ORDER BY timestamp LIMIT ?";
|
+ " ORDER BY timestamp LIMIT ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setInt(2, DELIVERED.getValue());
|
ps.setInt(2, DELIVERED.getValue());
|
||||||
ps.setLong(3, now);
|
ps.setLong(3, now);
|
||||||
ps.setInt(4, maxMessages);
|
ps.setLong(4, eta);
|
||||||
|
ps.setInt(5, maxMessages);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<>();
|
List<MessageId> ids = new ArrayList<>();
|
||||||
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
||||||
@@ -1918,8 +1930,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getMessagesToSend(Connection txn, ContactId c,
|
public Collection<MessageId> getMessagesToSend(Connection txn, ContactId c,
|
||||||
int maxLength) throws DbException {
|
int maxLength, int maxLatency) throws DbException {
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
|
long eta = now + maxLatency;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -1928,12 +1941,13 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||||
+ " AND deleted = FALSE"
|
+ " AND deleted = FALSE"
|
||||||
+ " AND seen = FALSE"
|
+ " AND seen = FALSE"
|
||||||
+ " AND expiry < ?"
|
+ " AND (expiry <= ? OR eta > ?)"
|
||||||
+ " ORDER BY timestamp";
|
+ " ORDER BY timestamp";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setInt(2, DELIVERED.getValue());
|
ps.setInt(2, DELIVERED.getValue());
|
||||||
ps.setLong(3, now);
|
ps.setLong(3, now);
|
||||||
|
ps.setLong(4, eta);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<>();
|
List<MessageId> ids = new ArrayList<>();
|
||||||
int total = 0;
|
int total = 0;
|
||||||
@@ -2047,8 +2061,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getRequestedMessagesToSend(Connection txn,
|
public Collection<MessageId> getRequestedMessagesToSend(Connection txn,
|
||||||
ContactId c, int maxLength) throws DbException {
|
ContactId c, int maxLength, int maxLatency) throws DbException {
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
|
long eta = now + maxLatency;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -2057,12 +2072,13 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||||
+ " AND deleted = FALSE"
|
+ " AND deleted = FALSE"
|
||||||
+ " AND seen = FALSE AND requested = TRUE"
|
+ " AND seen = FALSE AND requested = TRUE"
|
||||||
+ " AND expiry < ?"
|
+ " AND (expiry <= ? OR eta > ?)"
|
||||||
+ " ORDER BY timestamp";
|
+ " ORDER BY timestamp";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setInt(2, DELIVERED.getValue());
|
ps.setInt(2, DELIVERED.getValue());
|
||||||
ps.setLong(3, now);
|
ps.setLong(3, now);
|
||||||
|
ps.setLong(4, eta);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<>();
|
List<MessageId> ids = new ArrayList<>();
|
||||||
int total = 0;
|
int total = 0;
|
||||||
@@ -2873,7 +2889,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateExpiryTime(Connection txn, ContactId c, MessageId m,
|
public void updateExpiryTimeAndEta(Connection txn, ContactId c, MessageId m,
|
||||||
int maxLatency) throws DbException {
|
int maxLatency) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
@@ -2889,13 +2905,16 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if (rs.next()) throw new DbStateException();
|
if (rs.next()) throw new DbStateException();
|
||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
sql = "UPDATE statuses SET expiry = ?, txCount = txCount + 1"
|
sql = "UPDATE statuses"
|
||||||
|
+ " SET expiry = ?, txCount = txCount + 1, eta = ?"
|
||||||
+ " WHERE messageId = ? AND contactId = ?";
|
+ " WHERE messageId = ? AND contactId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
|
long eta = now + maxLatency;
|
||||||
ps.setLong(1, calculateExpiry(now, maxLatency, txCount));
|
ps.setLong(1, calculateExpiry(now, maxLatency, txCount));
|
||||||
ps.setBytes(2, m.getBytes());
|
ps.setLong(2, eta);
|
||||||
ps.setInt(3, c.getInt());
|
ps.setBytes(3, m.getBytes());
|
||||||
|
ps.setInt(4, c.getInt());
|
||||||
int affected = ps.executeUpdate();
|
int affected = ps.executeUpdate();
|
||||||
if (affected != 1) throw new DbStateException();
|
if (affected != 1) throw new DbStateException();
|
||||||
ps.close();
|
ps.close();
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
|
class Migration39_40 implements Migration<Connection> {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(Migration39_40.class.getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStartVersion() {
|
||||||
|
return 39;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEndVersion() {
|
||||||
|
return 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void migrate(Connection txn) throws DbException {
|
||||||
|
Statement s = null;
|
||||||
|
try {
|
||||||
|
s = txn.createStatement();
|
||||||
|
s.execute("ALTER TABLE statuses"
|
||||||
|
+ " ADD eta BIGINT");
|
||||||
|
s.execute("UPDATE statuses SET eta = 0");
|
||||||
|
s.execute("ALTER TABLE statuses"
|
||||||
|
+ " ALTER COLUMN eta"
|
||||||
|
+ " SET NOT NULL");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
tryToClose(s);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryToClose(@Nullable Statement s) {
|
||||||
|
try {
|
||||||
|
if (s != null) s.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,11 +39,7 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
if (body.length > MAX_MESSAGE_BODY_LENGTH)
|
if (body.length > MAX_MESSAGE_BODY_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
MessageId id = getMessageId(g, timestamp, body);
|
MessageId id = getMessageId(g, timestamp, body);
|
||||||
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
|
return new Message(id, g, timestamp, body);
|
||||||
System.arraycopy(g.getBytes(), 0, raw, 0, UniqueId.LENGTH);
|
|
||||||
ByteUtils.writeUint64(timestamp, raw, UniqueId.LENGTH);
|
|
||||||
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
|
|
||||||
return new Message(id, g, timestamp, raw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MessageId getMessageId(GroupId g, long timestamp, byte[] body) {
|
private MessageId getMessageId(GroupId g, long timestamp, byte[] body) {
|
||||||
@@ -69,18 +65,16 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
|
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
|
||||||
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
|
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
|
||||||
MessageId id = getMessageId(g, timestamp, body);
|
MessageId id = getMessageId(g, timestamp, body);
|
||||||
return new Message(id, g, timestamp, raw);
|
return new Message(id, g, timestamp, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Message createMessage(MessageId m, byte[] raw) {
|
public byte[] getRawMessage(Message m) {
|
||||||
if (raw.length < MESSAGE_HEADER_LENGTH)
|
byte[] body = m.getBody();
|
||||||
throw new IllegalArgumentException();
|
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
|
||||||
if (raw.length > MAX_MESSAGE_LENGTH)
|
System.arraycopy(m.getGroupId().getBytes(), 0, raw, 0, UniqueId.LENGTH);
|
||||||
throw new IllegalArgumentException();
|
ByteUtils.writeUint64(m.getTimestamp(), raw, UniqueId.LENGTH);
|
||||||
byte[] groupId = new byte[UniqueId.LENGTH];
|
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
|
||||||
System.arraycopy(raw, 0, groupId, 0, UniqueId.LENGTH);
|
return raw;
|
||||||
long timestamp = ByteUtils.readUint64(raw, UniqueId.LENGTH);
|
|
||||||
return new Message(m, new GroupId(groupId), timestamp, raw);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.sync;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.record.RecordWriter;
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
||||||
|
|
||||||
@@ -13,16 +14,19 @@ import javax.inject.Inject;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory {
|
class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory {
|
||||||
|
|
||||||
|
private final MessageFactory messageFactory;
|
||||||
private final RecordWriterFactory recordWriterFactory;
|
private final RecordWriterFactory recordWriterFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SyncRecordWriterFactoryImpl(RecordWriterFactory recordWriterFactory) {
|
SyncRecordWriterFactoryImpl(MessageFactory messageFactory,
|
||||||
|
RecordWriterFactory recordWriterFactory) {
|
||||||
|
this.messageFactory = messageFactory;
|
||||||
this.recordWriterFactory = recordWriterFactory;
|
this.recordWriterFactory = recordWriterFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SyncRecordWriter createRecordWriter(OutputStream out) {
|
public SyncRecordWriter createRecordWriter(OutputStream out) {
|
||||||
RecordWriter writer = recordWriterFactory.createRecordWriter(out);
|
RecordWriter writer = recordWriterFactory.createRecordWriter(out);
|
||||||
return new SyncRecordWriterImpl(writer);
|
return new SyncRecordWriterImpl(messageFactory, writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.record.Record;
|
|||||||
import org.briarproject.bramble.api.record.RecordWriter;
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.Offer;
|
import org.briarproject.bramble.api.sync.Offer;
|
||||||
import org.briarproject.bramble.api.sync.Request;
|
import org.briarproject.bramble.api.sync.Request;
|
||||||
@@ -25,10 +26,12 @@ import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class SyncRecordWriterImpl implements SyncRecordWriter {
|
class SyncRecordWriterImpl implements SyncRecordWriter {
|
||||||
|
|
||||||
|
private final MessageFactory messageFactory;
|
||||||
private final RecordWriter writer;
|
private final RecordWriter writer;
|
||||||
private final ByteArrayOutputStream payload = new ByteArrayOutputStream();
|
private final ByteArrayOutputStream payload = new ByteArrayOutputStream();
|
||||||
|
|
||||||
SyncRecordWriterImpl(RecordWriter writer) {
|
SyncRecordWriterImpl(MessageFactory messageFactory, RecordWriter writer) {
|
||||||
|
this.messageFactory = messageFactory;
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +49,8 @@ class SyncRecordWriterImpl implements SyncRecordWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeMessage(Message m) throws IOException {
|
public void writeMessage(Message m) throws IOException {
|
||||||
writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, m.getRaw()));
|
byte[] raw = messageFactory.getRawMessage(m);
|
||||||
|
writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, raw));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,10 +16,8 @@ import org.jmock.Expectations;
|
|||||||
import org.jmock.lib.legacy.ClassImposteriser;
|
import org.jmock.lib.legacy.ClassImposteriser;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertSame;
|
import static org.junit.Assert.assertSame;
|
||||||
|
|
||||||
@@ -58,8 +56,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
|
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
|
||||||
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH,
|
oneOf(clientHelper).toList(message.getBody());
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
will(returnValue(body));
|
will(returnValue(body));
|
||||||
oneOf(metadataEncoder).encode(dictionary);
|
oneOf(metadataEncoder).encode(dictionary);
|
||||||
will(returnValue(meta));
|
will(returnValue(meta));
|
||||||
@@ -84,18 +81,11 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
|
|
||||||
@Test(expected = InvalidMessageException.class)
|
@Test(expected = InvalidMessageException.class)
|
||||||
public void testRejectsTooShortMessage() throws Exception {
|
public void testRejectsTooShortMessage() throws Exception {
|
||||||
byte[] invalidRaw = getRandomBytes(MESSAGE_HEADER_LENGTH);
|
Message invalidMessage = getMessage(groupId, 0);
|
||||||
// Use a mock message so the length of the raw message can be invalid
|
|
||||||
Message invalidMessage = context.mock(Message.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
oneOf(invalidMessage).getTimestamp();
|
|
||||||
will(returnValue(timestamp));
|
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(invalidMessage).getRaw();
|
|
||||||
will(returnValue(invalidRaw));
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
failIfSubclassIsCalled.validateMessage(invalidMessage, group);
|
failIfSubclassIsCalled.validateMessage(invalidMessage, group);
|
||||||
@@ -103,13 +93,12 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptsMinLengthMessage() throws Exception {
|
public void testAcceptsMinLengthMessage() throws Exception {
|
||||||
Message shortMessage = getMessage(groupId, MESSAGE_HEADER_LENGTH + 1);
|
Message shortMessage = getMessage(groupId, 1);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(clientHelper).toList(shortMessage.getRaw(),
|
oneOf(clientHelper).toList(shortMessage.getBody());
|
||||||
MESSAGE_HEADER_LENGTH, 1);
|
|
||||||
will(returnValue(body));
|
will(returnValue(body));
|
||||||
oneOf(metadataEncoder).encode(dictionary);
|
oneOf(metadataEncoder).encode(dictionary);
|
||||||
will(returnValue(meta));
|
will(returnValue(meta));
|
||||||
@@ -137,8 +126,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH,
|
oneOf(clientHelper).toList(message.getBody());
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
will(throwException(new FormatException()));
|
will(throwException(new FormatException()));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
@@ -150,8 +138,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH,
|
oneOf(clientHelper).toList(message.getBody());
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
will(returnValue(body));
|
will(returnValue(body));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import java.util.HashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertTrue;
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.test.ArrayClock;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
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;
|
||||||
@@ -74,24 +76,4 @@ public class ScryptKdfTest extends BrambleTestCase {
|
|||||||
PasswordBasedKdf kdf = new ScryptKdf(clock);
|
PasswordBasedKdf kdf = new ScryptKdf(clock);
|
||||||
assertEquals(256, kdf.chooseCostParameter());
|
assertEquals(256, kdf.chooseCostParameter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ArrayClock implements Clock {
|
|
||||||
|
|
||||||
private final long[] times;
|
|
||||||
private int index = 0;
|
|
||||||
|
|
||||||
private ArrayClock(long... times) {
|
|
||||||
this.times = times;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long currentTimeMillis() {
|
|
||||||
return times[index++];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sleep(long milliseconds) throws InterruptedException {
|
|
||||||
Thread.sleep(milliseconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -871,15 +871,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).containsContact(txn, contactId);
|
oneOf(database).containsContact(txn, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getMessagesToSend(txn, contactId,
|
oneOf(database).getMessagesToSend(txn, contactId,
|
||||||
MAX_MESSAGE_LENGTH * 2);
|
MAX_MESSAGE_LENGTH * 2, maxLatency);
|
||||||
will(returnValue(ids));
|
will(returnValue(ids));
|
||||||
oneOf(database).getMessage(txn, messageId);
|
oneOf(database).getMessage(txn, messageId);
|
||||||
will(returnValue(message));
|
will(returnValue(message));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).getMessage(txn, messageId1);
|
oneOf(database).getMessage(txn, messageId1);
|
||||||
will(returnValue(message1));
|
will(returnValue(message1));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
|
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
@@ -907,11 +907,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(database).containsContact(txn, contactId);
|
oneOf(database).containsContact(txn, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getMessagesToOffer(txn, contactId, 123);
|
oneOf(database).getMessagesToOffer(txn, contactId, 123, maxLatency);
|
||||||
will(returnValue(ids));
|
will(returnValue(ids));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
@@ -967,15 +967,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).containsContact(txn, contactId);
|
oneOf(database).containsContact(txn, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getRequestedMessagesToSend(txn, contactId,
|
oneOf(database).getRequestedMessagesToSend(txn, contactId,
|
||||||
MAX_MESSAGE_LENGTH * 2);
|
MAX_MESSAGE_LENGTH * 2, maxLatency);
|
||||||
will(returnValue(ids));
|
will(returnValue(ids));
|
||||||
oneOf(database).getMessage(txn, messageId);
|
oneOf(database).getMessage(txn, messageId);
|
||||||
will(returnValue(message));
|
will(returnValue(message));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).getMessage(txn, messageId1);
|
oneOf(database).getMessage(txn, messageId1);
|
||||||
will(returnValue(message1));
|
will(returnValue(message1));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
|
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -45,6 +47,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
protected final DatabaseConfig config =
|
protected final DatabaseConfig config =
|
||||||
new TestDatabaseConfig(testDir, 1024 * 1024);
|
new TestDatabaseConfig(testDir, 1024 * 1024);
|
||||||
|
protected final MessageFactory messageFactory = new TestMessageFactory();
|
||||||
protected final SecretKey key = getSecretKey();
|
protected final SecretKey key = getSecretKey();
|
||||||
protected final Clock clock = new SystemClock();
|
protected final Clock clock = new SystemClock();
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
import org.briarproject.bramble.test.UTest;
|
import org.briarproject.bramble.test.UTest;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -30,7 +32,8 @@ public abstract class DatabasePerformanceComparisonTest
|
|||||||
private SecretKey databaseKey = getSecretKey();
|
private SecretKey databaseKey = getSecretKey();
|
||||||
|
|
||||||
abstract Database<Connection> createDatabase(boolean conditionA,
|
abstract Database<Connection> createDatabase(boolean conditionA,
|
||||||
DatabaseConfig databaseConfig, Clock clock);
|
DatabaseConfig databaseConfig, MessageFactory messageFactory,
|
||||||
|
Clock clock);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void benchmark(String name,
|
protected void benchmark(String name,
|
||||||
@@ -73,7 +76,8 @@ public abstract class DatabasePerformanceComparisonTest
|
|||||||
private Database<Connection> openDatabase(boolean conditionA)
|
private Database<Connection> openDatabase(boolean conditionA)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
Database<Connection> db = createDatabase(conditionA,
|
Database<Connection> db = createDatabase(conditionA,
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
|
new TestMessageFactory(), new SystemClock());
|
||||||
db.open(databaseKey, null);
|
db.open(databaseKey, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
*/
|
*/
|
||||||
private static final int STEADY_STATE_BLOCKS = 5;
|
private static final int STEADY_STATE_BLOCKS = 5;
|
||||||
|
|
||||||
|
// All our transports use a maximum latency of 30 seconds
|
||||||
|
private static final int MAX_LATENCY = 30 * 1000;
|
||||||
|
|
||||||
protected final File testDir = getTestDirectory();
|
protected final File testDir = getTestDirectory();
|
||||||
private final File resultsFile = new File(getTestName() + ".tsv");
|
private final File resultsFile = new File(getTestName() + ".tsv");
|
||||||
protected final Random random = new Random();
|
protected final Random random = new Random();
|
||||||
@@ -448,7 +451,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.getMessagesToOffer(txn, pickRandom(contacts).getId(),
|
db.getMessagesToOffer(txn, pickRandom(contacts).getId(),
|
||||||
MAX_MESSAGE_IDS);
|
MAX_MESSAGE_IDS, MAX_LATENCY);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -470,7 +473,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.getMessagesToSend(txn, pickRandom(contacts).getId(),
|
db.getMessagesToSend(txn, pickRandom(contacts).getId(),
|
||||||
MAX_MESSAGE_IDS);
|
MAX_MESSAGE_IDS, MAX_LATENCY);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -521,7 +524,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.getRequestedMessagesToSend(txn, pickRandom(contacts).getId(),
|
db.getRequestedMessagesToSend(txn, pickRandom(contacts).getId(),
|
||||||
MAX_MESSAGE_IDS);
|
MAX_MESSAGE_IDS, MAX_LATENCY);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -24,7 +26,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
|||||||
private SecretKey databaseKey = getSecretKey();
|
private SecretKey databaseKey = getSecretKey();
|
||||||
|
|
||||||
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
||||||
Clock clock);
|
MessageFactory messageFactory, Clock clock);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
protected abstract File getTraceFile();
|
protected abstract File getTraceFile();
|
||||||
@@ -46,7 +48,8 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
|||||||
|
|
||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
|
new TestMessageFactory(), new SystemClock());
|
||||||
db.open(databaseKey, null);
|
db.open(databaseKey, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -13,7 +14,8 @@ public class H2DatabasePerformanceTest extends SingleDatabasePerformanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
|
protected JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
return new H2Database(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new H2Database(config, messageFactory, clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
public class H2DatabaseTest extends JdbcDatabaseTest {
|
public class H2DatabaseTest extends JdbcDatabaseTest {
|
||||||
|
|
||||||
public H2DatabaseTest() throws Exception {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
|
protected JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
return new H2Database(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new H2Database(config, messageFactory, clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -14,8 +15,8 @@ public class H2DatabaseTraceTest extends DatabaseTraceTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
||||||
Clock clock) {
|
MessageFactory messageFactory, Clock clock) {
|
||||||
return new H2Database(databaseConfig, clock) {
|
return new H2Database(databaseConfig, messageFactory, clock) {
|
||||||
@Override
|
@Override
|
||||||
@Nonnull
|
@Nonnull
|
||||||
String getUrl() {
|
String getUrl() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -12,9 +13,11 @@ public class H2HyperSqlDatabasePerformanceComparisonTest
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(boolean conditionA,
|
Database<Connection> createDatabase(boolean conditionA,
|
||||||
DatabaseConfig databaseConfig, Clock clock) {
|
DatabaseConfig databaseConfig, MessageFactory messageFactory,
|
||||||
if (conditionA) return new H2Database(databaseConfig, clock);
|
Clock clock) {
|
||||||
else return new HyperSqlDatabase(databaseConfig, clock);
|
if (conditionA)
|
||||||
|
return new H2Database(databaseConfig, messageFactory, clock);
|
||||||
|
else return new HyperSqlDatabase(databaseConfig, messageFactory, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class H2MigrationTest extends DatabaseMigrationTest {
|
|||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(
|
Database<Connection> createDatabase(
|
||||||
List<Migration<Connection>> migrations) {
|
List<Migration<Connection>> migrations) {
|
||||||
return new H2Database(config, clock) {
|
return new H2Database(config, messageFactory, clock) {
|
||||||
@Override
|
@Override
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return migrations;
|
return migrations;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -17,8 +18,9 @@ public class H2SelfDatabasePerformanceComparisonTest
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(boolean conditionA,
|
Database<Connection> createDatabase(boolean conditionA,
|
||||||
DatabaseConfig databaseConfig, Clock clock) {
|
DatabaseConfig databaseConfig, MessageFactory messageFactory,
|
||||||
return new H2Database(databaseConfig, clock);
|
Clock clock) {
|
||||||
|
return new H2Database(databaseConfig, messageFactory, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -19,11 +20,12 @@ public class H2SleepDatabasePerformanceComparisonTest
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(boolean conditionA,
|
Database<Connection> createDatabase(boolean conditionA,
|
||||||
DatabaseConfig databaseConfig, Clock clock) {
|
DatabaseConfig databaseConfig, MessageFactory messageFactory,
|
||||||
|
Clock clock) {
|
||||||
if (conditionA) {
|
if (conditionA) {
|
||||||
return new H2Database(databaseConfig, clock);
|
return new H2Database(databaseConfig, messageFactory, clock);
|
||||||
} else {
|
} else {
|
||||||
return new H2Database(databaseConfig, clock) {
|
return new H2Database(databaseConfig, messageFactory, clock) {
|
||||||
@Override
|
@Override
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public void commitTransaction(Connection txn)
|
public void commitTransaction(Connection txn)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -14,7 +15,8 @@ public class HyperSqlDatabasePerformanceTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
|
protected JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
return new HyperSqlDatabase(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new HyperSqlDatabase(config, messageFactory, clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
public class HyperSqlDatabaseTest extends JdbcDatabaseTest {
|
public class HyperSqlDatabaseTest extends JdbcDatabaseTest {
|
||||||
|
|
||||||
public HyperSqlDatabaseTest() throws Exception {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
|
protected JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
return new HyperSqlDatabase(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new HyperSqlDatabase(config, messageFactory ,clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import java.util.List;
|
|||||||
public class HyperSqlMigrationTest extends DatabaseMigrationTest {
|
public class HyperSqlMigrationTest extends DatabaseMigrationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(List<Migration<Connection>> migrations)
|
Database<Connection> createDatabase(
|
||||||
throws Exception {
|
List<Migration<Connection>> migrations) {
|
||||||
return new HyperSqlDatabase(config, clock) {
|
return new HyperSqlDatabase(config, messageFactory, clock) {
|
||||||
@Override
|
@Override
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return migrations;
|
return migrations;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.sync.ClientId;
|
|||||||
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;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||||
@@ -25,8 +26,10 @@ import org.briarproject.bramble.api.transport.KeySetId;
|
|||||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
|
import org.briarproject.bramble.test.ArrayClock;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -58,6 +61,7 @@ import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERE
|
|||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
||||||
@@ -80,6 +84,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
private static final int ONE_MEGABYTE = 1024 * 1024;
|
private static final int ONE_MEGABYTE = 1024 * 1024;
|
||||||
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
|
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
|
||||||
|
// All our transports use a maximum latency of 30 seconds
|
||||||
|
private static final int MAX_LATENCY = 30 * 1000;
|
||||||
|
|
||||||
|
|
||||||
private final SecretKey key = getSecretKey();
|
private final SecretKey key = getSecretKey();
|
||||||
private final File testDir = getTestDirectory();
|
private final File testDir = getTestDirectory();
|
||||||
@@ -112,7 +119,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected abstract JdbcDatabase createDatabase(DatabaseConfig config,
|
protected abstract JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
Clock clock);
|
MessageFactory messageFactory, Clock clock);
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -144,8 +151,8 @@ 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));
|
||||||
assertArrayEquals(message.getRaw(),
|
assertArrayEquals(message.getBody(),
|
||||||
db.getMessage(txn, messageId).getRaw());
|
db.getMessage(txn, messageId).getBody());
|
||||||
|
|
||||||
// Delete the records
|
// Delete the records
|
||||||
db.removeMessage(txn, messageId);
|
db.removeMessage(txn, messageId);
|
||||||
@@ -197,16 +204,16 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The contact has not seen the message, so it should be sendable
|
// The contact has not seen the message, so it should be sendable
|
||||||
Collection<MessageId> ids =
|
Collection<MessageId> ids =
|
||||||
db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
// Changing the status to seen = true should make the message unsendable
|
// Changing the status to seen = true should make the message unsendable
|
||||||
db.raiseSeenFlag(txn, contactId, messageId);
|
db.raiseSeenFlag(txn, contactId, messageId);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -228,30 +235,30 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The message has not been validated, so it should not be sendable
|
// The message has not been validated, so it should not be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Marking the message delivered should make it sendable
|
// Marking the message delivered should make it sendable
|
||||||
db.setMessageState(txn, messageId, DELIVERED);
|
db.setMessageState(txn, messageId, DELIVERED);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
// Marking the message invalid should make it unsendable
|
// Marking the message invalid should make it unsendable
|
||||||
db.setMessageState(txn, messageId, INVALID);
|
db.setMessageState(txn, messageId, INVALID);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Marking the message pending should make it unsendable
|
// Marking the message pending should make it unsendable
|
||||||
db.setMessageState(txn, messageId, PENDING);
|
db.setMessageState(txn, messageId, PENDING);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -272,37 +279,37 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The group is invisible, so the message should not be sendable
|
// The group is invisible, so the message should not be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Making the group visible should not make the message sendable
|
// Making the group visible should not make the message sendable
|
||||||
db.addGroupVisibility(txn, contactId, groupId, false);
|
db.addGroupVisibility(txn, contactId, groupId, false);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Sharing the group should make the message sendable
|
// Sharing the group should make the message sendable
|
||||||
db.setGroupVisibility(txn, contactId, groupId, true);
|
db.setGroupVisibility(txn, contactId, groupId, true);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
// Unsharing the group should make the message unsendable
|
// Unsharing the group should make the message unsendable
|
||||||
db.setGroupVisibility(txn, contactId, groupId, false);
|
db.setGroupVisibility(txn, contactId, groupId, false);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Making the group invisible should make the message unsendable
|
// Making the group invisible should make the message unsendable
|
||||||
db.removeGroupVisibility(txn, contactId, groupId);
|
db.removeGroupVisibility(txn, contactId, groupId);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -324,16 +331,16 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The message is not shared, so it should not be sendable
|
// The message is not shared, so it should not be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Sharing the message should make it sendable
|
// Sharing the message should make it sendable
|
||||||
db.setMessageShared(txn, messageId);
|
db.setMessageShared(txn, messageId);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -354,12 +361,13 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
|
||||||
// The message is sendable, but too large to send
|
// The message is sendable, but too large to send
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids =
|
||||||
message.getRawLength() - 1);
|
db.getMessagesToSend(txn, contactId, message.getRawLength() - 1,
|
||||||
|
MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// The message is just the right size to send
|
// The message is just the right size to send
|
||||||
ids = db.getMessagesToSend(txn, contactId, message.getRawLength());
|
ids = db.getMessagesToSend(txn, contactId, message.getRawLength(),
|
||||||
|
MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -422,19 +430,19 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// Retrieve the message from the database and mark it as sent
|
// Retrieve the message from the database and mark it as sent
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
db.updateExpiryTime(txn, contactId, messageId, Integer.MAX_VALUE);
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, MAX_LATENCY);
|
||||||
|
|
||||||
// The message should no longer be sendable
|
// The message should no longer be sendable
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Pretend that the message was acked
|
// Pretend that the message was acked
|
||||||
db.raiseSeenFlag(txn, contactId, messageId);
|
db.raiseSeenFlag(txn, contactId, messageId);
|
||||||
|
|
||||||
// The message still should not be sendable
|
// The message still should not be sendable
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -1515,7 +1523,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
assertFalse(status.isSeen());
|
assertFalse(status.isSeen());
|
||||||
|
|
||||||
// Pretend the message was sent to the contact
|
// Pretend the message was sent to the contact
|
||||||
db.updateExpiryTime(txn, contactId, messageId, Integer.MAX_VALUE);
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, Integer.MAX_VALUE);
|
||||||
|
|
||||||
// The message should be sent but not seen
|
// The message should be sent but not seen
|
||||||
status = db.getMessageStatus(txn, contactId, messageId);
|
status = db.getMessageStatus(txn, contactId, messageId);
|
||||||
@@ -1634,9 +1642,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The message should be sendable
|
// The message should be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
// The message should be available
|
// The message should be available
|
||||||
@@ -1644,7 +1652,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
assertEquals(messageId, m.getId());
|
assertEquals(messageId, m.getId());
|
||||||
assertEquals(groupId, m.getGroupId());
|
assertEquals(groupId, m.getGroupId());
|
||||||
assertEquals(message.getTimestamp(), m.getTimestamp());
|
assertEquals(message.getTimestamp(), m.getTimestamp());
|
||||||
assertArrayEquals(message.getRaw(), m.getRaw());
|
assertArrayEquals(message.getBody(), m.getBody());
|
||||||
|
|
||||||
// Delete the message
|
// Delete the message
|
||||||
db.deleteMessage(txn, messageId);
|
db.deleteMessage(txn, messageId);
|
||||||
@@ -1653,9 +1661,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
assertTrue(db.containsVisibleMessage(txn, contactId, messageId));
|
assertTrue(db.containsVisibleMessage(txn, contactId, messageId));
|
||||||
|
|
||||||
// The message should not be sendable
|
// The message should not be sendable
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Requesting the message should throw an exception
|
// Requesting the message should throw an exception
|
||||||
@@ -1727,7 +1735,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testGetNextSendTime() throws Exception {
|
public void testGetNextSendTime() throws Exception {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Database<Connection> db = open(false, new StoppedClock(now));
|
Database<Connection> db = open(false, new TestMessageFactory(),
|
||||||
|
new StoppedClock(now));
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a group and a message
|
// Add a contact, a group and a message
|
||||||
@@ -1758,12 +1767,12 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// Update the message's expiry time as though we sent it - now the
|
// Update the message's expiry time as though we sent it - now the
|
||||||
// message should be sendable after one round-trip
|
// message should be sendable after one round-trip
|
||||||
db.updateExpiryTime(txn, contactId, messageId, 1000);
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, 1000);
|
||||||
assertEquals(now + 2000, db.getNextSendTime(txn, contactId));
|
assertEquals(now + 2000, db.getNextSendTime(txn, contactId));
|
||||||
|
|
||||||
// Update the message's expiry time again - now it should be sendable
|
// Update the message's expiry time again - now it should be sendable
|
||||||
// after two round-trips
|
// after two round-trips
|
||||||
db.updateExpiryTime(txn, contactId, messageId, 1000);
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, 1000);
|
||||||
assertEquals(now + 4000, db.getNextSendTime(txn, contactId));
|
assertEquals(now + 4000, db.getNextSendTime(txn, contactId));
|
||||||
|
|
||||||
// Delete the message - there should be no messages to send
|
// Delete the message - there should be no messages to send
|
||||||
@@ -1806,14 +1815,112 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Database<Connection> open(boolean resume) throws Exception {
|
@Test
|
||||||
return open(resume, new SystemClock());
|
public void testMessageRetransmission() throws Exception {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long steps[] = {now, now, now + MAX_LATENCY * 2 - 1,
|
||||||
|
now + MAX_LATENCY * 2};
|
||||||
|
Database<Connection> db =
|
||||||
|
open(false, new TestMessageFactory(), new ArrayClock(steps));
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add a contact, a shared group and a shared message
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
|
db.addGroup(txn, group);
|
||||||
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// Retrieve the message from the database
|
||||||
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// Mark the message as sent
|
||||||
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, MAX_LATENCY);
|
||||||
|
|
||||||
|
// The message should expire after 2 * MAX_LATENCY
|
||||||
|
assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId));
|
||||||
|
|
||||||
|
// Time: now + MAX_LATENCY * 2 - 1
|
||||||
|
// The message should not yet be sendable
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
// Time: now + MAX_LATENCY * 2
|
||||||
|
// The message should have expired and should now be sendable
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Database<Connection> open(boolean resume, Clock clock)
|
|
||||||
throws Exception {
|
@Test
|
||||||
Database<Connection> db = createDatabase(
|
public void testFasterMessageRetransmission() throws Exception {
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
|
long now = System.currentTimeMillis();
|
||||||
|
long steps[] = {now, now, now, now, now + 1};
|
||||||
|
Database<Connection> db =
|
||||||
|
open(false, new TestMessageFactory(), new ArrayClock(steps));
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add a contact, a shared group and a shared message
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
|
db.addGroup(txn, group);
|
||||||
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// Retrieve the message from the database
|
||||||
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// Mark the message as sent
|
||||||
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, MAX_LATENCY);
|
||||||
|
|
||||||
|
// The message should expire after 2 * MAX_LATENCY
|
||||||
|
assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId));
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// The message should not be sendable via the same transport
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// The message should be sendable via a transport with a faster ETA
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE,
|
||||||
|
MAX_LATENCY - 1);
|
||||||
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
|
// Time: now + 1
|
||||||
|
// The message should no longer be sendable via the faster transport,
|
||||||
|
// as the ETA is now equal
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE,
|
||||||
|
MAX_LATENCY - 1);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Database<Connection> open(boolean resume) throws Exception {
|
||||||
|
return open(resume, new TestMessageFactory(), new SystemClock());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Database<Connection> open(boolean resume,
|
||||||
|
MessageFactory messageFactory, Clock clock) throws Exception {
|
||||||
|
Database<Connection> db =
|
||||||
|
createDatabase(new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
|
messageFactory, clock);
|
||||||
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
||||||
db.open(key, null);
|
db.open(key, null);
|
||||||
return db;
|
return db;
|
||||||
@@ -1842,7 +1949,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
TestUtils.deleteTestDirectory(testDir);
|
deleteTestDirectory(testDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class StoppedClock implements Clock {
|
private static class StoppedClock implements Clock {
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@@ -21,7 +23,7 @@ public abstract class SingleDatabasePerformanceTest
|
|||||||
extends DatabasePerformanceTest {
|
extends DatabasePerformanceTest {
|
||||||
|
|
||||||
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
||||||
Clock clock);
|
MessageFactory messageFactory, Clock clock);
|
||||||
|
|
||||||
private SecretKey databaseKey = getSecretKey();
|
private SecretKey databaseKey = getSecretKey();
|
||||||
|
|
||||||
@@ -43,7 +45,8 @@ public abstract class SingleDatabasePerformanceTest
|
|||||||
|
|
||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
|
new TestMessageFactory(), new SystemClock());
|
||||||
db.open(databaseKey, null);
|
db.open(databaseKey, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,6 +170,6 @@ public class SyncIntegrationTest extends BrambleTestCase {
|
|||||||
m2.getGroupId().getBytes());
|
m2.getGroupId().getBytes());
|
||||||
assertEquals(m1.getTimestamp(), m2.getTimestamp());
|
assertEquals(m1.getTimestamp(), m2.getTimestamp());
|
||||||
assertEquals(m1.getRawLength(), m2.getRawLength());
|
assertEquals(m1.getRawLength(), m2.getRawLength());
|
||||||
assertArrayEquals(m1.getRaw(), m2.getRaw());
|
assertArrayEquals(m1.getBody(), m2.getBody());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class TestMessageFactory implements MessageFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message createMessage(GroupId g, long timestamp, byte[] body) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message createMessage(byte[] raw) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getRawMessage(Message m) {
|
||||||
|
byte[] body = m.getBody();
|
||||||
|
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
|
||||||
|
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,6 @@ public abstract class ValidatorTestCase extends BrambleMockTestCase {
|
|||||||
protected final Message message = getMessage(groupId);
|
protected final Message message = getMessage(groupId);
|
||||||
protected final MessageId messageId = message.getId();
|
protected final MessageId messageId = message.getId();
|
||||||
protected final long timestamp = message.getTimestamp();
|
protected final long timestamp = message.getTimestamp();
|
||||||
protected final byte[] raw = message.getRaw();
|
|
||||||
protected final Author author = getAuthor();
|
protected final Author author = getAuthor();
|
||||||
protected final BdfList authorList = BdfList.of(
|
protected final BdfList authorList = BdfList.of(
|
||||||
author.getFormatVersion(),
|
author.getFormatVersion(),
|
||||||
|
|||||||
@@ -2,65 +2,6 @@ apply plugin: 'com.android.application'
|
|||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation project(path: ':briar-core', configuration: 'default')
|
|
||||||
implementation project(path: ':bramble-core', configuration: 'default')
|
|
||||||
implementation project(':bramble-android')
|
|
||||||
|
|
||||||
def supportVersion = '27.1.1'
|
|
||||||
implementation "com.android.support:support-v4:$supportVersion"
|
|
||||||
implementation("com.android.support:appcompat-v7:$supportVersion") {
|
|
||||||
exclude module: 'support-v4'
|
|
||||||
}
|
|
||||||
implementation("com.android.support:preference-v14:$supportVersion") {
|
|
||||||
exclude module: 'support-v4'
|
|
||||||
}
|
|
||||||
implementation("com.android.support:design:$supportVersion") {
|
|
||||||
exclude module: 'support-v4'
|
|
||||||
exclude module: 'recyclerview-v7'
|
|
||||||
}
|
|
||||||
implementation "com.android.support:cardview-v7:$supportVersion"
|
|
||||||
implementation "com.android.support:support-annotations:$supportVersion"
|
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
|
|
||||||
|
|
||||||
implementation('ch.acra:acra:4.9.1') {
|
|
||||||
exclude module: 'support-v4'
|
|
||||||
exclude module: 'support-annotations'
|
|
||||||
}
|
|
||||||
implementation 'info.guardianproject.panic:panic:0.5'
|
|
||||||
implementation 'info.guardianproject.trustedintents:trustedintents:0.2'
|
|
||||||
implementation 'de.hdodenhof:circleimageview:2.2.0'
|
|
||||||
implementation 'com.google.zxing:core:3.3.0'
|
|
||||||
implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0'
|
|
||||||
implementation 'com.vanniktech:emoji-google:0.5.1'
|
|
||||||
|
|
||||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
|
||||||
|
|
||||||
compileOnly 'javax.annotation:jsr250-api:1.0'
|
|
||||||
|
|
||||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
|
||||||
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
|
||||||
testImplementation 'org.robolectric:robolectric:3.8'
|
|
||||||
testImplementation 'org.robolectric:shadows-support-v4:3.3.2'
|
|
||||||
testImplementation 'org.mockito:mockito-core:2.13.0'
|
|
||||||
testImplementation 'junit:junit:4.12'
|
|
||||||
testImplementation "org.jmock:jmock:2.8.2"
|
|
||||||
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
|
||||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
|
||||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
|
||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
|
||||||
|
|
||||||
def espressoVersion = '3.0.2'
|
|
||||||
androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
|
|
||||||
androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion"
|
|
||||||
androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion"
|
|
||||||
androidTestImplementation "tools.fastlane:screengrab:1.1.0"
|
|
||||||
androidTestImplementation "com.android.support.test.uiautomator:uiautomator-v18:2.1.3"
|
|
||||||
androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2"
|
|
||||||
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
|
|
||||||
androidTestImplementation 'junit:junit:4.12'
|
|
||||||
}
|
|
||||||
|
|
||||||
def getStdout = { command, defaultValue ->
|
def getStdout = { command, defaultValue ->
|
||||||
def stdout = new ByteArrayOutputStream()
|
def stdout = new ByteArrayOutputStream()
|
||||||
try {
|
try {
|
||||||
@@ -89,7 +30,7 @@ android {
|
|||||||
def now = (long) (System.currentTimeMillis() / 1000)
|
def now = (long) (System.currentTimeMillis() / 1000)
|
||||||
buildConfigField "Long", "BuildTimestamp",
|
buildConfigField "Long", "BuildTimestamp",
|
||||||
"${getStdout(['git', 'log', '-n', '1', '--format=%ct'], now)}000L"
|
"${getStdout(['git', 'log', '-n', '1', '--format=%ct'], now)}000L"
|
||||||
testInstrumentationRunner 'org.briarproject.briar.android.test.BriarTestRunner'
|
testInstrumentationRunner 'org.briarproject.briar.android.BriarTestRunner'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@@ -144,6 +85,68 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(path: ':briar-core', configuration: 'default')
|
||||||
|
implementation project(path: ':bramble-core', configuration: 'default')
|
||||||
|
implementation project(':bramble-android')
|
||||||
|
|
||||||
|
def supportVersion = '27.1.1'
|
||||||
|
implementation "com.android.support:support-v4:$supportVersion"
|
||||||
|
implementation("com.android.support:appcompat-v7:$supportVersion") {
|
||||||
|
exclude module: 'support-v4'
|
||||||
|
}
|
||||||
|
implementation("com.android.support:preference-v14:$supportVersion") {
|
||||||
|
exclude module: 'support-v4'
|
||||||
|
}
|
||||||
|
implementation("com.android.support:design:$supportVersion") {
|
||||||
|
exclude module: 'support-v4'
|
||||||
|
exclude module: 'recyclerview-v7'
|
||||||
|
}
|
||||||
|
implementation "com.android.support:cardview-v7:$supportVersion"
|
||||||
|
implementation "com.android.support:support-annotations:$supportVersion"
|
||||||
|
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
|
||||||
|
|
||||||
|
implementation('ch.acra:acra:4.9.1') {
|
||||||
|
exclude module: 'support-v4'
|
||||||
|
exclude module: 'support-annotations'
|
||||||
|
}
|
||||||
|
implementation 'info.guardianproject.panic:panic:0.5'
|
||||||
|
implementation 'info.guardianproject.trustedintents:trustedintents:0.2'
|
||||||
|
implementation 'de.hdodenhof:circleimageview:2.2.0'
|
||||||
|
implementation 'com.google.zxing:core:3.3.0'
|
||||||
|
implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0'
|
||||||
|
implementation 'com.vanniktech:emoji-google:0.5.1'
|
||||||
|
|
||||||
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
|
compileOnly 'javax.annotation:jsr250-api:1.0'
|
||||||
|
|
||||||
|
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
|
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
||||||
|
testImplementation 'org.robolectric:robolectric:3.8'
|
||||||
|
testImplementation 'org.robolectric:shadows-support-v4:3.3.2'
|
||||||
|
testImplementation 'org.mockito:mockito-core:2.13.0'
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
testImplementation "org.jmock:jmock:2.8.2"
|
||||||
|
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
||||||
|
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||||
|
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
||||||
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
|
|
||||||
|
def espressoVersion = '3.0.2'
|
||||||
|
androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
|
||||||
|
androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion"
|
||||||
|
androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion"
|
||||||
|
androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2"
|
||||||
|
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
|
||||||
|
androidTestImplementation 'junit:junit:4.12'
|
||||||
|
|
||||||
|
androidTestScreenshotImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
|
androidTestScreenshotImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
||||||
|
androidTestScreenshotImplementation "tools.fastlane:screengrab:1.2.0"
|
||||||
|
androidTestScreenshotImplementation "com.android.support.test.uiautomator:uiautomator-v18:2.1.3"
|
||||||
|
}
|
||||||
|
|
||||||
task verifyTranslations {
|
task verifyTranslations {
|
||||||
doLast {
|
doLast {
|
||||||
def file = project.file("src/main/res/values/arrays.xml")
|
def file = project.file("src/main/res/values/arrays.xml")
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
app_package_name "org.briarproject.briar.android.screenshot.debug"
|
app_package_name "org.briarproject.briar.android.screenshot.debug"
|
||||||
locales ['en-US']
|
locales ['en-US']
|
||||||
use_tests_in_classes([
|
|
||||||
'org.briarproject.briar.android.login.SetupActivityScreenshotTest',
|
|
||||||
'org.briarproject.briar.android.settings.SettingsActivityScreenshotTest',
|
|
||||||
])
|
|
||||||
app_apk_path "build/outputs/apk/screenshot/debug/briar-android-screenshot-debug.apk"
|
app_apk_path "build/outputs/apk/screenshot/debug/briar-android-screenshot-debug.apk"
|
||||||
tests_apk_path "build/outputs/apk/androidTest/screenshot/debug/briar-android-screenshot-debug-androidTest.apk"
|
tests_apk_path "build/outputs/apk/androidTest/screenshot/debug/briar-android-screenshot-debug-androidTest.apk"
|
||||||
test_instrumentation_runner "org.briarproject.briar.android.test.BriarTestRunner"
|
test_instrumentation_runner "org.briarproject.briar.android.BriarTestRunner"
|
||||||
|
reinstall_app = true
|
||||||
|
exit_on_test_failure = true
|
||||||
@@ -4,4 +4,8 @@ adb shell am broadcast -a com.android.systemui.demo -e command enter
|
|||||||
adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
|
adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
|
||||||
adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100
|
adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100
|
||||||
adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show
|
adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show
|
||||||
adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337
|
adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337
|
||||||
|
|
||||||
|
# workaround for Android Pie hidden API Espresso bug
|
||||||
|
adb shell settings put global hidden_api_policy_pre_p_apps 1
|
||||||
|
adb shell settings put global hidden_api_policy_p_apps 1
|
||||||
|
|||||||
@@ -28,3 +28,5 @@
|
|||||||
|
|
||||||
# Emoji
|
# Emoji
|
||||||
-keep class com.vanniktech.emoji.**
|
-keep class com.vanniktech.emoji.**
|
||||||
|
|
||||||
|
-keepclasseswithmembers public class android.support.v7.widget.RecyclerView { *; }
|
||||||
|
|||||||
@@ -12,4 +12,5 @@
|
|||||||
-keep class junit.** { *; }
|
-keep class junit.** { *; }
|
||||||
-dontwarn junit.**
|
-dontwarn junit.**
|
||||||
|
|
||||||
-dontwarn org.briarproject.briar.android.BriarTestComponentApplication
|
-dontwarn org.briarproject.briar.android.**
|
||||||
|
-dontwarn org.briarproject.bramble.**
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ public class BriarTestComponentApplication extends BriarApplicationImpl {
|
|||||||
@Override
|
@Override
|
||||||
protected AndroidComponent createApplicationComponent() {
|
protected AndroidComponent createApplicationComponent() {
|
||||||
AndroidComponent component = DaggerBriarUiTestComponent.builder()
|
AndroidComponent component = DaggerBriarUiTestComponent.builder()
|
||||||
.appModule(new AppModule(this)).build();
|
.testAppModule(new TestAppModule(this)).build();
|
||||||
// We need to load the eager singletons directly after making the
|
// We need to load the eager singletons directly after making the
|
||||||
// dependency graphs
|
// dependency graphs
|
||||||
BrambleCoreModule.initEagerSingletons(component);
|
BrambleCoreModule.initEagerSingletons(component);
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package org.briarproject.briar.android.test;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.test.runner.AndroidJUnitRunner;
|
import android.support.test.runner.AndroidJUnitRunner;
|
||||||
|
|
||||||
import org.briarproject.briar.android.BriarTestComponentApplication;
|
|
||||||
|
|
||||||
public class BriarTestRunner extends AndroidJUnitRunner {
|
public class BriarTestRunner extends AndroidJUnitRunner {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -13,8 +11,8 @@ public class BriarTestRunner extends AndroidJUnitRunner {
|
|||||||
Context context)
|
Context context)
|
||||||
throws InstantiationException, IllegalAccessException,
|
throws InstantiationException, IllegalAccessException,
|
||||||
ClassNotFoundException {
|
ClassNotFoundException {
|
||||||
return super.newApplication(cl, BriarTestComponentApplication.class.getName(),
|
return super.newApplication(cl,
|
||||||
context);
|
BriarTestComponentApplication.class.getName(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public abstract class UiTest {
|
||||||
|
|
||||||
|
protected final String USERNAME =
|
||||||
|
getTargetContext().getString(R.string.screenshot_alice);
|
||||||
|
protected static final String PASSWORD = "123456";
|
||||||
|
|
||||||
|
protected final BriarUiTestComponent alice;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected AccountManager accountManager;
|
||||||
|
@Inject
|
||||||
|
protected LifecycleManager lifecycleManager;
|
||||||
|
|
||||||
|
public UiTest() {
|
||||||
|
BriarTestComponentApplication app =
|
||||||
|
(BriarTestComponentApplication) getTargetContext()
|
||||||
|
.getApplicationContext();
|
||||||
|
alice = (BriarUiTestComponent) app.getApplicationComponent();
|
||||||
|
inject(alice);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void inject(BriarUiTestComponent component);
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
protected class CleanAccountTestRule<A extends Activity>
|
||||||
|
extends IntentsTestRule<A> {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Runnable runnable;
|
||||||
|
|
||||||
|
public CleanAccountTestRule(Class<A> activityClass) {
|
||||||
|
super(activityClass);
|
||||||
|
this.runnable = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this if you need to run code before launching the activity.
|
||||||
|
* Note: You need to use {@link #launchActivity(Intent)} yourself
|
||||||
|
* to start the activity.
|
||||||
|
*/
|
||||||
|
public CleanAccountTestRule(Class<A> activityClass, Runnable runnable) {
|
||||||
|
super(activityClass, false, false);
|
||||||
|
this.runnable = runnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void beforeActivityLaunched() {
|
||||||
|
super.beforeActivityLaunched();
|
||||||
|
accountManager.deleteAccount();
|
||||||
|
accountManager.createAccount(USERNAME, PASSWORD);
|
||||||
|
if (runnable != null) {
|
||||||
|
Intent serviceIntent =
|
||||||
|
new Intent(getTargetContext(), BriarService.class);
|
||||||
|
getTargetContext().startService(serviceIntent);
|
||||||
|
try {
|
||||||
|
lifecycleManager.waitForStartup();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.test;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.support.test.espresso.PerformException;
|
import android.support.test.espresso.PerformException;
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package org.briarproject.briar.android.login;
|
|
||||||
|
|
||||||
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
|
||||||
import android.support.test.uiautomator.UiDevice;
|
|
||||||
import android.support.test.uiautomator.UiObject;
|
|
||||||
import android.support.test.uiautomator.UiSelector;
|
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
|
||||||
import org.briarproject.briar.android.BriarUiTestComponent;
|
|
||||||
import org.briarproject.briar.android.test.ScreenshotTest;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
|
||||||
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
|
||||||
import static android.support.test.espresso.Espresso.onView;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.click;
|
|
||||||
import static android.support.test.espresso.action.ViewActions.typeText;
|
|
||||||
import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
|
||||||
import static android.support.test.espresso.intent.Intents.intended;
|
|
||||||
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
|
||||||
import static android.support.test.runner.lifecycle.Stage.PAUSED;
|
|
||||||
import static junit.framework.Assert.assertTrue;
|
|
||||||
import static org.briarproject.briar.android.test.ViewActions.waitForActivity;
|
|
||||||
import static org.briarproject.briar.android.test.ViewActions.waitUntilMatches;
|
|
||||||
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
|
|
||||||
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class SetupActivityScreenshotTest extends ScreenshotTest {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public IntentsTestRule<SetupActivity> testRule =
|
|
||||||
new IntentsTestRule<SetupActivity>(SetupActivity.class) {
|
|
||||||
@Override
|
|
||||||
protected void beforeActivityLaunched() {
|
|
||||||
super.beforeActivityLaunched();
|
|
||||||
accountManager.deleteAccount();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void inject(BriarUiTestComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createAccount() throws Exception {
|
|
||||||
// Enter username
|
|
||||||
onView(withText(R.string.setup_title))
|
|
||||||
.check(matches(isDisplayed()));
|
|
||||||
onView(withId(R.id.nickname_entry))
|
|
||||||
.check(matches(isDisplayed()))
|
|
||||||
.perform(typeText(USERNAME));
|
|
||||||
onView(withId(R.id.nickname_entry))
|
|
||||||
.perform(waitUntilMatches(withText(USERNAME)));
|
|
||||||
|
|
||||||
screenshot("manual_create_account");
|
|
||||||
|
|
||||||
onView(withId(R.id.next))
|
|
||||||
.check(matches(isDisplayed()))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
// Enter password
|
|
||||||
onView(withId(R.id.password_entry))
|
|
||||||
.check(matches(isDisplayed()))
|
|
||||||
.perform(typeText(PASSWORD));
|
|
||||||
onView(withId(R.id.password_confirm))
|
|
||||||
.check(matches(isDisplayed()))
|
|
||||||
.perform(typeText(PASSWORD));
|
|
||||||
onView(withId(R.id.next))
|
|
||||||
.check(matches(isDisplayed()))
|
|
||||||
.perform(click());
|
|
||||||
|
|
||||||
// White-list Doze if needed
|
|
||||||
if (needsDozeWhitelisting(getTargetContext())) {
|
|
||||||
onView(withText(R.string.setup_doze_button))
|
|
||||||
.check(matches(isDisplayed()))
|
|
||||||
.perform(click());
|
|
||||||
UiDevice device = UiDevice.getInstance(getInstrumentation());
|
|
||||||
UiObject allowButton = device.findObject(
|
|
||||||
new UiSelector().className("android.widget.Button")
|
|
||||||
.index(1));
|
|
||||||
allowButton.click();
|
|
||||||
onView(withId(R.id.next))
|
|
||||||
.check(matches(isDisplayed()))
|
|
||||||
.perform(click());
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for OpenDatabaseActivity to show up
|
|
||||||
onView(withId(R.id.progress))
|
|
||||||
.check(matches(isDisplayed()));
|
|
||||||
onView(isRoot())
|
|
||||||
.perform(waitForActivity(testRule.getActivity(), PAUSED));
|
|
||||||
intended(hasComponent(OpenDatabaseActivity.class.getName()));
|
|
||||||
|
|
||||||
assertTrue(accountManager.hasDatabaseKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package org.briarproject.briar.android.test;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.account.AccountManager;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
|
||||||
import org.briarproject.briar.android.BriarTestComponentApplication;
|
|
||||||
import org.briarproject.briar.android.BriarUiTestComponent;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import tools.fastlane.screengrab.Screengrab;
|
|
||||||
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy;
|
|
||||||
import tools.fastlane.screengrab.locale.LocaleTestRule;
|
|
||||||
|
|
||||||
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
|
||||||
import static tools.fastlane.screengrab.Screengrab.setDefaultScreenshotStrategy;
|
|
||||||
|
|
||||||
public abstract class ScreenshotTest {
|
|
||||||
|
|
||||||
@ClassRule
|
|
||||||
public static final LocaleTestRule localeTestRule = new LocaleTestRule();
|
|
||||||
|
|
||||||
protected static final String USERNAME = "Alice";
|
|
||||||
protected static final String PASSWORD = "123456";
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected AccountManager accountManager;
|
|
||||||
@Inject
|
|
||||||
protected LifecycleManager lifecycleManager;
|
|
||||||
|
|
||||||
public ScreenshotTest() {
|
|
||||||
super();
|
|
||||||
setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy());
|
|
||||||
BriarTestComponentApplication app =
|
|
||||||
(BriarTestComponentApplication) getTargetContext()
|
|
||||||
.getApplicationContext();
|
|
||||||
inject((BriarUiTestComponent) app.getApplicationComponent());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void inject(BriarUiTestComponent component);
|
|
||||||
|
|
||||||
protected void screenshot(String name) {
|
|
||||||
try {
|
|
||||||
Screengrab.screenshot(name);
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
if (!e.getMessage().equals("Unable to capture screenshot."))
|
|
||||||
throw e;
|
|
||||||
// The tests should still pass when run from AndroidStudio
|
|
||||||
// without manually granting permissions like fastlane does.
|
|
||||||
Log.w("Screengrab", "Permission to write screenshot is missing.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class CleanAccountTestRule<A extends Activity>
|
|
||||||
extends IntentsTestRule<A> {
|
|
||||||
|
|
||||||
public CleanAccountTestRule(Class<A> activityClass) {
|
|
||||||
super(activityClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void beforeActivityLaunched() {
|
|
||||||
super.beforeActivityLaunched();
|
|
||||||
accountManager.deleteAccount();
|
|
||||||
accountManager.createAccount(USERNAME, PASSWORD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -4,9 +4,7 @@ import org.briarproject.bramble.BrambleAndroidModule;
|
|||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
import org.briarproject.bramble.account.BriarAccountModule;
|
import org.briarproject.bramble.account.BriarAccountModule;
|
||||||
import org.briarproject.briar.BriarCoreModule;
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
import org.briarproject.briar.android.login.SetupActivityScreenshotTest;
|
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivityTest;
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivityTest;
|
||||||
import org.briarproject.briar.android.settings.SettingsActivityScreenshotTest;
|
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
@@ -22,8 +20,6 @@ import dagger.Component;
|
|||||||
})
|
})
|
||||||
public interface BriarUiTestComponent extends AndroidComponent {
|
public interface BriarUiTestComponent extends AndroidComponent {
|
||||||
|
|
||||||
void inject(SetupActivityScreenshotTest test);
|
|
||||||
void inject(NavDrawerActivityTest test);
|
void inject(NavDrawerActivityTest test);
|
||||||
void inject(SettingsActivityScreenshotTest test);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,8 @@ import android.view.Gravity;
|
|||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.BriarUiTestComponent;
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.briarproject.briar.android.UiTest;
|
||||||
import org.briarproject.briar.android.settings.SettingsActivity;
|
import org.briarproject.briar.android.settings.SettingsActivity;
|
||||||
import org.briarproject.briar.android.test.ScreenshotTest;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -23,7 +23,7 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
|||||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class NavDrawerActivityTest extends ScreenshotTest {
|
public class NavDrawerActivityTest extends UiTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public CleanAccountTestRule<NavDrawerActivity> testRule =
|
public CleanAccountTestRule<NavDrawerActivity> testRule =
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.BrambleAndroidModule;
|
||||||
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
|
import org.briarproject.bramble.account.BriarAccountModule;
|
||||||
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
|
import org.briarproject.briar.android.contact.ConversationActivityScreenshotTest;
|
||||||
|
import org.briarproject.briar.android.settings.SettingsActivityScreenshotTest;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Component;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Component(modules = {
|
||||||
|
TestAppModule.class,
|
||||||
|
BriarCoreModule.class,
|
||||||
|
BrambleAndroidModule.class,
|
||||||
|
BriarAccountModule.class,
|
||||||
|
BrambleCoreModule.class
|
||||||
|
})
|
||||||
|
public interface BriarUiTestComponent extends AndroidComponent, FakeDataTestComponent {
|
||||||
|
|
||||||
|
void inject(SetupDataTest test);
|
||||||
|
|
||||||
|
void inject(ConversationActivityScreenshotTest test);
|
||||||
|
void inject(SettingsActivityScreenshotTest test);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||||
|
import org.briarproject.bramble.api.transport.KeyManager;
|
||||||
|
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||||
|
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||||
|
import org.briarproject.bramble.client.ClientModule;
|
||||||
|
import org.briarproject.bramble.contact.ContactModule;
|
||||||
|
import org.briarproject.bramble.crypto.CryptoModule;
|
||||||
|
import org.briarproject.bramble.data.DataModule;
|
||||||
|
import org.briarproject.bramble.db.DatabaseModule;
|
||||||
|
import org.briarproject.bramble.event.EventModule;
|
||||||
|
import org.briarproject.bramble.identity.IdentityModule;
|
||||||
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
|
import org.briarproject.bramble.record.RecordModule;
|
||||||
|
import org.briarproject.bramble.sync.SyncModule;
|
||||||
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
|
import org.briarproject.bramble.test.TestCryptoExecutorModule;
|
||||||
|
import org.briarproject.bramble.test.TestDatabaseModule;
|
||||||
|
import org.briarproject.bramble.test.TestSecureRandomModule;
|
||||||
|
import org.briarproject.bramble.transport.TransportModule;
|
||||||
|
import org.briarproject.bramble.versioning.VersioningModule;
|
||||||
|
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
|
||||||
|
import org.briarproject.briar.client.BriarClientModule;
|
||||||
|
import org.briarproject.briar.messaging.MessagingModule;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Component;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Component(modules = {
|
||||||
|
TestCryptoExecutorModule.class,
|
||||||
|
TestDatabaseModule.class,
|
||||||
|
TestPluginConfigModule.class,
|
||||||
|
TestSecureRandomModule.class,
|
||||||
|
BriarClientModule.class,
|
||||||
|
ClientModule.class,
|
||||||
|
ContactModule.class,
|
||||||
|
CryptoModule.class,
|
||||||
|
DataModule.class,
|
||||||
|
DatabaseModule.class,
|
||||||
|
EventModule.class,
|
||||||
|
IdentityModule.class,
|
||||||
|
LifecycleModule.class,
|
||||||
|
MessagingModule.class,
|
||||||
|
RecordModule.class,
|
||||||
|
SyncModule.class,
|
||||||
|
SystemModule.class,
|
||||||
|
TransportModule.class,
|
||||||
|
VersioningModule.class
|
||||||
|
})
|
||||||
|
interface FakeDataTestComponent {
|
||||||
|
|
||||||
|
void inject(ContactModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(IdentityModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(LifecycleModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(MessagingModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(SyncModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(SystemModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(TransportModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(VersioningModule.EagerSingletons init);
|
||||||
|
|
||||||
|
LifecycleManager getLifecycleManager();
|
||||||
|
|
||||||
|
IdentityManager getIdentityManager();
|
||||||
|
|
||||||
|
ContactManager getContactManager();
|
||||||
|
|
||||||
|
MessagingManager getMessagingManager();
|
||||||
|
|
||||||
|
KeyManager getKeyManager();
|
||||||
|
|
||||||
|
PrivateMessageFactory getPrivateMessageFactory();
|
||||||
|
|
||||||
|
EventBus getEventBus();
|
||||||
|
|
||||||
|
StreamWriterFactory getStreamWriterFactory();
|
||||||
|
|
||||||
|
StreamReaderFactory getStreamReaderFactory();
|
||||||
|
|
||||||
|
SyncSessionFactory getSyncSessionFactory();
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.briar.api.test.TestDataCreator;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import tools.fastlane.screengrab.FalconScreenshotStrategy;
|
||||||
|
import tools.fastlane.screengrab.Screengrab;
|
||||||
|
import tools.fastlane.screengrab.locale.LocaleTestRule;
|
||||||
|
|
||||||
|
public abstract class ScreenshotTest extends UiTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final LocaleTestRule localeTestRule = new LocaleTestRule();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected TestDataCreator testDataCreator;
|
||||||
|
@Inject
|
||||||
|
protected ConnectionRegistry connectionRegistry;
|
||||||
|
@Inject
|
||||||
|
protected Clock clock;
|
||||||
|
|
||||||
|
protected void screenshot(String name, Activity activity) {
|
||||||
|
try {
|
||||||
|
Screengrab.screenshot(name, new FalconScreenshotStrategy(activity));
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
if (!e.getMessage().equals("Unable to capture screenshot."))
|
||||||
|
throw e;
|
||||||
|
// The tests should still pass when run from AndroidStudio
|
||||||
|
// without manually granting permissions like fastlane does.
|
||||||
|
Log.w("Screengrab", "Permission to write screenshot is missing.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long getMinutesAgo(int minutes) {
|
||||||
|
return clock.currentTimeMillis() - minutes * 60 * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,338 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.support.test.uiautomator.UiDevice;
|
||||||
|
import android.support.test.uiautomator.UiObject;
|
||||||
|
import android.support.test.uiautomator.UiSelector;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
|
import org.briarproject.bramble.api.sync.SyncSession;
|
||||||
|
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||||
|
import org.briarproject.bramble.api.transport.KeyManager;
|
||||||
|
import org.briarproject.bramble.api.transport.StreamContext;
|
||||||
|
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||||
|
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||||
|
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||||
|
import org.briarproject.bramble.contact.ContactModule;
|
||||||
|
import org.briarproject.bramble.identity.IdentityModule;
|
||||||
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
|
import org.briarproject.bramble.sync.SyncModule;
|
||||||
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
|
import org.briarproject.bramble.test.TestDatabaseModule;
|
||||||
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.transport.TransportModule;
|
||||||
|
import org.briarproject.bramble.versioning.VersioningModule;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.login.OpenDatabaseActivity;
|
||||||
|
import org.briarproject.briar.android.login.SetupActivity;
|
||||||
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
|
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateMessage;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
|
||||||
|
import org.briarproject.briar.messaging.MessagingModule;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
|
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||||
|
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
||||||
|
import static android.support.test.espresso.Espresso.onView;
|
||||||
|
import static android.support.test.espresso.action.ViewActions.click;
|
||||||
|
import static android.support.test.espresso.action.ViewActions.typeText;
|
||||||
|
import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
||||||
|
import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
|
||||||
|
import static android.support.test.espresso.intent.Intents.intended;
|
||||||
|
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
import static android.support.test.runner.lifecycle.Stage.PAUSED;
|
||||||
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
|
import static org.briarproject.briar.android.TestPluginConfigModule.MAX_LATENCY;
|
||||||
|
import static org.briarproject.briar.android.TestPluginConfigModule.TRANSPORT_ID;
|
||||||
|
import static org.briarproject.briar.android.ViewActions.waitForActivity;
|
||||||
|
import static org.briarproject.briar.android.ViewActions.waitUntilMatches;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class SetupDataTest extends ScreenshotTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public IntentsTestRule<SetupActivity> testRule =
|
||||||
|
new IntentsTestRule<SetupActivity>(SetupActivity.class) {
|
||||||
|
@Override
|
||||||
|
protected void beforeActivityLaunched() {
|
||||||
|
super.beforeActivityLaunched();
|
||||||
|
accountManager.deleteAccount();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private FakeDataTestComponent bob;
|
||||||
|
private final File testDir =
|
||||||
|
getTargetContext().getDir("test", MODE_PRIVATE);
|
||||||
|
private final File bobDir = new File(testDir, "bob");
|
||||||
|
private final SecretKey master = getSecretKey();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void inject(BriarUiTestComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
Log.e("TEST", testDir.getAbsolutePath());
|
||||||
|
Log.e("TEST", "exists: " + testDir.exists());
|
||||||
|
assertTrue(testDir.mkdirs());
|
||||||
|
bob = DaggerFakeDataTestComponent.builder()
|
||||||
|
.testDatabaseModule(new TestDatabaseModule(bobDir)).build();
|
||||||
|
injectEagerSingletons(bob);
|
||||||
|
Log.e("TEST", "built bob");
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
// Stop the lifecycle manager
|
||||||
|
LifecycleManager lifecycleManager = bob.getLifecycleManager();
|
||||||
|
lifecycleManager.stopServices();
|
||||||
|
lifecycleManager.waitForShutdown();
|
||||||
|
|
||||||
|
TestUtils.deleteTestDirectory(testDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void injectEagerSingletons(FakeDataTestComponent component) {
|
||||||
|
component.inject(new ContactModule.EagerSingletons());
|
||||||
|
component.inject(new IdentityModule.EagerSingletons());
|
||||||
|
component.inject(new LifecycleModule.EagerSingletons());
|
||||||
|
component.inject(new MessagingModule.EagerSingletons());
|
||||||
|
component.inject(new SyncModule.EagerSingletons());
|
||||||
|
component.inject(new SystemModule.EagerSingletons());
|
||||||
|
component.inject(new TransportModule.EagerSingletons());
|
||||||
|
component.inject(new VersioningModule.EagerSingletons());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createAccount() throws Exception {
|
||||||
|
// Enter username
|
||||||
|
onView(withText(R.string.setup_title))
|
||||||
|
.check(matches(isDisplayed()));
|
||||||
|
onView(withId(R.id.nickname_entry))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(typeText(USERNAME));
|
||||||
|
onView(withId(R.id.nickname_entry))
|
||||||
|
.perform(waitUntilMatches(withText(USERNAME)));
|
||||||
|
|
||||||
|
screenshot("manual_create_account", testRule.getActivity());
|
||||||
|
|
||||||
|
onView(withId(R.id.next))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
|
||||||
|
// Enter password
|
||||||
|
onView(withId(R.id.password_entry))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(typeText(PASSWORD));
|
||||||
|
onView(withId(R.id.password_confirm))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(typeText(PASSWORD));
|
||||||
|
onView(withId(R.id.next))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
|
||||||
|
// White-list Doze if needed
|
||||||
|
if (needsDozeWhitelisting(getTargetContext())) {
|
||||||
|
onView(withText(R.string.setup_doze_button))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
UiDevice device = UiDevice.getInstance(getInstrumentation());
|
||||||
|
UiObject allowButton = device.findObject(
|
||||||
|
new UiSelector().className("android.widget.Button")
|
||||||
|
.index(1));
|
||||||
|
allowButton.click();
|
||||||
|
onView(withId(R.id.next))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for OpenDatabaseActivity to show up
|
||||||
|
onView(isRoot())
|
||||||
|
.perform(waitForActivity(testRule.getActivity(), PAUSED));
|
||||||
|
intended(hasComponent(OpenDatabaseActivity.class.getName()));
|
||||||
|
|
||||||
|
assertTrue(accountManager.hasDatabaseKey());
|
||||||
|
|
||||||
|
// WIP below
|
||||||
|
|
||||||
|
// wait for OpenDatabaseActivity to go away
|
||||||
|
onView(isRoot())
|
||||||
|
.perform(waitUntilMatches(
|
||||||
|
allOf(withId(R.id.progressBar), not(isDisplayed()))));
|
||||||
|
lifecycleManager.waitForStartup();
|
||||||
|
intended(hasComponent(NavDrawerActivity.class.getName()));
|
||||||
|
|
||||||
|
// close expiry warning
|
||||||
|
onView(withId(R.id.expiryWarningClose))
|
||||||
|
.check(matches(isDisplayed()));
|
||||||
|
onView(withId(R.id.expiryWarningClose))
|
||||||
|
.perform(click());
|
||||||
|
|
||||||
|
LocalAuthor aliceAuthor = alice.identityManager().getLocalAuthor();
|
||||||
|
|
||||||
|
LocalAuthor bobAuthor = bob.getIdentityManager().createLocalAuthor(
|
||||||
|
getTargetContext().getString(R.string.screenshot_bob));
|
||||||
|
bob.getIdentityManager().registerLocalAuthor(bobAuthor);
|
||||||
|
// Start the lifecycle manager
|
||||||
|
bob.getLifecycleManager().startServices(getSecretKey());
|
||||||
|
bob.getLifecycleManager().waitForStartup();
|
||||||
|
long timestamp = clock.currentTimeMillis();
|
||||||
|
// Bob adds Alice as a contact
|
||||||
|
ContactId aliceContactId = bob.getContactManager()
|
||||||
|
.addContact(aliceAuthor, bobAuthor.getId(), master,
|
||||||
|
timestamp, true, true, true);
|
||||||
|
// Alice adds Bob as a contact
|
||||||
|
ContactId bobContactId = alice.contactManager()
|
||||||
|
.addContact(bobAuthor, aliceAuthor.getId(), master,
|
||||||
|
timestamp, false, true, true);
|
||||||
|
|
||||||
|
// TODO figure out how many messages
|
||||||
|
read(alice, bobContactId, write(bob, aliceContactId));
|
||||||
|
read(bob, aliceContactId, write(alice, bobContactId));
|
||||||
|
read(alice, bobContactId, write(bob, aliceContactId));
|
||||||
|
read(bob, aliceContactId, write(alice, bobContactId));
|
||||||
|
read(alice, bobContactId, write(bob, aliceContactId));
|
||||||
|
read(bob, aliceContactId, write(alice, bobContactId));
|
||||||
|
read(alice, bobContactId, write(bob, aliceContactId));
|
||||||
|
read(bob, aliceContactId, write(alice, bobContactId));
|
||||||
|
read(alice, bobContactId, write(bob, aliceContactId));
|
||||||
|
read(bob, aliceContactId, write(alice, bobContactId));
|
||||||
|
read(alice, bobContactId, write(bob, aliceContactId));
|
||||||
|
read(bob, aliceContactId, write(alice, bobContactId));
|
||||||
|
read(alice, bobContactId, write(bob, aliceContactId));
|
||||||
|
|
||||||
|
sendMessage(bob, aliceContactId);
|
||||||
|
read(alice, bobContactId, write(bob, aliceContactId));
|
||||||
|
|
||||||
|
onView(isRoot())
|
||||||
|
.perform(waitUntilMatches(withText(bobAuthor.getName())));
|
||||||
|
onView(withId(R.id.recyclerView))
|
||||||
|
.perform(actionOnItemAtPosition(0, click()));
|
||||||
|
onView(isRoot())
|
||||||
|
.perform(waitUntilMatches(withText(R.string.screenshot_message_2)));
|
||||||
|
|
||||||
|
assertEquals(1,
|
||||||
|
alice.conversationManager().getGroupCount(bobContactId).getMsgCount());
|
||||||
|
|
||||||
|
Thread.sleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendMessage(FakeDataTestComponent device, ContactId contactId)
|
||||||
|
throws Exception {
|
||||||
|
// Send Bob a message
|
||||||
|
MessagingManager messagingManager = device.getMessagingManager();
|
||||||
|
GroupId groupId = messagingManager.getConversationId(contactId);
|
||||||
|
PrivateMessageFactory privateMessageFactory =
|
||||||
|
device.getPrivateMessageFactory();
|
||||||
|
PrivateMessage message = privateMessageFactory.createPrivateMessage(
|
||||||
|
groupId, getMinutesAgo(3),
|
||||||
|
getTargetContext().getString(R.string.screenshot_message_2));
|
||||||
|
messagingManager.addLocalMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void read(FakeDataTestComponent device,
|
||||||
|
ContactId contactId, byte[] stream) throws Exception {
|
||||||
|
// Read and recognise the tag
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(stream);
|
||||||
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
|
int read = in.read(tag);
|
||||||
|
assertEquals(tag.length, read);
|
||||||
|
KeyManager keyManager = device.getKeyManager();
|
||||||
|
StreamContext ctx = keyManager.getStreamContext(TRANSPORT_ID, tag);
|
||||||
|
assertNotNull(ctx);
|
||||||
|
// Create a stream reader
|
||||||
|
StreamReaderFactory streamReaderFactory =
|
||||||
|
device.getStreamReaderFactory();
|
||||||
|
InputStream streamReader = streamReaderFactory.createStreamReader(
|
||||||
|
in, ctx);
|
||||||
|
// Create an incoming sync session
|
||||||
|
SyncSessionFactory syncSessionFactory = device.getSyncSessionFactory();
|
||||||
|
SyncSession session = syncSessionFactory.createIncomingSession(
|
||||||
|
contactId, streamReader);
|
||||||
|
// Read whatever needs to be read
|
||||||
|
session.run();
|
||||||
|
streamReader.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] write(FakeDataTestComponent device,
|
||||||
|
ContactId contactId) throws Exception {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
// Get a stream context
|
||||||
|
KeyManager keyManager = device.getKeyManager();
|
||||||
|
StreamContext ctx = keyManager.getStreamContext(contactId,
|
||||||
|
TRANSPORT_ID);
|
||||||
|
assertNotNull(ctx);
|
||||||
|
// Create a stream writer
|
||||||
|
StreamWriterFactory streamWriterFactory =
|
||||||
|
device.getStreamWriterFactory();
|
||||||
|
StreamWriter streamWriter =
|
||||||
|
streamWriterFactory.createStreamWriter(out, ctx);
|
||||||
|
// Create an outgoing sync session
|
||||||
|
SyncSessionFactory syncSessionFactory = device.getSyncSessionFactory();
|
||||||
|
SyncSession session = syncSessionFactory.createSimplexOutgoingSession(
|
||||||
|
contactId, MAX_LATENCY, streamWriter);
|
||||||
|
// Write whatever needs to be written
|
||||||
|
session.run();
|
||||||
|
streamWriter.sendEndOfStream();
|
||||||
|
// Return the contents of the stream
|
||||||
|
return out.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
private void createTestDataExceptions()
|
||||||
|
throws DbException, FormatException {
|
||||||
|
String bobName =
|
||||||
|
getTargetContext().getString(R.string.screenshot_bob);
|
||||||
|
Contact bob = testDataCreator.addContact(bobName);
|
||||||
|
|
||||||
|
String bobHi = getTargetContext()
|
||||||
|
.getString(R.string.screenshot_message_1);
|
||||||
|
long bobTime = getMinutesAgo(2);
|
||||||
|
testDataCreator.addPrivateMessage(bob, bobHi, bobTime, true);
|
||||||
|
|
||||||
|
String aliceHi = getTargetContext()
|
||||||
|
.getString(R.string.screenshot_message_2);
|
||||||
|
long aliceTime = getMinutesAgo(1);
|
||||||
|
testDataCreator.addPrivateMessage(bob, aliceHi, aliceTime, false);
|
||||||
|
|
||||||
|
String bobHi2 = getTargetContext()
|
||||||
|
.getString(R.string.screenshot_message_3);
|
||||||
|
long bobTime2 = getMinutesAgo(0);
|
||||||
|
testDataCreator.addPrivateMessage(bob, bobHi2, bobTime2, true);
|
||||||
|
|
||||||
|
connectionRegistry.registerConnection(bob.getId(), ID, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.StrictMode;
|
||||||
|
|
||||||
|
import com.vanniktech.emoji.RecentEmoji;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.reporting.DevConfig;
|
||||||
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
import org.briarproject.briar.android.account.LockManagerImpl;
|
||||||
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
|
import org.briarproject.briar.api.android.DozeWatchdog;
|
||||||
|
import org.briarproject.briar.api.android.LockManager;
|
||||||
|
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
|
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
|
||||||
|
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
|
||||||
|
|
||||||
|
@Module(includes = TestPluginConfigModule.class)
|
||||||
|
public class TestAppModule {
|
||||||
|
|
||||||
|
static class EagerSingletons {
|
||||||
|
@Inject
|
||||||
|
AndroidNotificationManager androidNotificationManager;
|
||||||
|
@Inject
|
||||||
|
NetworkUsageLogger networkUsageLogger;
|
||||||
|
@Inject
|
||||||
|
DozeWatchdog dozeWatchdog;
|
||||||
|
@Inject
|
||||||
|
RecentEmoji recentEmoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Application application;
|
||||||
|
|
||||||
|
public TestAppModule(Application application) {
|
||||||
|
this.application = application;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
Application providesApplication() {
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
DatabaseConfig provideDatabaseConfig(Application app) {
|
||||||
|
//FIXME: StrictMode
|
||||||
|
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskReads();
|
||||||
|
StrictMode.allowThreadDiskWrites();
|
||||||
|
File dbDir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
|
||||||
|
File keyDir = app.getApplicationContext().getDir("key", MODE_PRIVATE);
|
||||||
|
StrictMode.setThreadPolicy(tp);
|
||||||
|
return new AndroidDatabaseConfig(dbDir, keyDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
DevConfig provideDevConfig(Application app, CryptoComponent crypto) {
|
||||||
|
@NotNullByDefault
|
||||||
|
DevConfig devConfig = new DevConfig() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublicKey getDevPublicKey() {
|
||||||
|
try {
|
||||||
|
return crypto.getMessageKeyParser().parsePublicKey(
|
||||||
|
StringUtils.fromHexString(DEV_PUBLIC_KEY_HEX));
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDevOnionAddress() {
|
||||||
|
return DEV_ONION_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getReportDir() {
|
||||||
|
return AndroidUtils.getReportDir(app.getApplicationContext());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return devConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
SharedPreferences provideSharedPreferences(Application app) {
|
||||||
|
// FIXME unify this with getDefaultSharedPreferences()
|
||||||
|
return app.getSharedPreferences("db", MODE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
AndroidNotificationManager provideAndroidNotificationManager(
|
||||||
|
LifecycleManager lifecycleManager, EventBus eventBus,
|
||||||
|
AndroidNotificationManagerImpl notificationManager) {
|
||||||
|
lifecycleManager.registerService(notificationManager);
|
||||||
|
eventBus.addListener(notificationManager);
|
||||||
|
return notificationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
ScreenFilterMonitor provideScreenFilterMonitor(
|
||||||
|
LifecycleManager lifecycleManager,
|
||||||
|
ScreenFilterMonitorImpl screenFilterMonitor) {
|
||||||
|
lifecycleManager.registerService(screenFilterMonitor);
|
||||||
|
return screenFilterMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
NetworkUsageLogger provideNetworkUsageLogger(
|
||||||
|
LifecycleManager lifecycleManager) {
|
||||||
|
NetworkUsageLogger networkUsageLogger = new NetworkUsageLogger();
|
||||||
|
lifecycleManager.registerService(networkUsageLogger);
|
||||||
|
return networkUsageLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
DozeWatchdog provideDozeWatchdog(LifecycleManager lifecycleManager) {
|
||||||
|
DozeWatchdogImpl dozeWatchdog = new DozeWatchdogImpl(application);
|
||||||
|
lifecycleManager.registerService(dozeWatchdog);
|
||||||
|
return dozeWatchdog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
LockManager provideLockManager(LifecycleManager lifecycleManager,
|
||||||
|
EventBus eventBus, LockManagerImpl lockManager) {
|
||||||
|
lifecycleManager.registerService(lockManager);
|
||||||
|
eventBus.addListener(lockManager);
|
||||||
|
return lockManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
RecentEmoji provideRecentEmoji(LifecycleManager lifecycleManager,
|
||||||
|
RecentEmojiImpl recentEmoji) {
|
||||||
|
lifecycleManager.registerClient(recentEmoji);
|
||||||
|
return recentEmoji;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
||||||
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class TestPluginConfigModule {
|
||||||
|
|
||||||
|
public static final TransportId TRANSPORT_ID = getTransportId();
|
||||||
|
public static final int MAX_LATENCY = 2 * 60 * 1000; // 2 minutes
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
private final SimplexPluginFactory simplex = new SimplexPluginFactory() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransportId getId() {
|
||||||
|
return TRANSPORT_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxLatency() {
|
||||||
|
return MAX_LATENCY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public SimplexPlugin createPlugin(SimplexPluginCallback callback) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
PluginConfig providePluginConfig() {
|
||||||
|
@NotNullByDefault
|
||||||
|
PluginConfig pluginConfig = new PluginConfig() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
|
return singletonList(simplex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldPoll() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return pluginConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package org.briarproject.briar.android.contact;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.support.test.rule.ActivityTestRule;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.briarproject.briar.android.ScreenshotTest;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||||
|
import static android.support.test.espresso.Espresso.onView;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
import static org.briarproject.briar.android.ViewActions.waitUntilMatches;
|
||||||
|
import static org.briarproject.briar.android.contact.ConversationActivity.CONTACT_ID;
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ConversationActivityScreenshotTest extends ScreenshotTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ActivityTestRule<ConversationActivity> testRule =
|
||||||
|
new ActivityTestRule<>(ConversationActivity.class, false, false);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void inject(BriarUiTestComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void messaging() throws Exception {
|
||||||
|
Context targetContext = getInstrumentation().getTargetContext();
|
||||||
|
Intent intent = new Intent(targetContext, ConversationActivity.class);
|
||||||
|
intent.putExtra(CONTACT_ID, 1);
|
||||||
|
testRule.launchActivity(intent);
|
||||||
|
|
||||||
|
onView(withId(R.id.conversationView))
|
||||||
|
.perform(waitUntilMatches(allOf(
|
||||||
|
withText(R.string.screenshot_message_3),
|
||||||
|
isCompletelyDisplayed())
|
||||||
|
));
|
||||||
|
|
||||||
|
screenshot("manual_messaging", testRule.getActivity());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,14 +2,15 @@ package org.briarproject.briar.android.settings;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.support.test.espresso.contrib.DrawerActions;
|
import android.support.test.espresso.contrib.DrawerActions;
|
||||||
|
import android.support.test.rule.ActivityTestRule;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.BriarUiTestComponent;
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.briarproject.briar.android.ScreenshotTest;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
import org.briarproject.briar.android.test.ScreenshotTest;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -26,15 +27,15 @@ import static android.support.test.espresso.matcher.ViewMatchers.withChild;
|
|||||||
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
|
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
import static org.briarproject.briar.android.test.ViewActions.waitUntilMatches;
|
import static org.briarproject.briar.android.ViewActions.waitUntilMatches;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public CleanAccountTestRule<SettingsActivity> testRule =
|
public ActivityTestRule<SettingsActivity> testRule =
|
||||||
new CleanAccountTestRule<>(SettingsActivity.class);
|
new ActivityTestRule<>(SettingsActivity.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void inject(BriarUiTestComponent component) {
|
protected void inject(BriarUiTestComponent component) {
|
||||||
@@ -46,7 +47,7 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
|||||||
onView(withText(R.string.settings_button))
|
onView(withText(R.string.settings_button))
|
||||||
.check(matches(isDisplayed()));
|
.check(matches(isDisplayed()));
|
||||||
|
|
||||||
screenshot("manual_dark_theme_settings");
|
screenshot("manual_dark_theme_settings", testRule.getActivity());
|
||||||
|
|
||||||
// switch to dark theme
|
// switch to dark theme
|
||||||
onView(withText(R.string.pref_theme_title))
|
onView(withText(R.string.pref_theme_title))
|
||||||
@@ -56,10 +57,20 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
|||||||
.check(matches(isDisplayed()))
|
.check(matches(isDisplayed()))
|
||||||
.perform(click());
|
.perform(click());
|
||||||
|
|
||||||
// open nav drawer and remove expiry warning
|
openNavDrawer();
|
||||||
openNavDrawer(true);
|
|
||||||
|
|
||||||
screenshot("manual_dark_theme_nav_drawer");
|
screenshot("manual_dark_theme_nav_drawer", testRule.getActivity());
|
||||||
|
|
||||||
|
// switch to back to light theme
|
||||||
|
onView(withText(R.string.settings_button))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
onView(withText(R.string.pref_theme_title))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
onView(withText(R.string.pref_theme_light))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -83,12 +94,11 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
|||||||
.check(matches(isDisplayed()))
|
.check(matches(isDisplayed()))
|
||||||
.check(matches(isEnabled()));
|
.check(matches(isEnabled()));
|
||||||
|
|
||||||
screenshot("manual_app_lock");
|
screenshot("manual_app_lock", testRule.getActivity());
|
||||||
|
|
||||||
// no more expiry warning to remove, because sharedprefs cached?
|
openNavDrawer();
|
||||||
openNavDrawer(false);
|
|
||||||
|
|
||||||
screenshot("manual_app_lock_nav_drawer");
|
screenshot("manual_app_lock_nav_drawer", testRule.getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -104,23 +114,15 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
|||||||
.check(matches(isDisplayed()))
|
.check(matches(isDisplayed()))
|
||||||
.perform(waitUntilMatches(isEnabled()));
|
.perform(waitUntilMatches(isEnabled()));
|
||||||
|
|
||||||
screenshot("manual_tor_settings");
|
screenshot("manual_tor_settings", testRule.getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openNavDrawer(boolean expiry) {
|
private void openNavDrawer() {
|
||||||
// start main activity
|
// start main activity
|
||||||
Intent i =
|
Intent i =
|
||||||
new Intent(testRule.getActivity(), NavDrawerActivity.class);
|
new Intent(testRule.getActivity(), NavDrawerActivity.class);
|
||||||
testRule.getActivity().startActivity(i);
|
testRule.getActivity().startActivity(i);
|
||||||
|
|
||||||
// close expiry warning
|
|
||||||
if (expiry) {
|
|
||||||
onView(withId(R.id.expiryWarningClose))
|
|
||||||
.check(matches(isDisplayed()));
|
|
||||||
onView(withId(R.id.expiryWarningClose))
|
|
||||||
.perform(click());
|
|
||||||
}
|
|
||||||
|
|
||||||
// open navigation drawer
|
// open navigation drawer
|
||||||
onView(withId(R.id.drawer_layout))
|
onView(withId(R.id.drawer_layout))
|
||||||
.check(matches(isClosed(Gravity.START)))
|
.check(matches(isClosed(Gravity.START)))
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
|
|
||||||
@@ -11,24 +10,9 @@ import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
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.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.PluginConfig;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
|
||||||
import org.briarproject.bramble.api.reporting.DevConfig;
|
import org.briarproject.bramble.api.reporting.DevConfig;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.api.system.ResourceProvider;
|
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
|
||||||
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
|
|
||||||
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
|
||||||
import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory;
|
|
||||||
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
|
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.android.account.LockManagerImpl;
|
import org.briarproject.briar.android.account.LockManagerImpl;
|
||||||
@@ -39,25 +23,18 @@ import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import javax.net.SocketFactory;
|
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
|
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS;
|
||||||
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
|
import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX;
|
||||||
|
|
||||||
@Module
|
@Module(includes = PluginConfigModule.class)
|
||||||
public class AppModule {
|
public class AppModule {
|
||||||
|
|
||||||
static class EagerSingletons {
|
static class EagerSingletons {
|
||||||
@@ -95,47 +72,6 @@ public class AppModule {
|
|||||||
return new AndroidDatabaseConfig(dbDir, keyDir);
|
return new AndroidDatabaseConfig(dbDir, keyDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
|
|
||||||
@Scheduler ScheduledExecutorService scheduler,
|
|
||||||
AndroidExecutor androidExecutor, SecureRandom random,
|
|
||||||
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
|
||||||
Application app, NetworkManager networkManager,
|
|
||||||
LocationUtils locationUtils, EventBus eventBus,
|
|
||||||
ResourceProvider resourceProvider,
|
|
||||||
CircumventionProvider circumventionProvider, Clock clock) {
|
|
||||||
Context appContext = app.getApplicationContext();
|
|
||||||
DuplexPluginFactory bluetooth =
|
|
||||||
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
|
||||||
appContext, random, eventBus, backoffFactory);
|
|
||||||
DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor,
|
|
||||||
scheduler, appContext, networkManager, locationUtils, eventBus,
|
|
||||||
torSocketFactory, backoffFactory, resourceProvider,
|
|
||||||
circumventionProvider, clock);
|
|
||||||
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
|
||||||
eventBus, backoffFactory, appContext);
|
|
||||||
Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);
|
|
||||||
@NotNullByDefault
|
|
||||||
PluginConfig pluginConfig = new PluginConfig() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
|
||||||
return duplex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
|
||||||
return emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldPoll() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return pluginConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
DevConfig provideDevConfig(Application app, CryptoComponent crypto) {
|
DevConfig provideDevConfig(Application app, CryptoComponent crypto) {
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
|
||||||
|
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
||||||
|
import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory;
|
||||||
|
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class PluginConfigModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
|
||||||
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
|
AndroidExecutor androidExecutor, SecureRandom random,
|
||||||
|
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
||||||
|
Application app, NetworkManager networkManager,
|
||||||
|
LocationUtils locationUtils, EventBus eventBus,
|
||||||
|
ResourceProvider resourceProvider,
|
||||||
|
CircumventionProvider circumventionProvider, Clock clock) {
|
||||||
|
Context appContext = app.getApplicationContext();
|
||||||
|
DuplexPluginFactory bluetooth =
|
||||||
|
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
||||||
|
appContext, random, eventBus, backoffFactory);
|
||||||
|
DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor,
|
||||||
|
scheduler, appContext, networkManager, locationUtils, eventBus,
|
||||||
|
torSocketFactory, backoffFactory, resourceProvider,
|
||||||
|
circumventionProvider, clock);
|
||||||
|
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
||||||
|
eventBus, backoffFactory, appContext);
|
||||||
|
Collection<DuplexPluginFactory> duplex = asList(bluetooth, tor, lan);
|
||||||
|
@NotNullByDefault
|
||||||
|
PluginConfig pluginConfig = new PluginConfig() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
||||||
|
return duplex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldPoll() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return pluginConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -68,6 +68,11 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||||||
public void onCreate(@Nullable Bundle state) {
|
public void onCreate(@Nullable Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
|
|
||||||
|
// WARNING: When removing this or making it possible to turn it off,
|
||||||
|
// we need a solution for the app lock feature.
|
||||||
|
// When the app is locked by a timeout and FLAG_SECURE is not
|
||||||
|
// set, the app content becomes visible briefly before the
|
||||||
|
// unlock screen is shown.
|
||||||
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
||||||
|
|
||||||
AndroidComponent applicationComponent =
|
AndroidComponent applicationComponent =
|
||||||
|
|||||||
@@ -480,4 +480,20 @@
|
|||||||
<string name="lock_is_locked">Briar is locked</string>
|
<string name="lock_is_locked">Briar is locked</string>
|
||||||
<string name="lock_tap_to_unlock">Tap to unlock</string>
|
<string name="lock_tap_to_unlock">Tap to unlock</string>
|
||||||
|
|
||||||
|
<!-- Screenshots -->
|
||||||
|
|
||||||
|
<!-- This is a name to be used in screenshots. Feel free to change it to a local name. -->
|
||||||
|
<string name="screenshot_alice">Alice</string>
|
||||||
|
<!-- This is a name to be used in screenshots. Feel free to change it to a local name. -->
|
||||||
|
<string name="screenshot_bob">Bob</string>
|
||||||
|
<!-- This is a name to be used in screenshots. Feel free to change it to a local name. -->
|
||||||
|
<string name="screenshot_carol">Carol</string>
|
||||||
|
<!-- This is a message to be used in screenshots. Please use the same translation for Bob! -->
|
||||||
|
<string name="screenshot_message_1">Hi Bob!</string>
|
||||||
|
<!-- This is a message to be used in screenshots. Please use the same translation for Alice! -->
|
||||||
|
<string name="screenshot_message_2">Hi Alice! Thanks for telling me about Briar!</string>
|
||||||
|
<!-- This is a message to be used in screenshots. -->
|
||||||
|
<string name="screenshot_message_3">No problem, hope you like it 😀</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ dependencyVerification {
|
|||||||
'com.google.zxing:core:3.3.0:core-3.3.0.jar:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
|
'com.google.zxing:core:3.3.0:core-3.3.0.jar:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
|
||||||
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
|
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
|
||||||
'com.ibm.icu:icu4j:53.1:icu4j-53.1.jar:e37a4467bac5cdeb02c5c4b8e5063d2f4e67b69e3c7df6d6b610f13185572bab',
|
'com.ibm.icu:icu4j:53.1:icu4j-53.1.jar:e37a4467bac5cdeb02c5c4b8e5063d2f4e67b69e3c7df6d6b610f13185572bab',
|
||||||
|
'com.jraska:falcon:1.0.4:falcon-1.0.4.aar:6114a48d8b3814f75fc69b5e84dc087c1254883874eae8a36bd778979800630a',
|
||||||
'com.squareup:javawriter:2.1.1:javawriter-2.1.1.jar:f699823d0081f69cbb676c1845ea222e0ada79bc88a53e5d22d8bd02d328f57e',
|
'com.squareup:javawriter:2.1.1:javawriter-2.1.1.jar:f699823d0081f69cbb676c1845ea222e0ada79bc88a53e5d22d8bd02d328f57e',
|
||||||
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
|
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
|
||||||
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
|
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
|
||||||
@@ -171,7 +172,7 @@ dependencyVerification {
|
|||||||
'org.robolectric:shadows-framework:3.8:shadows-framework-3.8.jar:83548db7249edf1af87e1a1f4d8f4eec3e85d6220161da601e6f6398476911b2',
|
'org.robolectric:shadows-framework:3.8:shadows-framework-3.8.jar:83548db7249edf1af87e1a1f4d8f4eec3e85d6220161da601e6f6398476911b2',
|
||||||
'org.robolectric:shadows-support-v4:3.3.2:shadows-support-v4-3.3.2.jar:6f689264738266e70fe08db7c04b7b5a75155994f4e3f7f311960d90486bf005',
|
'org.robolectric:shadows-support-v4:3.3.2:shadows-support-v4-3.3.2.jar:6f689264738266e70fe08db7c04b7b5a75155994f4e3f7f311960d90486bf005',
|
||||||
'org.robolectric:utils:3.8:utils-3.8.jar:e945d04d40e37554e02d4be1bc3abf9bede45375c843aa36d10ccb6b63edbf34',
|
'org.robolectric:utils:3.8:utils-3.8.jar:e945d04d40e37554e02d4be1bc3abf9bede45375c843aa36d10ccb6b63edbf34',
|
||||||
'tools.fastlane:screengrab:1.1.0:screengrab-1.1.0.aar:03ce3868ee8a0082d14e7a1de0999f91531c0cc794392688beb08ee9bc4495fd',
|
'tools.fastlane:screengrab:1.2.0:screengrab-1.2.0.aar:af4ee23bb06f94404d3ab18e2ea69db8265539fc8da29f9ee45b7e472684ba83',
|
||||||
'uk.co.samuelwall:material-tap-target-prompt:2.8.0:material-tap-target-prompt-2.8.0.aar:ac70770c05bbc4675a1d5712c0e53d46ee4fa961b74947589fce50d8003065ec',
|
'uk.co.samuelwall:material-tap-target-prompt:2.8.0:material-tap-target-prompt-2.8.0.aar:ac70770c05bbc4675a1d5712c0e53d46ee4fa961b74947589fce50d8003065ec',
|
||||||
'xmlpull:xmlpull:1.1.3.1:xmlpull-1.1.3.1.jar:34e08ee62116071cbb69c0ed70d15a7a5b208d62798c59f2120bb8929324cb63',
|
'xmlpull:xmlpull:1.1.3.1:xmlpull-1.1.3.1.jar:34e08ee62116071cbb69c0ed70d15a7a5b208d62798c59f2120bb8929324cb63',
|
||||||
'xpp3:xpp3_min:1.1.4c:xpp3_min-1.1.4c.jar:bfc90e9e32d0eab1f397fb974b5f150a815188382ac41f372a7149d5bc178008',
|
'xpp3:xpp3_min:1.1.4c:xpp3_min-1.1.4c.jar:bfc90e9e32d0eab1f397fb974b5f150a815188382ac41f372a7149d5bc178008',
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
package org.briarproject.briar.api.test;
|
package org.briarproject.briar.api.test;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface TestDataCreator {
|
public interface TestDataCreator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create fake test data on the DatabaseExecutor
|
* Create fake test data on the IoExecutor
|
||||||
*
|
*
|
||||||
* @param numContacts Number of contacts to create. Must be >= 1
|
* @param numContacts Number of contacts to create. Must be >= 1
|
||||||
* @param numPrivateMsgs Number of private messages to create for each
|
* @param numPrivateMsgs Number of private messages to create for each
|
||||||
@@ -18,4 +22,11 @@ public interface TestDataCreator {
|
|||||||
void createTestData(int numContacts, int numPrivateMsgs, int numBlogPosts,
|
void createTestData(int numContacts, int numPrivateMsgs, int numBlogPosts,
|
||||||
int numForums, int numForumPosts);
|
int numForums, int numForumPosts);
|
||||||
|
|
||||||
|
@IoExecutor
|
||||||
|
Contact addContact(String name) throws DbException;
|
||||||
|
|
||||||
|
@IoExecutor
|
||||||
|
void addPrivateMessage(Contact contact, String body, long time,
|
||||||
|
boolean local) throws DbException, FormatException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,11 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||||
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.BluetoothConstants;
|
import org.briarproject.bramble.api.plugin.BluetoothConstants;
|
||||||
import org.briarproject.bramble.api.plugin.LanTcpConstants;
|
import org.briarproject.bramble.api.plugin.LanTcpConstants;
|
||||||
import org.briarproject.bramble.api.plugin.TorConstants;
|
import org.briarproject.bramble.api.plugin.TorConstants;
|
||||||
@@ -59,6 +61,7 @@ import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
|||||||
import static org.briarproject.briar.test.TestData.AUTHOR_NAMES;
|
import static org.briarproject.briar.test.TestData.AUTHOR_NAMES;
|
||||||
import static org.briarproject.briar.test.TestData.GROUP_NAMES;
|
import static org.briarproject.briar.test.TestData.GROUP_NAMES;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public class TestDataCreatorImpl implements TestDataCreator {
|
public class TestDataCreatorImpl implements TestDataCreator {
|
||||||
|
|
||||||
private final Logger LOG =
|
private final Logger LOG =
|
||||||
@@ -147,17 +150,17 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
List<Contact> contacts = new ArrayList<>(numContacts);
|
List<Contact> contacts = new ArrayList<>(numContacts);
|
||||||
LocalAuthor localAuthor = identityManager.getLocalAuthor();
|
LocalAuthor localAuthor = identityManager.getLocalAuthor();
|
||||||
for (int i = 0; i < numContacts; i++) {
|
for (int i = 0; i < numContacts; i++) {
|
||||||
Contact contact = addRandomContact(localAuthor);
|
LocalAuthor author = getRandomAuthor();
|
||||||
|
Contact contact = addContact(localAuthor.getId(), author);
|
||||||
contacts.add(contact);
|
contacts.add(contact);
|
||||||
}
|
}
|
||||||
return contacts;
|
return contacts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Contact addRandomContact(LocalAuthor localAuthor)
|
private Contact addContact(AuthorId localAuthorId, LocalAuthor author)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
|
||||||
// prepare to add contact
|
// prepare to add contact
|
||||||
LocalAuthor author = getRandomAuthor();
|
|
||||||
SecretKey secretKey = getSecretKey();
|
SecretKey secretKey = getSecretKey();
|
||||||
long timestamp = clock.currentTimeMillis();
|
long timestamp = clock.currentTimeMillis();
|
||||||
boolean verified = random.nextBoolean();
|
boolean verified = random.nextBoolean();
|
||||||
@@ -170,7 +173,7 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
ContactId contactId = contactManager
|
ContactId contactId = contactManager
|
||||||
.addContact(txn, author, localAuthor.getId(), secretKey,
|
.addContact(txn, author, localAuthorId, secretKey,
|
||||||
timestamp, true, verified, true);
|
timestamp, true, verified, true);
|
||||||
transportPropertyManager.addRemoteProperties(txn, contactId, props);
|
transportPropertyManager.addRemoteProperties(txn, contactId, props);
|
||||||
contact = db.getContact(txn, contactId);
|
contact = db.getContact(txn, contactId);
|
||||||
@@ -187,14 +190,23 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
return contact;
|
return contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalAuthor getRandomAuthor() {
|
@Override
|
||||||
int i = random.nextInt(AUTHOR_NAMES.length);
|
public Contact addContact(String name) throws DbException {
|
||||||
String authorName = AUTHOR_NAMES[i];
|
LocalAuthor localAuthor = identityManager.getLocalAuthor();
|
||||||
|
return addContact(localAuthor.getId(), getAuthor(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalAuthor getAuthor(String name) {
|
||||||
KeyPair keyPair = cryptoComponent.generateSignatureKeyPair();
|
KeyPair keyPair = cryptoComponent.generateSignatureKeyPair();
|
||||||
byte[] publicKey = keyPair.getPublic().getEncoded();
|
byte[] publicKey = keyPair.getPublic().getEncoded();
|
||||||
byte[] privateKey = keyPair.getPrivate().getEncoded();
|
byte[] privateKey = keyPair.getPrivate().getEncoded();
|
||||||
return authorFactory.createLocalAuthor(authorName, publicKey,
|
return authorFactory.createLocalAuthor(name, publicKey, privateKey);
|
||||||
privateKey);
|
}
|
||||||
|
|
||||||
|
private LocalAuthor getRandomAuthor() {
|
||||||
|
int i = random.nextInt(AUTHOR_NAMES.length);
|
||||||
|
String authorName = AUTHOR_NAMES[i];
|
||||||
|
return getAuthor(authorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKey getSecretKey() {
|
private SecretKey getSecretKey() {
|
||||||
@@ -286,7 +298,7 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
Group group = messagingManager.getContactGroup(contact);
|
Group group = messagingManager.getContactGroup(contact);
|
||||||
for (int i = 0; i < numPrivateMsgs; i++) {
|
for (int i = 0; i < numPrivateMsgs; i++) {
|
||||||
try {
|
try {
|
||||||
createPrivateMessage(group.getId(), i);
|
createRandomPrivateMessage(group.getId(), i);
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -298,14 +310,18 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPrivateMessage(GroupId groupId, int num)
|
private void createRandomPrivateMessage(GroupId groupId, int num)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
long timestamp = clock.currentTimeMillis() - num * 60 * 1000;
|
long timestamp = clock.currentTimeMillis() - num * 60 * 1000;
|
||||||
String body = getRandomText();
|
String body = getRandomText();
|
||||||
|
boolean local = random.nextBoolean();
|
||||||
|
createPrivateMessage(groupId, body, timestamp, local);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createPrivateMessage(GroupId groupId, String body,
|
||||||
|
long timestamp, boolean local) throws DbException, FormatException {
|
||||||
PrivateMessage m = privateMessageFactory
|
PrivateMessage m = privateMessageFactory
|
||||||
.createPrivateMessage(groupId, timestamp, body);
|
.createPrivateMessage(groupId, timestamp, body);
|
||||||
|
|
||||||
boolean local = random.nextBoolean();
|
|
||||||
BdfDictionary meta = new BdfDictionary();
|
BdfDictionary meta = new BdfDictionary();
|
||||||
meta.put("timestamp", timestamp);
|
meta.put("timestamp", timestamp);
|
||||||
meta.put("local", local);
|
meta.put("local", local);
|
||||||
@@ -322,6 +338,13 @@ public class TestDataCreatorImpl implements TestDataCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addPrivateMessage(Contact contact, String body, long time,
|
||||||
|
boolean local) throws DbException, FormatException {
|
||||||
|
Group group = messagingManager.getContactGroup(contact);
|
||||||
|
createPrivateMessage(group.getId(), body, time, local);
|
||||||
|
}
|
||||||
|
|
||||||
private void createBlogPosts(List<Contact> contacts, int numBlogPosts)
|
private void createBlogPosts(List<Contact> contacts, int numBlogPosts)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
for (int i = 0; i < numBlogPosts; i++) {
|
for (int i = 0; i < numBlogPosts; i++) {
|
||||||
|
|||||||
@@ -12,10 +12,8 @@ import org.jmock.Expectations;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH;
|
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH;
|
||||||
@@ -30,9 +28,10 @@ public class MessageEncoderTest extends BrambleMockTestCase {
|
|||||||
new MessageEncoderImpl(clientHelper, messageFactory);
|
new MessageEncoderImpl(clientHelper, messageFactory);
|
||||||
|
|
||||||
private final GroupId groupId = new GroupId(getRandomId());
|
private final GroupId groupId = new GroupId(getRandomId());
|
||||||
private final Message message = getMessage(groupId, MAX_MESSAGE_LENGTH);
|
private final Message message =
|
||||||
|
getMessage(groupId, MAX_MESSAGE_BODY_LENGTH);
|
||||||
private final long timestamp = message.getTimestamp();
|
private final long timestamp = message.getTimestamp();
|
||||||
private final byte[] body = getRandomBytes(MAX_MESSAGE_BODY_LENGTH);
|
private final byte[] body = message.getBody();
|
||||||
private final Author author = getAuthor();
|
private final Author author = getAuthor();
|
||||||
private final BdfList authorList = new BdfList();
|
private final BdfList authorList = new BdfList();
|
||||||
private final String text = getRandomString(MAX_REQUEST_MESSAGE_LENGTH);
|
private final String text = getRandomString(MAX_REQUEST_MESSAGE_LENGTH);
|
||||||
|
|||||||
Reference in New Issue
Block a user