From 960ead0247de2e7cd9cea8861bae27ba63c7415d Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Thu, 6 Sep 2012 17:21:03 +0100
Subject: [PATCH] Wrapped the system clock in an interface so it can be
 replaced in tests.

---
 .../api/plugins/duplex/DuplexPluginFactory.java  |  4 +++-
 .../plugins/simplex/SimplexPluginFactory.java    |  4 +++-
 api/net/sf/briar/clock/Clock.java                | 11 +++++++++++
 api/net/sf/briar/clock/SystemClock.java          |  9 +++++++++
 components/net/sf/briar/clock/ClockModule.java   | 11 +++++++++++
 .../net/sf/briar/db/DatabaseComponentImpl.java   | 16 ++++++++++------
 components/net/sf/briar/db/DatabaseModule.java   |  9 +++++----
 components/net/sf/briar/db/H2Database.java       |  5 +++--
 components/net/sf/briar/db/JdbcDatabase.java     | 15 +++++++++------
 .../sf/briar/plugins/InvitationStarterImpl.java  |  4 ++--
 .../net/sf/briar/plugins/PluginManagerImpl.java  |  9 ++++++---
 .../briar/plugins/bluetooth/BluetoothPlugin.java |  9 ++++++---
 .../bluetooth/BluetoothPluginFactory.java        |  6 ++++--
 .../briar/plugins/email/GmailPluginFactory.java  |  3 ++-
 .../file/RemovableDrivePluginFactory.java        |  3 ++-
 .../socket/SimpleSocketPluginFactory.java        |  3 ++-
 .../sf/briar/plugins/tor/TorPluginFactory.java   |  3 ++-
 test/net/sf/briar/ProtocolIntegrationTest.java   |  3 ++-
 .../sf/briar/db/DatabaseComponentImplTest.java   |  3 ++-
 test/net/sf/briar/db/H2DatabaseTest.java         |  3 ++-
 .../sf/briar/plugins/PluginManagerImplTest.java  |  7 ++++---
 .../plugins/bluetooth/BluetoothClientTest.java   |  3 ++-
 .../plugins/bluetooth/BluetoothServerTest.java   |  3 ++-
 .../briar/plugins/email/GmailPluginTester.java   | 13 +++++--------
 .../simplex/SimplexConnectionReadWriteTest.java  |  6 ++++--
 .../sf/briar/transport/ConnectionWriterTest.java |  3 ++-
 26 files changed, 115 insertions(+), 53 deletions(-)
 create mode 100644 api/net/sf/briar/clock/Clock.java
 create mode 100644 api/net/sf/briar/clock/SystemClock.java
 create mode 100644 components/net/sf/briar/clock/ClockModule.java

diff --git a/api/net/sf/briar/api/plugins/duplex/DuplexPluginFactory.java b/api/net/sf/briar/api/plugins/duplex/DuplexPluginFactory.java
index 5d9609ff90..c790dc9b6e 100644
--- a/api/net/sf/briar/api/plugins/duplex/DuplexPluginFactory.java
+++ b/api/net/sf/briar/api/plugins/duplex/DuplexPluginFactory.java
@@ -2,8 +2,10 @@ package net.sf.briar.api.plugins.duplex;
 
 import java.util.concurrent.Executor;
 
+import net.sf.briar.clock.Clock;
+
 public interface DuplexPluginFactory {
 
-	DuplexPlugin createPlugin(Executor pluginExecutor,
+	DuplexPlugin createPlugin(Executor pluginExecutor, Clock clock,
 			DuplexPluginCallback callback);
 }
diff --git a/api/net/sf/briar/api/plugins/simplex/SimplexPluginFactory.java b/api/net/sf/briar/api/plugins/simplex/SimplexPluginFactory.java
index d114ec376b..1da8775230 100644
--- a/api/net/sf/briar/api/plugins/simplex/SimplexPluginFactory.java
+++ b/api/net/sf/briar/api/plugins/simplex/SimplexPluginFactory.java
@@ -2,8 +2,10 @@ package net.sf.briar.api.plugins.simplex;
 
 import java.util.concurrent.Executor;
 
+import net.sf.briar.clock.Clock;
+
 public interface SimplexPluginFactory {
 
-	SimplexPlugin createPlugin(Executor pluginExecutor,
+	SimplexPlugin createPlugin(Executor pluginExecutor, Clock clock,
 			SimplexPluginCallback callback);
 }
diff --git a/api/net/sf/briar/clock/Clock.java b/api/net/sf/briar/clock/Clock.java
new file mode 100644
index 0000000000..701d11412b
--- /dev/null
+++ b/api/net/sf/briar/clock/Clock.java
@@ -0,0 +1,11 @@
+package net.sf.briar.clock;
+
+/**
+ * An interface for time-related system functions that allows them to be
+ * replaced for testing.
+ */
+public interface Clock {
+
+	/** @see {@link java.lang.System#currentTimeMillis()} */
+	long currentTimeMillis();
+}
diff --git a/api/net/sf/briar/clock/SystemClock.java b/api/net/sf/briar/clock/SystemClock.java
new file mode 100644
index 0000000000..460b147e89
--- /dev/null
+++ b/api/net/sf/briar/clock/SystemClock.java
@@ -0,0 +1,9 @@
+package net.sf.briar.clock;
+
+/** Default clock implementation. */
+public class SystemClock implements Clock {
+
+	public long currentTimeMillis() {
+		return System.currentTimeMillis();
+	}
+}
diff --git a/components/net/sf/briar/clock/ClockModule.java b/components/net/sf/briar/clock/ClockModule.java
new file mode 100644
index 0000000000..42ad9217f9
--- /dev/null
+++ b/components/net/sf/briar/clock/ClockModule.java
@@ -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);
+	}
+}
diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java
index c960329610..ad21a135f0 100644
--- a/components/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/components/net/sf/briar/db/DatabaseComponentImpl.java
@@ -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;
diff --git a/components/net/sf/briar/db/DatabaseModule.java b/components/net/sf/briar/db/DatabaseModule.java
index 9fa851d6d1..9c2b4b0210 100644
--- a/components/net/sf/briar/db/DatabaseModule.java
+++ b/components/net/sf/briar/db/DatabaseModule.java
@@ -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);
 	}
 }
diff --git a/components/net/sf/briar/db/H2Database.java b/components/net/sf/briar/db/H2Database.java
index 4b975e2e29..42bc5622d0 100644
--- a/components/net/sf/briar/db/H2Database.java
+++ b/components/net/sf/briar/db/H2Database.java
@@ -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()
diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java
index 7e4daaec8f..8d5d87eaeb 100644
--- a/components/net/sf/briar/db/JdbcDatabase.java
+++ b/components/net/sf/briar/db/JdbcDatabase.java
@@ -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();
diff --git a/components/net/sf/briar/plugins/InvitationStarterImpl.java b/components/net/sf/briar/plugins/InvitationStarterImpl.java
index 0df6981e2f..f67be85716 100644
--- a/components/net/sf/briar/plugins/InvitationStarterImpl.java
+++ b/components/net/sf/briar/plugins/InvitationStarterImpl.java
@@ -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";
diff --git a/components/net/sf/briar/plugins/PluginManagerImpl.java b/components/net/sf/briar/plugins/PluginManagerImpl.java
index ab05b6de48..0da6aef13f 100644
--- a/components/net/sf/briar/plugins/PluginManagerImpl.java
+++ b/components/net/sf/briar/plugins/PluginManagerImpl.java
@@ -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()
diff --git a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
index 9e8e58b6a7..2d295bc939 100644
--- a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
+++ b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
@@ -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
diff --git a/components/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java b/components/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java
index 615c3c66d9..1b138c0041 100644
--- a/components/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java
+++ b/components/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java
@@ -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);
 	}
 }
diff --git a/components/net/sf/briar/plugins/email/GmailPluginFactory.java b/components/net/sf/briar/plugins/email/GmailPluginFactory.java
index 244a89373d..4b912e28d0 100644
--- a/components/net/sf/briar/plugins/email/GmailPluginFactory.java
+++ b/components/net/sf/briar/plugins/email/GmailPluginFactory.java
@@ -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);
diff --git a/components/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java b/components/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
index 689efc8502..6a453f559b 100644
--- a/components/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
+++ b/components/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
@@ -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()) {
diff --git a/components/net/sf/briar/plugins/socket/SimpleSocketPluginFactory.java b/components/net/sf/briar/plugins/socket/SimpleSocketPluginFactory.java
index d8499fb32e..9ee36419eb 100644
--- a/components/net/sf/briar/plugins/socket/SimpleSocketPluginFactory.java
+++ b/components/net/sf/briar/plugins/socket/SimpleSocketPluginFactory.java
@@ -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);
 	}
diff --git a/components/net/sf/briar/plugins/tor/TorPluginFactory.java b/components/net/sf/briar/plugins/tor/TorPluginFactory.java
index e7caf6aa19..78cd3d5e92 100644
--- a/components/net/sf/briar/plugins/tor/TorPluginFactory.java
+++ b/components/net/sf/briar/plugins/tor/TorPluginFactory.java
@@ -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);
 	}
 }
diff --git a/test/net/sf/briar/ProtocolIntegrationTest.java b/test/net/sf/briar/ProtocolIntegrationTest.java
index 35942d2dfc..5f74283171 100644
--- a/test/net/sf/briar/ProtocolIntegrationTest.java
+++ b/test/net/sf/briar/ProtocolIntegrationTest.java
@@ -46,6 +46,7 @@ import net.sf.briar.api.transport.ConnectionReader;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
+import net.sf.briar.clock.ClockModule;
 import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.db.DatabaseModule;
 import net.sf.briar.lifecycle.LifecycleModule;
@@ -83,7 +84,7 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 
 	public ProtocolIntegrationTest() throws Exception {
 		super();
-		Injector i = Guice.createInjector(new CryptoModule(),
+		Injector i = Guice.createInjector(new ClockModule(), new CryptoModule(),
 				new DatabaseModule(), new LifecycleModule(),
 				new ProtocolModule(), new SerialModule(),
 				new TestDatabaseModule(), new SimplexProtocolModule(),
diff --git a/test/net/sf/briar/db/DatabaseComponentImplTest.java b/test/net/sf/briar/db/DatabaseComponentImplTest.java
index ccab25ee69..474be1e37a 100644
--- a/test/net/sf/briar/db/DatabaseComponentImplTest.java
+++ b/test/net/sf/briar/db/DatabaseComponentImplTest.java
@@ -9,6 +9,7 @@ import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
 import net.sf.briar.api.lifecycle.ShutdownManager;
 import net.sf.briar.api.protocol.PacketFactory;
+import net.sf.briar.clock.SystemClock;
 import net.sf.briar.db.DatabaseCleaner.Callback;
 
 import org.jmock.Expectations;
@@ -145,6 +146,6 @@ public class DatabaseComponentImplTest extends DatabaseComponentTest {
 			Database<T> database, DatabaseCleaner cleaner,
 			ShutdownManager shutdown, PacketFactory packetFactory) {
 		return new DatabaseComponentImpl<T>(database, cleaner, shutdown,
-				packetFactory);
+				packetFactory, new SystemClock());
 	}
 }
diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java
index 671cc5905b..2c743f7b72 100644
--- a/test/net/sf/briar/db/H2DatabaseTest.java
+++ b/test/net/sf/briar/db/H2DatabaseTest.java
@@ -42,6 +42,7 @@ 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.api.transport.TransportConstants;
+import net.sf.briar.clock.SystemClock;
 import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.lifecycle.LifecycleModule;
 import net.sf.briar.protocol.ProtocolModule;
@@ -1847,7 +1848,7 @@ public class H2DatabaseTest extends BriarTestCase {
 	private Database<Connection> open(boolean resume) throws Exception {
 		Database<Connection> db = new H2Database(testDir, password, MAX_SIZE,
 				connectionContextFactory, connectionWindowFactory,
-				groupFactory);
+				groupFactory, new SystemClock());
 		db.open(resume);
 		return db;
 	}
diff --git a/test/net/sf/briar/plugins/PluginManagerImplTest.java b/test/net/sf/briar/plugins/PluginManagerImplTest.java
index feda37c3db..c1c1a30f90 100644
--- a/test/net/sf/briar/plugins/PluginManagerImplTest.java
+++ b/test/net/sf/briar/plugins/PluginManagerImplTest.java
@@ -13,6 +13,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.SystemClock;
 
 import org.jmock.Expectations;
 import org.jmock.Mockery;
@@ -27,7 +28,7 @@ public class PluginManagerImplTest extends BriarTestCase {
 		final DatabaseComponent db = context.mock(DatabaseComponent.class);
 		final Poller poller = context.mock(Poller.class);
 		final ConnectionDispatcher dispatcher =
-			context.mock(ConnectionDispatcher.class);
+				context.mock(ConnectionDispatcher.class);
 		final UiCallback uiCallback = context.mock(UiCallback.class);
 		final AtomicInteger index = new AtomicInteger(0);
 		context.checking(new Expectations() {{
@@ -47,8 +48,8 @@ public class PluginManagerImplTest extends BriarTestCase {
 			oneOf(poller).stop();
 		}});
 		ExecutorService executor = Executors.newCachedThreadPool();
-		PluginManagerImpl p = new PluginManagerImpl(executor, db, poller,
-				dispatcher, uiCallback);
+		PluginManagerImpl p = new PluginManagerImpl(executor, new SystemClock(),
+				db, poller, dispatcher, uiCallback);
 		// We expect either 3 or 4 plugins to be started, depending on whether
 		// the test machine has a Bluetooth device
 		int started = p.start();
diff --git a/test/net/sf/briar/plugins/bluetooth/BluetoothClientTest.java b/test/net/sf/briar/plugins/bluetooth/BluetoothClientTest.java
index 96ee30ca24..39c9d4331d 100644
--- a/test/net/sf/briar/plugins/bluetooth/BluetoothClientTest.java
+++ b/test/net/sf/briar/plugins/bluetooth/BluetoothClientTest.java
@@ -9,6 +9,7 @@ import java.util.concurrent.Executors;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
+import net.sf.briar.clock.SystemClock;
 import net.sf.briar.plugins.DuplexClientTest;
 
 // This is not a JUnit test - it has to be run manually while the server test
@@ -25,7 +26,7 @@ public class BluetoothClientTest extends DuplexClientTest {
 		// Create the plugin
 		callback = new ClientCallback(new TransportConfig(),
 				new TransportProperties(), remote);
-		plugin = new BluetoothPlugin(executor, callback, 0L);
+		plugin = new BluetoothPlugin(executor, new SystemClock(), callback, 0L);
 	}
 
 	public static void main(String[] args) throws Exception {
diff --git a/test/net/sf/briar/plugins/bluetooth/BluetoothServerTest.java b/test/net/sf/briar/plugins/bluetooth/BluetoothServerTest.java
index b818d05e73..8bd8eef571 100644
--- a/test/net/sf/briar/plugins/bluetooth/BluetoothServerTest.java
+++ b/test/net/sf/briar/plugins/bluetooth/BluetoothServerTest.java
@@ -7,6 +7,7 @@ import java.util.concurrent.Executors;
 
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
+import net.sf.briar.clock.SystemClock;
 import net.sf.briar.plugins.DuplexServerTest;
 
 // This is not a JUnit test - it has to be run manually while the client test
@@ -20,7 +21,7 @@ public class BluetoothServerTest extends DuplexServerTest {
 		// Create the plugin
 		callback = new ServerCallback(new TransportConfig(), local,
 				Collections.singletonMap(contactId, new TransportProperties()));
-		plugin = new BluetoothPlugin(executor, callback, 0L);
+		plugin = new BluetoothPlugin(executor, new SystemClock(), callback, 0L);
 	}
 
 	public static void main(String[] args) throws Exception {
diff --git a/test/net/sf/briar/plugins/email/GmailPluginTester.java b/test/net/sf/briar/plugins/email/GmailPluginTester.java
index 6d54456fbd..17145c0e26 100644
--- a/test/net/sf/briar/plugins/email/GmailPluginTester.java
+++ b/test/net/sf/briar/plugins/email/GmailPluginTester.java
@@ -1,25 +1,21 @@
 package net.sf.briar.plugins.email;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 
 import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
-import java.util.Map.Entry;
 import java.util.concurrent.Executors;
 
-import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.plugins.simplex.SimplexPluginCallback;
 import net.sf.briar.api.plugins.simplex.SimplexTransportReader;
 import net.sf.briar.api.plugins.simplex.SimplexTransportWriter;
+import net.sf.briar.clock.SystemClock;
 
-import org.jmock.Mockery;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -106,7 +102,8 @@ Map<ContactId,TransportProperties> map = new HashMap<ContactId, TransportPropert
 	public void testPluginFactoryCreation()
 	{
 		GmailPluginFactory plugin = new GmailPluginFactory();
-		plugin.createPlugin(Executors.newSingleThreadExecutor(), callback);
+		plugin.createPlugin(Executors.newSingleThreadExecutor(),
+				new SystemClock(), callback);
 	}
 	
 	@Test
diff --git a/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java b/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java
index 0649fd3103..036392a974 100644
--- a/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java
+++ b/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java
@@ -30,6 +30,7 @@ import net.sf.briar.api.transport.ConnectionReaderFactory;
 import net.sf.briar.api.transport.ConnectionRecogniser;
 import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
+import net.sf.briar.clock.ClockModule;
 import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.db.DatabaseModule;
 import net.sf.briar.lifecycle.LifecycleModule;
@@ -77,8 +78,9 @@ public class SimplexConnectionReadWriteTest extends BriarTestCase {
 	}
 
 	private Injector createInjector(File dir) {
-		return Guice.createInjector(new CryptoModule(), new DatabaseModule(),
-				new LifecycleModule(), new ProtocolModule(), new SerialModule(),
+		return Guice.createInjector(new ClockModule(), new CryptoModule(),
+				new DatabaseModule(), new LifecycleModule(),
+				new ProtocolModule(), new SerialModule(),
 				new TestDatabaseModule(dir), new SimplexProtocolModule(),
 				new TransportModule(), new DuplexProtocolModule());
 	}
diff --git a/test/net/sf/briar/transport/ConnectionWriterTest.java b/test/net/sf/briar/transport/ConnectionWriterTest.java
index 6c416658ec..615944366c 100644
--- a/test/net/sf/briar/transport/ConnectionWriterTest.java
+++ b/test/net/sf/briar/transport/ConnectionWriterTest.java
@@ -10,6 +10,7 @@ import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestDatabaseModule;
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
+import net.sf.briar.clock.ClockModule;
 import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.db.DatabaseModule;
 import net.sf.briar.lifecycle.LifecycleModule;
@@ -30,7 +31,7 @@ public class ConnectionWriterTest extends BriarTestCase {
 
 	public ConnectionWriterTest() throws Exception {
 		super();
-		Injector i = Guice.createInjector(new CryptoModule(),
+		Injector i = Guice.createInjector(new ClockModule(), new CryptoModule(),
 				new DatabaseModule(), new LifecycleModule(),
 				new ProtocolModule(), new SerialModule(),
 				new TestDatabaseModule(), new SimplexProtocolModule(),
-- 
GitLab