Wrapped the system clock in an interface so it can be replaced in tests.

This commit is contained in:
akwizgran
2012-09-06 17:21:03 +01:00
parent 67eb9d6f93
commit 960ead0247
26 changed files with 115 additions and 53 deletions

View File

@@ -0,0 +1,11 @@
package net.sf.briar.clock;
import com.google.inject.AbstractModule;
public class ClockModule extends AbstractModule {
@Override
protected void configure() {
bind(Clock.class).to(SystemClock.class);
}
}

View File

@@ -61,6 +61,7 @@ import net.sf.briar.api.protocol.TransportIndex;
import net.sf.briar.api.protocol.TransportUpdate;
import net.sf.briar.api.transport.ConnectionContext;
import net.sf.briar.api.transport.ConnectionWindow;
import net.sf.briar.clock.Clock;
import net.sf.briar.util.ByteUtils;
import com.google.inject.Inject;
@@ -103,6 +104,7 @@ DatabaseCleaner.Callback {
private final DatabaseCleaner cleaner;
private final ShutdownManager shutdown;
private final PacketFactory packetFactory;
private final Clock clock;
private final Collection<DatabaseListener> listeners =
new CopyOnWriteArrayList<DatabaseListener>();
@@ -117,11 +119,13 @@ DatabaseCleaner.Callback {
@Inject
DatabaseComponentImpl(Database<T> db, DatabaseCleaner cleaner,
ShutdownManager shutdown, PacketFactory packetFactory) {
ShutdownManager shutdown, PacketFactory packetFactory,
Clock clock) {
this.db = db;
this.cleaner = cleaner;
this.shutdown = shutdown;
this.packetFactory = packetFactory;
this.clock = clock;
}
public void open(boolean resume) throws DbException, IOException {
@@ -632,7 +636,7 @@ DatabaseCleaner.Callback {
try {
T txn = db.startTransaction();
try {
timestamp = System.currentTimeMillis() - 1;
timestamp = clock.currentTimeMillis() - 1;
holes = db.getVisibleHoles(txn, c, timestamp);
subs = db.getVisibleSubscriptions(txn, c, timestamp);
expiry = db.getExpiryTime(txn);
@@ -652,7 +656,7 @@ DatabaseCleaner.Callback {
}
private boolean updateIsDue(long sent) {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
return now - sent >= DatabaseConstants.MAX_UPDATE_INTERVAL;
}
@@ -686,7 +690,7 @@ DatabaseCleaner.Callback {
T txn = db.startTransaction();
try {
transports = db.getLocalTransports(txn);
timestamp = System.currentTimeMillis();
timestamp = clock.currentTimeMillis();
db.setTransportsSent(txn, c, timestamp);
db.commitTransaction(txn);
} catch(DbException e) {
@@ -1328,7 +1332,7 @@ DatabaseCleaner.Callback {
try {
if(!p.equals(db.getLocalProperties(txn, t))) {
db.setLocalProperties(txn, t, p);
db.setTransportsModified(txn, System.currentTimeMillis());
db.setTransportsModified(txn, clock.currentTimeMillis());
changed = true;
}
db.commitTransaction(txn);
@@ -1606,7 +1610,7 @@ DatabaseCleaner.Callback {
public boolean shouldCheckFreeSpace() {
synchronized(spaceLock) {
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
if(bytesStoredSinceLastCheck > MAX_BYTES_BETWEEN_SPACE_CHECKS
|| now - timeOfLastCheck > MAX_MS_BETWEEN_SPACE_CHECKS) {
bytesStoredSinceLastCheck = 0L;

View File

@@ -15,6 +15,7 @@ import net.sf.briar.api.protocol.GroupFactory;
import net.sf.briar.api.protocol.PacketFactory;
import net.sf.briar.api.transport.ConnectionContextFactory;
import net.sf.briar.api.transport.ConnectionWindowFactory;
import net.sf.briar.clock.Clock;
import net.sf.briar.util.BoundedExecutor;
import com.google.inject.AbstractModule;
@@ -51,16 +52,16 @@ public class DatabaseModule extends AbstractModule {
@DatabasePassword Password password, @DatabaseMaxSize long maxSize,
ConnectionContextFactory connectionContextFactory,
ConnectionWindowFactory connectionWindowFactory,
GroupFactory groupFactory) {
GroupFactory groupFactory, Clock clock) {
return new H2Database(dir, password, maxSize, connectionContextFactory,
connectionWindowFactory, groupFactory);
connectionWindowFactory, groupFactory, clock);
}
@Provides @Singleton
DatabaseComponent getDatabaseComponent(Database<Connection> db,
DatabaseCleaner cleaner, ShutdownManager shutdown,
PacketFactory packetFactory) {
PacketFactory packetFactory, Clock clock) {
return new DatabaseComponentImpl<Connection>(db, cleaner, shutdown,
packetFactory);
packetFactory, clock);
}
}

View File

@@ -16,6 +16,7 @@ import net.sf.briar.api.db.DbException;
import net.sf.briar.api.protocol.GroupFactory;
import net.sf.briar.api.transport.ConnectionContextFactory;
import net.sf.briar.api.transport.ConnectionWindowFactory;
import net.sf.briar.clock.Clock;
import org.apache.commons.io.FileSystemUtils;
@@ -40,9 +41,9 @@ class H2Database extends JdbcDatabase {
@DatabaseMaxSize long maxSize,
ConnectionContextFactory connectionContextFactory,
ConnectionWindowFactory connectionWindowFactory,
GroupFactory groupFactory) {
GroupFactory groupFactory, Clock clock) {
super(connectionContextFactory, connectionWindowFactory, groupFactory,
HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE);
clock, HASH_TYPE, BINARY_TYPE, COUNTER_TYPE, SECRET_TYPE);
home = new File(dir, "db");
this.password = password;
url = "jdbc:h2:split:" + home.getPath()

View File

@@ -42,6 +42,7 @@ import net.sf.briar.api.transport.ConnectionContext;
import net.sf.briar.api.transport.ConnectionContextFactory;
import net.sf.briar.api.transport.ConnectionWindow;
import net.sf.briar.api.transport.ConnectionWindowFactory;
import net.sf.briar.clock.Clock;
import net.sf.briar.util.FileUtils;
/**
@@ -275,6 +276,7 @@ abstract class JdbcDatabase implements Database<Connection> {
private final ConnectionContextFactory connectionContextFactory;
private final ConnectionWindowFactory connectionWindowFactory;
private final GroupFactory groupFactory;
private final Clock clock;
// Different database libraries use different names for certain types
private final String hashType, binaryType, counterType, secretType;
@@ -288,11 +290,12 @@ abstract class JdbcDatabase implements Database<Connection> {
JdbcDatabase(ConnectionContextFactory connectionContextFactory,
ConnectionWindowFactory connectionWindowFactory,
GroupFactory groupFactory, String hashType, String binaryType,
String counterType, String secretType) {
GroupFactory groupFactory, Clock clock, String hashType,
String binaryType, String counterType, String secretType) {
this.connectionContextFactory = connectionContextFactory;
this.connectionWindowFactory = connectionWindowFactory;
this.groupFactory = groupFactory;
this.clock = clock;
this.hashType = hashType;
this.binaryType = binaryType;
this.counterType = counterType;
@@ -654,7 +657,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ps = txn.prepareStatement(sql);
ps.setBytes(1, b.getBytes());
ps.setInt(2, c.getInt());
ps.setLong(3, System.currentTimeMillis());
ps.setLong(3, clock.currentTimeMillis());
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
ps.close();
@@ -741,7 +744,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.setBytes(1, g.getId().getBytes());
ps.setString(2, g.getName());
ps.setBytes(3, g.getPublicKey());
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
ps.setLong(4, now);
int affected = ps.executeUpdate();
if(affected != 1) throw new DbStateException();
@@ -2230,7 +2233,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ResultSet rs = null;
try {
// Remove the group ID from the visibility lists
long now = System.currentTimeMillis();
long now = clock.currentTimeMillis();
String sql = "SELECT contactId, nextId FROM visibilities"
+ " WHERE groupId = ?";
ps = txn.prepareStatement(sql);
@@ -2342,7 +2345,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ps = txn.prepareStatement(sql);
if(nextId == null) ps.setNull(1, Types.BINARY); // At the tail
else ps.setBytes(1, nextId); // At the head or in the middle
ps.setLong(2, System.currentTimeMillis());
ps.setLong(2, clock.currentTimeMillis());
ps.setInt(3, c.getInt());
ps.setBytes(4, g.getBytes());
affected = ps.executeUpdate();

View File

@@ -12,8 +12,6 @@ import java.security.KeyPair;
import java.util.Arrays;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.crypto.MessageDigest;
import net.sf.briar.api.crypto.PseudoRandom;
@@ -32,6 +30,8 @@ import net.sf.briar.api.serial.Writer;
import net.sf.briar.api.serial.WriterFactory;
import net.sf.briar.util.ByteUtils;
import com.google.inject.Inject;
class InvitationStarterImpl implements InvitationStarter {
private static final String TIMED_OUT = "INVITATION_TIMED_OUT";

View File

@@ -35,6 +35,7 @@ import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.api.protocol.TransportIndex;
import net.sf.briar.api.transport.ConnectionDispatcher;
import net.sf.briar.api.ui.UiCallback;
import net.sf.briar.clock.Clock;
import com.google.inject.Inject;
@@ -54,6 +55,7 @@ class PluginManagerImpl implements PluginManager {
};
private final ExecutorService pluginExecutor;
private final Clock clock;
private final DatabaseComponent db;
private final Poller poller;
private final ConnectionDispatcher dispatcher;
@@ -63,9 +65,10 @@ class PluginManagerImpl implements PluginManager {
@Inject
PluginManagerImpl(@PluginExecutor ExecutorService pluginExecutor,
DatabaseComponent db, Poller poller,
Clock clock, DatabaseComponent db, Poller poller,
ConnectionDispatcher dispatcher, UiCallback uiCallback) {
this.pluginExecutor = pluginExecutor;
this.clock = clock;
this.db = db;
this.poller = poller;
this.dispatcher = dispatcher;
@@ -88,7 +91,7 @@ class PluginManagerImpl implements PluginManager {
(SimplexPluginFactory) c.newInstance();
SimplexCallback callback = new SimplexCallback();
SimplexPlugin plugin = factory.createPlugin(pluginExecutor,
callback);
clock, callback);
if(plugin == null) {
if(LOG.isLoggable(Level.INFO)) {
LOG.info(factory.getClass().getSimpleName()
@@ -128,7 +131,7 @@ class PluginManagerImpl implements PluginManager {
(DuplexPluginFactory) c.newInstance();
DuplexCallback callback = new DuplexCallback();
DuplexPlugin plugin = factory.createPlugin(pluginExecutor,
callback);
clock, callback);
if(plugin == null) {
if(LOG.isLoggable(Level.INFO)) {
LOG.info(factory.getClass().getSimpleName()

View File

@@ -32,6 +32,7 @@ import net.sf.briar.api.plugins.duplex.DuplexPlugin;
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
import net.sf.briar.api.protocol.TransportId;
import net.sf.briar.clock.Clock;
import net.sf.briar.util.OsUtils;
import net.sf.briar.util.StringUtils;
@@ -47,6 +48,7 @@ class BluetoothPlugin implements DuplexPlugin {
Logger.getLogger(BluetoothPlugin.class.getName());
private final Executor pluginExecutor;
private final Clock clock;
private final DuplexPluginCallback callback;
private final long pollingInterval;
private final Object discoveryLock = new Object();
@@ -58,9 +60,10 @@ class BluetoothPlugin implements DuplexPlugin {
private LocalDevice localDevice = null; // Locking: this
private StreamConnectionNotifier socket = null; // Locking: this
BluetoothPlugin(@PluginExecutor Executor pluginExecutor,
BluetoothPlugin(@PluginExecutor Executor pluginExecutor, Clock clock,
DuplexPluginCallback callback, long pollingInterval) {
this.pluginExecutor = pluginExecutor;
this.clock = clock;
this.callback = callback;
this.pollingInterval = pollingInterval;
scheduler = Executors.newScheduledThreadPool(0);
@@ -360,9 +363,9 @@ class BluetoothPlugin implements DuplexPlugin {
}
DiscoveryAgent discoveryAgent = localDevice.getDiscoveryAgent();
// Try to discover the other party until the invitation times out
long end = System.currentTimeMillis() + c.getTimeout();
long end = clock.currentTimeMillis() + c.getTimeout();
String url = null;
while(url == null && System.currentTimeMillis() < end) {
while(url == null && clock.currentTimeMillis() < end) {
InvitationListener listener = new InvitationListener(discoveryAgent,
c.getUuid());
// FIXME: Avoid making alien calls with a lock held

View File

@@ -6,13 +6,15 @@ import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
import net.sf.briar.clock.Clock;
public class BluetoothPluginFactory implements DuplexPluginFactory {
private static final long POLLING_INTERVAL = 3L * 60L * 1000L; // 3 mins
public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
DuplexPluginCallback callback) {
return new BluetoothPlugin(pluginExecutor, callback, POLLING_INTERVAL);
Clock clock, DuplexPluginCallback callback) {
return new BluetoothPlugin(pluginExecutor, clock, callback,
POLLING_INTERVAL);
}
}

View File

@@ -5,10 +5,11 @@ import java.util.concurrent.Executor;
import net.sf.briar.api.plugins.simplex.SimplexPlugin;
import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
import net.sf.briar.clock.Clock;
public class GmailPluginFactory implements SimplexPluginFactory {
public SimplexPlugin createPlugin(Executor pluginExecutor,
public SimplexPlugin createPlugin(Executor pluginExecutor, Clock clock,
SimplexPluginCallback callback) {
return new GmailPlugin(pluginExecutor, callback);

View File

@@ -6,6 +6,7 @@ import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.plugins.simplex.SimplexPlugin;
import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
import net.sf.briar.api.plugins.simplex.SimplexPluginFactory;
import net.sf.briar.clock.Clock;
import net.sf.briar.util.OsUtils;
public class RemovableDrivePluginFactory implements SimplexPluginFactory {
@@ -13,7 +14,7 @@ public class RemovableDrivePluginFactory implements SimplexPluginFactory {
private static final long POLLING_INTERVAL = 10L * 1000L; // 10 seconds
public SimplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
SimplexPluginCallback callback) {
Clock clock, SimplexPluginCallback callback) {
RemovableDriveFinder finder;
RemovableDriveMonitor monitor;
if(OsUtils.isLinux()) {

View File

@@ -6,13 +6,14 @@ import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
import net.sf.briar.clock.Clock;
public class SimpleSocketPluginFactory implements DuplexPluginFactory {
private static final long POLLING_INTERVAL = 5L * 60L * 1000L; // 5 mins
public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
DuplexPluginCallback callback) {
Clock clock, DuplexPluginCallback callback) {
return new SimpleSocketPlugin(pluginExecutor, callback,
POLLING_INTERVAL);
}

View File

@@ -6,13 +6,14 @@ import net.sf.briar.api.plugins.PluginExecutor;
import net.sf.briar.api.plugins.duplex.DuplexPlugin;
import net.sf.briar.api.plugins.duplex.DuplexPluginCallback;
import net.sf.briar.api.plugins.duplex.DuplexPluginFactory;
import net.sf.briar.clock.Clock;
public class TorPluginFactory implements DuplexPluginFactory {
private static final long POLLING_INTERVAL = 15L * 60L * 1000L; // 15 mins
public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
DuplexPluginCallback callback) {
Clock clock, DuplexPluginCallback callback) {
return new TorPlugin(pluginExecutor, callback, POLLING_INTERVAL);
}
}