mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-03-10 00:09:31 +01:00
TimeUtils: migrate mock clock to java.time
API
* Migrate `setMockClock()` parameters to Instant * Migrate `rollMockClock()` parameters to Duration * Rename to `clearMockClock()` from `resetMocking()` * Use `Clock` internally to provide the time
This commit is contained in:
parent
7a1c71c319
commit
16c90d2891
15 changed files with 76 additions and 69 deletions
|
@ -18,6 +18,7 @@ package org.bitcoinj.base.internal;
|
|||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
@ -29,75 +30,68 @@ import java.util.TimeZone;
|
|||
*/
|
||||
public class TimeUtils {
|
||||
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
|
||||
/**
|
||||
* If non-null, overrides the return value of now().
|
||||
*/
|
||||
private static volatile Date mockTime;
|
||||
// Clock to be used for the return value of now() and currentTime() variants
|
||||
private static volatile Clock clock = Clock.systemUTC();
|
||||
|
||||
/**
|
||||
* Advances (or rewinds) the mock clock by the given number of seconds.
|
||||
*/
|
||||
public static Date rollMockClock(int seconds) {
|
||||
return rollMockClockMillis(seconds * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances (or rewinds) the mock clock by the given number of milliseconds.
|
||||
*/
|
||||
public static Date rollMockClockMillis(long millis) {
|
||||
if (mockTime == null)
|
||||
throw new IllegalStateException("You need to use setMockClock() first.");
|
||||
mockTime = new Date(mockTime.getTime() + millis);
|
||||
return mockTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mock clock to the current time.
|
||||
* Sets the mock clock to the current time as a fixed instant.
|
||||
*/
|
||||
public static void setMockClock() {
|
||||
mockTime = new Date();
|
||||
setMockClock(Instant.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the mock clock to the given time (in seconds).
|
||||
* Sets the mock clock to a fixed instant.
|
||||
* @param fixedInstant a fixed instant
|
||||
*/
|
||||
public static void setMockClock(long mockClockSeconds) {
|
||||
mockTime = new Date(mockClockSeconds * 1000);
|
||||
public static void setMockClock(Instant fixedInstant) {
|
||||
clock = Clock.fixed(fixedInstant, UTC.toZoneId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the mock clock and sleep
|
||||
* Rolls an already set mock clock by the given duration.
|
||||
* @param delta amount to roll the mock clock, can be negative
|
||||
* @throws IllegalStateException if the mock clock isn't set
|
||||
*/
|
||||
public static void resetMocking() {
|
||||
mockTime = null;
|
||||
public static void rollMockClock(Duration delta) {
|
||||
if (clock.equals(Clock.systemUTC()))
|
||||
throw new IllegalStateException("You need to use setMockClock() first.");
|
||||
setMockClock(clock.instant().plus(delta));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the mock clock and causes time to tick again.
|
||||
*/
|
||||
public static void clearMockClock() {
|
||||
clock = Clock.systemUTC();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time, or a mocked out equivalent.
|
||||
*/
|
||||
public static Date now() {
|
||||
return mockTime != null ? mockTime : new Date();
|
||||
return Date.from(currentTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time in milliseconds since the epoch, or a mocked out equivalent.
|
||||
*/
|
||||
public static long currentTimeMillis() {
|
||||
return mockTime != null ? mockTime.getTime() : System.currentTimeMillis();
|
||||
return currentTime().toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time in seconds since the epoch, or a mocked out equivalent.
|
||||
*/
|
||||
public static long currentTimeSeconds() {
|
||||
return currentTimeMillis() / 1000;
|
||||
return currentTime().getEpochSecond();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time as an Instant, or a mocked out equivalent.
|
||||
*/
|
||||
public static Instant currentTime() {
|
||||
return Instant.ofEpochMilli(currentTimeMillis());
|
||||
return Instant.now(clock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.bitcoinj.base.internal;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -35,9 +37,15 @@ public class TimeUtilsTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testRollMockClock() {
|
||||
TimeUtils.setMockClock(25200);
|
||||
assertEquals(new Date("Thu Jan 01 07:00:08 GMT 1970"), TimeUtils.rollMockClock(8));
|
||||
TimeUtils.resetMocking();
|
||||
public void setAndRollMockClock() {
|
||||
TimeUtils.setMockClock(Instant.ofEpochSecond(25200));
|
||||
assertEquals(new Date("Thu Jan 01 07:00:00 GMT 1970"), TimeUtils.now());
|
||||
TimeUtils.rollMockClock(Duration.ofSeconds(8));
|
||||
assertEquals(new Date("Thu Jan 01 07:00:08 GMT 1970"), TimeUtils.now());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void rollMockClock_uninitialized() {
|
||||
TimeUtils.rollMockClock(Duration.ofMinutes(1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public abstract class AbstractFullPrunedBlockChainTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
TimeUtils.resetMocking();
|
||||
TimeUtils.clearMockClock();
|
||||
PARAMS = new UnitTestParams() {
|
||||
@Override public int getInterval() {
|
||||
return 10000;
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.junit.rules.ExpectedException;
|
|||
|
||||
import java.math.BigInteger;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
@ -178,7 +179,7 @@ public class BlockChainTest {
|
|||
assertTrue(chain.add(newBlock));
|
||||
prev = newBlock;
|
||||
// The fake chain should seem to be "fast" for the purposes of difficulty calculations.
|
||||
TimeUtils.rollMockClock(2);
|
||||
TimeUtils.rollMockClock(Duration.ofSeconds(2));
|
||||
}
|
||||
// Now add another block that has no difficulty adjustment, it should be rejected.
|
||||
try {
|
||||
|
|
|
@ -42,6 +42,7 @@ import java.io.IOException;
|
|||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
|
@ -147,7 +148,7 @@ public class TransactionTest {
|
|||
@Test
|
||||
public void testEstimatedLockTime_WhenParameterSignifiesBlockHeight() {
|
||||
int TEST_LOCK_TIME = 20;
|
||||
Instant now = TimeUtils.currentTime();
|
||||
Instant now = TimeUtils.currentTime().truncatedTo(ChronoUnit.SECONDS);
|
||||
|
||||
BlockChain mockBlockChain = createMock(BlockChain.class);
|
||||
EasyMock.expect(mockBlockChain.estimateBlockTimeInstant(TEST_LOCK_TIME)).andReturn(now);
|
||||
|
|
|
@ -39,7 +39,6 @@ import java.math.BigInteger;
|
|||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
@ -51,7 +50,7 @@ public class SPVBlockStoreTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
TimeUtils.resetMocking();
|
||||
TimeUtils.clearMockClock();
|
||||
}
|
||||
|
||||
@Before
|
||||
|
|
|
@ -97,7 +97,7 @@ public class WalletProtobufSerializerTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
TimeUtils.resetMocking();
|
||||
TimeUtils.clearMockClock();
|
||||
Context.propagate(new Context());
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class TestWithWallet {
|
|||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
TimeUtils.resetMocking();
|
||||
TimeUtils.clearMockClock();
|
||||
}
|
||||
|
||||
public void setUp() throws Exception {
|
||||
|
|
|
@ -42,7 +42,7 @@ public class VersionTallyTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
TimeUtils.resetMocking();
|
||||
TimeUtils.clearMockClock();
|
||||
}
|
||||
|
||||
@Before
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.bitcoinj.wallet.listeners.AbstractKeyChainEventListener;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -69,7 +70,7 @@ public class BasicKeyChainTest {
|
|||
TimeUtils.setMockClock();
|
||||
long now = TimeUtils.currentTimeSeconds();
|
||||
final ECKey key1 = new ECKey();
|
||||
TimeUtils.rollMockClock(86400);
|
||||
TimeUtils.rollMockClock(Duration.ofDays(1));
|
||||
final ECKey key2 = new ECKey();
|
||||
final ArrayList<ECKey> keys = Lists.newArrayList(key1, key2);
|
||||
|
||||
|
@ -198,7 +199,7 @@ public class BasicKeyChainTest {
|
|||
TimeUtils.setMockClock();
|
||||
Date now = TimeUtils.now();
|
||||
final ECKey key1 = new ECKey();
|
||||
TimeUtils.rollMockClock(5000);
|
||||
TimeUtils.rollMockClock(Duration.ofSeconds(5000));
|
||||
final ECKey key2 = new ECKey();
|
||||
chain.importKeys(Arrays.asList(key1, key2));
|
||||
List<Protos.Key> keys = chain.serializeToProtobuf();
|
||||
|
@ -278,7 +279,7 @@ public class BasicKeyChainTest {
|
|||
TimeUtils.setMockClock();
|
||||
long now = TimeUtils.currentTimeSeconds();
|
||||
final ECKey key1 = new ECKey();
|
||||
TimeUtils.rollMockClock(86400);
|
||||
TimeUtils.rollMockClock(Duration.ofDays(1));
|
||||
final ECKey key2 = new ECKey();
|
||||
final List<ECKey> keys = Lists.newArrayList(key1, key2);
|
||||
assertEquals(2, chain.importKeys(keys));
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
@ -256,11 +257,11 @@ public class KeyChainGroupTest {
|
|||
}
|
||||
|
||||
private void encryption(boolean withImported) {
|
||||
TimeUtils.rollMockClock(0);
|
||||
TimeUtils.setMockClock();
|
||||
long now = TimeUtils.currentTimeSeconds();
|
||||
ECKey a = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||
assertEquals(now, group.getEarliestKeyCreationTime());
|
||||
TimeUtils.rollMockClock(-86400);
|
||||
TimeUtils.rollMockClock(Duration.ofDays(-1));
|
||||
long yesterday = TimeUtils.currentTimeSeconds();
|
||||
ECKey b = new ECKey();
|
||||
|
||||
|
@ -403,9 +404,9 @@ public class KeyChainGroupTest {
|
|||
long now = TimeUtils.currentTimeSeconds(); // mock
|
||||
long yesterday = now - 86400;
|
||||
assertEquals(now, group.getEarliestKeyCreationTime());
|
||||
TimeUtils.rollMockClock(10000);
|
||||
TimeUtils.rollMockClock(Duration.ofSeconds(10000));
|
||||
group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||
TimeUtils.rollMockClock(10000);
|
||||
TimeUtils.rollMockClock(Duration.ofSeconds(10000));
|
||||
group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||
// Check that all keys are assumed to be created at the same instant the seed is.
|
||||
assertEquals(now, group.getEarliestKeyCreationTime());
|
||||
|
|
|
@ -81,6 +81,7 @@ import java.io.File;
|
|||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
|
@ -1444,7 +1445,7 @@ public class WalletTest extends TestWithWallet {
|
|||
// Check the wallet can give us an ordered list of all received transactions.
|
||||
TimeUtils.setMockClock();
|
||||
Transaction tx1 = sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, COIN);
|
||||
TimeUtils.rollMockClock(60 * 10);
|
||||
TimeUtils.rollMockClock(Duration.ofMinutes(10));
|
||||
Transaction tx2 = sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, valueOf(0, 5));
|
||||
// Check we got them back in order.
|
||||
List<Transaction> transactions = wallet.getTransactionsByTime();
|
||||
|
@ -1457,7 +1458,7 @@ public class WalletTest extends TestWithWallet {
|
|||
assertEquals(tx2, transactions.get(0));
|
||||
|
||||
// Create a spend five minutes later.
|
||||
TimeUtils.rollMockClock(60 * 5);
|
||||
TimeUtils.rollMockClock(Duration.ofMinutes(5));
|
||||
Transaction tx3 = wallet.createSend(OTHER_ADDRESS, valueOf(0, 5));
|
||||
// Does not appear in list yet.
|
||||
assertEquals(2, wallet.getTransactionsByTime().size());
|
||||
|
@ -1483,7 +1484,7 @@ public class WalletTest extends TestWithWallet {
|
|||
long now = TimeUtils.currentTimeSeconds();
|
||||
wallet = Wallet.createDeterministic(TESTNET, ScriptType.P2PKH);
|
||||
assertEquals(now, wallet.getEarliestKeyCreationTime());
|
||||
TimeUtils.rollMockClock(60);
|
||||
TimeUtils.rollMockClock(Duration.ofMinutes(1));
|
||||
wallet.freshReceiveKey();
|
||||
assertEquals(now, wallet.getEarliestKeyCreationTime());
|
||||
}
|
||||
|
@ -1494,7 +1495,7 @@ public class WalletTest extends TestWithWallet {
|
|||
long now = TimeUtils.currentTimeSeconds();
|
||||
wallet = Wallet.createDeterministic(TESTNET, ScriptType.P2PKH);
|
||||
assertEquals(now, wallet.getEarliestKeyCreationTime());
|
||||
TimeUtils.rollMockClock(-120);
|
||||
TimeUtils.rollMockClock(Duration.ofMinutes(-2));
|
||||
wallet.addWatchedAddress(OTHER_ADDRESS);
|
||||
wallet.freshReceiveKey();
|
||||
assertEquals(now - 120, wallet.getEarliestKeyCreationTime());
|
||||
|
@ -2916,7 +2917,7 @@ public class WalletTest extends TestWithWallet {
|
|||
assertFalse(wallet.isKeyRotating(key1));
|
||||
|
||||
// We got compromised!
|
||||
TimeUtils.rollMockClock(1);
|
||||
TimeUtils.rollMockClock(Duration.ofSeconds(1));
|
||||
wallet.setKeyRotationTime(compromiseTime);
|
||||
assertTrue(wallet.isKeyRotating(key1));
|
||||
wallet.doMaintenance(null, true);
|
||||
|
@ -3010,7 +3011,7 @@ public class WalletTest extends TestWithWallet {
|
|||
DeterministicKey watchKey1 = wallet.getWatchingKey();
|
||||
|
||||
// A day later, we get compromised.
|
||||
TimeUtils.rollMockClock(86400);
|
||||
TimeUtils.rollMockClock(Duration.ofDays(1));
|
||||
wallet.setKeyRotationTime(TimeUtils.currentTime());
|
||||
|
||||
List<Transaction> txns = wallet.doMaintenance(null, false).get();
|
||||
|
@ -3030,7 +3031,7 @@ public class WalletTest extends TestWithWallet {
|
|||
ECKey key = wallet.freshReceiveKey();
|
||||
Address address = key.toAddress(ScriptType.P2PKH, BitcoinNetwork.TESTNET);
|
||||
TimeUtils.setMockClock();
|
||||
TimeUtils.rollMockClock(86400);
|
||||
TimeUtils.rollMockClock(Duration.ofDays(1));
|
||||
for (int i = 0; i < 800; i++) {
|
||||
sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, CENT, address);
|
||||
}
|
||||
|
@ -3038,7 +3039,7 @@ public class WalletTest extends TestWithWallet {
|
|||
MockTransactionBroadcaster broadcaster = new MockTransactionBroadcaster(wallet);
|
||||
|
||||
Instant compromise = TimeUtils.currentTime().truncatedTo(ChronoUnit.SECONDS);
|
||||
TimeUtils.rollMockClock(86400);
|
||||
TimeUtils.rollMockClock(Duration.ofDays(1));
|
||||
wallet.freshReceiveKey();
|
||||
wallet.setKeyRotationTime(compromise);
|
||||
wallet.doMaintenance(null, true);
|
||||
|
|
|
@ -452,15 +452,15 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
// This test is INCOMPLETE because it does not check we handle >2000 blocks correctly.
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
TimeUtils.rollMockClock(60 * 10); // 10 minutes later.
|
||||
TimeUtils.rollMockClock(Duration.ofMinutes(10)); // 10 minutes later.
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
b2.setTime(TimeUtils.currentTime());
|
||||
b2.solve();
|
||||
TimeUtils.rollMockClock(60 * 10); // 10 minutes later.
|
||||
TimeUtils.rollMockClock(Duration.ofMinutes(10)); // 10 minutes later.
|
||||
Block b3 = makeSolvedTestBlock(b2);
|
||||
b3.setTime(TimeUtils.currentTime());
|
||||
b3.solve();
|
||||
TimeUtils.rollMockClock(60 * 10);
|
||||
TimeUtils.rollMockClock(Duration.ofMinutes(10));
|
||||
Block b4 = makeSolvedTestBlock(b3);
|
||||
b4.setTime(TimeUtils.currentTime());
|
||||
b4.solve();
|
||||
|
@ -498,7 +498,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
inbound(writeTarget, b3);
|
||||
pingAndWait(writeTarget);
|
||||
closePeer(peer);
|
||||
TimeUtils.resetMocking();
|
||||
TimeUtils.clearMockClock();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -513,7 +513,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
assertEquals(Long.MAX_VALUE, peer.getPingTime());
|
||||
assertFalse(future.isDone());
|
||||
Ping pingMsg = (Ping) outbound(writeTarget);
|
||||
TimeUtils.rollMockClock(5);
|
||||
TimeUtils.rollMockClock(Duration.ofSeconds(5));
|
||||
// The pong is returned.
|
||||
inbound(writeTarget, new Pong(pingMsg.getNonce()));
|
||||
pingAndWait(writeTarget);
|
||||
|
@ -525,12 +525,12 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
// Do it again and make sure it affects the average.
|
||||
CompletableFuture<Duration> future2 = peer.sendPing();
|
||||
pingMsg = (Ping) outbound(writeTarget);
|
||||
TimeUtils.rollMockClock(50);
|
||||
TimeUtils.rollMockClock(Duration.ofSeconds(50));
|
||||
inbound(writeTarget, new Pong(pingMsg.getNonce()));
|
||||
Duration elapsed2 = future2.get();
|
||||
assertEquals(elapsed2.toMillis(), peer.getLastPingTime());
|
||||
assertEquals(7250, peer.getPingTime());
|
||||
TimeUtils.resetMocking();
|
||||
TimeUtils.clearMockClock();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -80,7 +80,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
|
|||
@After
|
||||
public void tearDown() {
|
||||
super.tearDown();
|
||||
TimeUtils.resetMocking();
|
||||
TimeUtils.clearMockClock();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.junit.rules.Timeout;
|
|||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
@ -121,7 +122,7 @@ public class TestWithPeerGroup extends TestWithNetworkConnections {
|
|||
if (!blockJobs)
|
||||
return super.schedule(command, delay, unit);
|
||||
return super.schedule(() -> {
|
||||
TimeUtils.rollMockClockMillis(unit.toMillis(delay));
|
||||
TimeUtils.rollMockClock(Duration.ofMillis(unit.toMillis(delay)));
|
||||
command.run();
|
||||
jobBlocks.acquireUninterruptibly();
|
||||
}, 0 /* immediate */, unit);
|
||||
|
|
Loading…
Add table
Reference in a new issue