Clean up testing with clocks.
This commit is contained in:
parent
0c357bc340
commit
fe60cf003f
|
@ -37,6 +37,7 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
|||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
|
||||
class BaseAccountAuthenticatorTest {
|
||||
|
||||
|
@ -47,7 +48,7 @@ class BaseAccountAuthenticatorTest {
|
|||
|
||||
private AccountsManager accountsManager;
|
||||
private BaseAccountAuthenticator baseAccountAuthenticator;
|
||||
private Clock clock;
|
||||
private TestClock clock;
|
||||
private Account acct1;
|
||||
private Account acct2;
|
||||
private Account oldAccount;
|
||||
|
@ -55,7 +56,7 @@ class BaseAccountAuthenticatorTest {
|
|||
@BeforeEach
|
||||
void setup() {
|
||||
accountsManager = mock(AccountsManager.class);
|
||||
clock = mock(Clock.class);
|
||||
clock = TestClock.now();
|
||||
baseAccountAuthenticator = new BaseAccountAuthenticator(accountsManager, clock);
|
||||
|
||||
// We use static UUIDs here because the UUID affects the "date last seen" offset
|
||||
|
@ -76,7 +77,7 @@ class BaseAccountAuthenticatorTest {
|
|||
|
||||
@Test
|
||||
void testUpdateLastSeenMiddleOfDay() {
|
||||
when(clock.instant()).thenReturn(Instant.ofEpochMilli(currentTime));
|
||||
clock.pin(Instant.ofEpochMilli(currentTime));
|
||||
|
||||
final Device device1 = acct1.getDevices().stream().findFirst().get();
|
||||
final Device device2 = acct2.getDevices().stream().findFirst().get();
|
||||
|
@ -96,7 +97,7 @@ class BaseAccountAuthenticatorTest {
|
|||
|
||||
@Test
|
||||
void testUpdateLastSeenStartOfDay() {
|
||||
when(clock.instant()).thenReturn(Instant.ofEpochMilli(today));
|
||||
clock.pin(Instant.ofEpochMilli(today));
|
||||
|
||||
final Device device1 = acct1.getDevices().stream().findFirst().get();
|
||||
final Device device2 = acct2.getDevices().stream().findFirst().get();
|
||||
|
@ -116,7 +117,7 @@ class BaseAccountAuthenticatorTest {
|
|||
|
||||
@Test
|
||||
void testUpdateLastSeenEndOfDay() {
|
||||
when(clock.instant()).thenReturn(Instant.ofEpochMilli(today + 86_400_000L - 1));
|
||||
clock.pin(Instant.ofEpochMilli(today + 86_400_000L - 1));
|
||||
|
||||
final Device device1 = acct1.getDevices().stream().findFirst().get();
|
||||
final Device device2 = acct2.getDevices().stream().findFirst().get();
|
||||
|
@ -136,7 +137,7 @@ class BaseAccountAuthenticatorTest {
|
|||
|
||||
@Test
|
||||
void testNeverWriteYesterday() {
|
||||
when(clock.instant()).thenReturn(Instant.ofEpochMilli(today));
|
||||
clock.pin(Instant.ofEpochMilli(today));
|
||||
|
||||
final Device device = oldAccount.getDevices().stream().findFirst().get();
|
||||
|
||||
|
@ -157,7 +158,7 @@ class BaseAccountAuthenticatorTest {
|
|||
final Device device = mock(Device.class);
|
||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||
|
||||
when(clock.instant()).thenReturn(Instant.now());
|
||||
clock.unpin();
|
||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||
when(account.getUuid()).thenReturn(uuid);
|
||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||
|
@ -187,7 +188,7 @@ class BaseAccountAuthenticatorTest {
|
|||
final Device device = mock(Device.class);
|
||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||
|
||||
when(clock.instant()).thenReturn(Instant.now());
|
||||
clock.unpin();
|
||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||
when(account.getUuid()).thenReturn(uuid);
|
||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||
|
@ -218,7 +219,7 @@ class BaseAccountAuthenticatorTest {
|
|||
final Device device = mock(Device.class);
|
||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||
|
||||
when(clock.instant()).thenReturn(Instant.now());
|
||||
clock.unpin();
|
||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||
when(account.getUuid()).thenReturn(uuid);
|
||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||
|
@ -251,7 +252,7 @@ class BaseAccountAuthenticatorTest {
|
|||
final Device device = mock(Device.class);
|
||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||
|
||||
when(clock.instant()).thenReturn(Instant.now());
|
||||
clock.unpin();
|
||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||
when(account.getUuid()).thenReturn(uuid);
|
||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||
|
@ -288,7 +289,7 @@ class BaseAccountAuthenticatorTest {
|
|||
final Device device = mock(Device.class);
|
||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||
|
||||
when(clock.instant()).thenReturn(Instant.now());
|
||||
clock.unpin();
|
||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||
when(account.getUuid()).thenReturn(uuid);
|
||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||
|
@ -316,7 +317,7 @@ class BaseAccountAuthenticatorTest {
|
|||
final Device device = mock(Device.class);
|
||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||
|
||||
when(clock.instant()).thenReturn(Instant.now());
|
||||
clock.unpin();
|
||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||
when(account.getUuid()).thenReturn(uuid);
|
||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||
|
|
|
@ -37,21 +37,19 @@ import org.whispersystems.textsecuregcm.entities.Badge;
|
|||
import org.whispersystems.textsecuregcm.entities.BadgeSvg;
|
||||
import org.whispersystems.textsecuregcm.entities.SelfBadge;
|
||||
import org.whispersystems.textsecuregcm.storage.AccountBadge;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
|
||||
public class ConfiguredProfileBadgeConverterTest {
|
||||
|
||||
private Clock clock;
|
||||
private final Clock clock = TestClock.pinned(Instant.ofEpochSecond(42));
|
||||
private ResourceBundleFactory resourceBundleFactory;
|
||||
private ResourceBundle resourceBundle;
|
||||
|
||||
@BeforeEach
|
||||
private void beforeEach() {
|
||||
clock = mock(Clock.class);
|
||||
resourceBundleFactory = mock(ResourceBundleFactory.class, (invocation) -> {
|
||||
throw new UnsupportedOperationException();
|
||||
});
|
||||
|
||||
when(clock.instant()).thenReturn(Instant.ofEpochSecond(42));
|
||||
}
|
||||
|
||||
private static String idFor(int i) {
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.security.SecureRandom;
|
|||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -105,6 +106,7 @@ import org.whispersystems.textsecuregcm.storage.VersionedProfile;
|
|||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
import software.amazon.awssdk.services.s3.S3Client;
|
||||
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
|
||||
|
@ -112,7 +114,7 @@ import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
|
|||
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||
class ProfileControllerTest {
|
||||
|
||||
private static final Clock clock = mock(Clock.class);
|
||||
private static final Clock clock = TestClock.pinned(Instant.ofEpochSecond(42));
|
||||
private static final AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
private static final ProfilesManager profilesManager = mock(ProfilesManager.class);
|
||||
private static final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||
|
@ -172,8 +174,6 @@ class ProfileControllerTest {
|
|||
void setup() {
|
||||
reset(s3client);
|
||||
|
||||
when(clock.instant()).thenReturn(Instant.ofEpochSecond(42));
|
||||
|
||||
AccountsHelper.setupMockUpdate(accountsManager);
|
||||
|
||||
dynamicPaymentsConfiguration = mock(DynamicPaymentsConfiguration.class);
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.whispersystems.textsecuregcm.storage.Account;
|
|||
import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
|
||||
class ApnPushNotificationSchedulerTest {
|
||||
|
||||
|
@ -41,7 +42,7 @@ class ApnPushNotificationSchedulerTest {
|
|||
private Device device;
|
||||
|
||||
private APNSender apnSender;
|
||||
private Clock clock;
|
||||
private TestClock clock;
|
||||
|
||||
private ApnPushNotificationScheduler apnPushNotificationScheduler;
|
||||
|
||||
|
@ -70,7 +71,7 @@ class ApnPushNotificationSchedulerTest {
|
|||
when(accountsManager.getByAccountIdentifier(ACCOUNT_UUID)).thenReturn(Optional.of(account));
|
||||
|
||||
apnSender = mock(APNSender.class);
|
||||
clock = mock(Clock.class);
|
||||
clock = TestClock.now();
|
||||
|
||||
apnPushNotificationScheduler = new ApnPushNotificationScheduler(REDIS_CLUSTER_EXTENSION.getRedisCluster(), apnSender, accountsManager, clock);
|
||||
}
|
||||
|
@ -83,10 +84,10 @@ class ApnPushNotificationSchedulerTest {
|
|||
assertTrue(
|
||||
apnPushNotificationScheduler.getPendingDestinationsForRecurringVoipNotifications(SlotHash.getSlot(endpoint), 1).isEmpty());
|
||||
|
||||
when(clock.millis()).thenReturn(currentTimeMillis - 30_000);
|
||||
clock.pin(Instant.ofEpochMilli(currentTimeMillis - 30_000));
|
||||
apnPushNotificationScheduler.scheduleRecurringVoipNotification(account, device);
|
||||
|
||||
when(clock.millis()).thenReturn(currentTimeMillis);
|
||||
clock.pin(Instant.ofEpochMilli(currentTimeMillis));
|
||||
final List<String> pendingDestinations = apnPushNotificationScheduler.getPendingDestinationsForRecurringVoipNotifications(SlotHash.getSlot(endpoint), 2);
|
||||
assertEquals(1, pendingDestinations.size());
|
||||
|
||||
|
@ -106,10 +107,10 @@ class ApnPushNotificationSchedulerTest {
|
|||
final ApnPushNotificationScheduler.NotificationWorker worker = apnPushNotificationScheduler.new NotificationWorker();
|
||||
final long currentTimeMillis = System.currentTimeMillis();
|
||||
|
||||
when(clock.millis()).thenReturn(currentTimeMillis - 30_000);
|
||||
clock.pin(Instant.ofEpochMilli(currentTimeMillis - 30_000));
|
||||
apnPushNotificationScheduler.scheduleRecurringVoipNotification(account, device);
|
||||
|
||||
when(clock.millis()).thenReturn(currentTimeMillis);
|
||||
clock.pin(Instant.ofEpochMilli(currentTimeMillis));
|
||||
|
||||
final int slot = SlotHash.getSlot(ApnPushNotificationScheduler.getEndpointKey(account, device));
|
||||
|
||||
|
@ -130,7 +131,7 @@ class ApnPushNotificationSchedulerTest {
|
|||
@Test
|
||||
void testScheduleBackgroundNotificationWithNoRecentNotification() {
|
||||
final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
||||
clock.pin(now);
|
||||
|
||||
assertEquals(Optional.empty(),
|
||||
apnPushNotificationScheduler.getLastBackgroundNotificationTimestamp(account, device));
|
||||
|
@ -151,10 +152,10 @@ class ApnPushNotificationSchedulerTest {
|
|||
now.minus(ApnPushNotificationScheduler.BACKGROUND_NOTIFICATION_PERIOD.dividedBy(2));
|
||||
|
||||
// Insert a timestamp for a recently-sent background push notification
|
||||
when(clock.millis()).thenReturn(recentNotificationTimestamp.toEpochMilli());
|
||||
clock.pin(Instant.ofEpochMilli(recentNotificationTimestamp.toEpochMilli()));
|
||||
apnPushNotificationScheduler.sendBackgroundNotification(account, device);
|
||||
|
||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
||||
clock.pin(now);
|
||||
apnPushNotificationScheduler.scheduleBackgroundNotification(account, device);
|
||||
|
||||
final Instant expectedScheduledTimestamp =
|
||||
|
@ -170,16 +171,16 @@ class ApnPushNotificationSchedulerTest {
|
|||
|
||||
final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
||||
|
||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
||||
clock.pin(Instant.ofEpochMilli(now.toEpochMilli()));
|
||||
apnPushNotificationScheduler.scheduleBackgroundNotification(account, device);
|
||||
|
||||
final int slot =
|
||||
SlotHash.getSlot(ApnPushNotificationScheduler.getPendingBackgroundNotificationQueueKey(account, device));
|
||||
|
||||
when(clock.millis()).thenReturn(now.minusMillis(1).toEpochMilli());
|
||||
clock.pin(Instant.ofEpochMilli(now.minusMillis(1).toEpochMilli()));
|
||||
assertEquals(0, worker.processScheduledBackgroundNotifications(slot));
|
||||
|
||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
||||
clock.pin(now);
|
||||
assertEquals(1, worker.processScheduledBackgroundNotifications(slot));
|
||||
|
||||
final ArgumentCaptor<PushNotification> notificationCaptor = ArgumentCaptor.forClass(PushNotification.class);
|
||||
|
@ -203,7 +204,7 @@ class ApnPushNotificationSchedulerTest {
|
|||
|
||||
final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
||||
|
||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
||||
clock.pin(now);
|
||||
apnPushNotificationScheduler.scheduleBackgroundNotification(account, device);
|
||||
apnPushNotificationScheduler.cancelScheduledNotifications(account, device);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
|||
import org.whispersystems.textsecuregcm.tests.util.DevicesHelper;
|
||||
import org.whispersystems.textsecuregcm.util.AttributeValues;
|
||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
|
@ -78,7 +79,7 @@ class AccountsTest {
|
|||
.build())
|
||||
.build();
|
||||
|
||||
private Clock mockClock;
|
||||
private TestClock clock = TestClock.pinned(Instant.EPOCH);
|
||||
private DynamicConfigurationManager<DynamicConfiguration> mockDynamicConfigManager;
|
||||
private Accounts accounts;
|
||||
|
||||
|
@ -135,11 +136,8 @@ class AccountsTest {
|
|||
when(mockDynamicConfigManager.getConfiguration())
|
||||
.thenReturn(new DynamicConfiguration());
|
||||
|
||||
mockClock = mock(Clock.class);
|
||||
when(mockClock.instant()).thenReturn(Instant.EPOCH);
|
||||
|
||||
this.accounts = new Accounts(
|
||||
mockClock,
|
||||
clock,
|
||||
mockDynamicConfigManager,
|
||||
dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(),
|
||||
|
@ -810,12 +808,12 @@ class AccountsTest {
|
|||
Supplier<UUID> take = () -> accounts.reserveUsername(account2, username, Duration.ofDays(2));
|
||||
|
||||
for (int i = 0; i <= 2; i++) {
|
||||
when(mockClock.instant()).thenReturn(Instant.EPOCH.plus(Duration.ofDays(i)));
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(i)));
|
||||
assertThrows(ContestedOptimisticLockException.class, take::get);
|
||||
}
|
||||
|
||||
// after 2 days, can take the name
|
||||
when(mockClock.instant()).thenReturn(Instant.EPOCH.plus(Duration.ofDays(2)).plus(Duration.ofSeconds(1)));
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(2)).plus(Duration.ofSeconds(1)));
|
||||
final UUID token = take.get();
|
||||
|
||||
assertThrows(ContestedOptimisticLockException.class,
|
||||
|
@ -840,12 +838,12 @@ class AccountsTest {
|
|||
Runnable take = () -> accounts.setUsername(account2, username);
|
||||
|
||||
for (int i = 0; i <= 2; i++) {
|
||||
when(mockClock.instant()).thenReturn(Instant.EPOCH.plus(Duration.ofDays(i)));
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(i)));
|
||||
assertThrows(ContestedOptimisticLockException.class, take::run);
|
||||
}
|
||||
|
||||
// after 2 days, can take the name
|
||||
when(mockClock.instant()).thenReturn(Instant.EPOCH.plus(Duration.ofDays(2)).plus(Duration.ofSeconds(1)));
|
||||
clock.pin(Instant.EPOCH.plus(Duration.ofDays(2)).plus(Duration.ofSeconds(1)));
|
||||
take.run();
|
||||
|
||||
assertThrows(ContestedOptimisticLockException.class,
|
||||
|
|
|
@ -61,6 +61,7 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
|||
import org.whispersystems.textsecuregcm.storage.RedeemedReceiptsManager;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
|
||||
class DonationControllerTest {
|
||||
|
||||
|
@ -99,7 +100,7 @@ class DonationControllerTest {
|
|||
Map.of(1L, "TEST1", 2L, "TEST2", 3L, "TEST3"));
|
||||
}
|
||||
|
||||
Clock clock;
|
||||
Clock clock = TestClock.pinned(Instant.ofEpochSecond(nowEpochSeconds));
|
||||
ServerZkReceiptOperations zkReceiptOperations;
|
||||
RedeemedReceiptsManager redeemedReceiptsManager;
|
||||
AccountsManager accountsManager;
|
||||
|
@ -112,7 +113,6 @@ class DonationControllerTest {
|
|||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Throwable {
|
||||
clock = mock(Clock.class);
|
||||
zkReceiptOperations = mock(ServerZkReceiptOperations.class);
|
||||
redeemedReceiptsManager = mock(RedeemedReceiptsManager.class);
|
||||
accountsManager = mock(AccountsManager.class);
|
||||
|
@ -125,9 +125,6 @@ class DonationControllerTest {
|
|||
receiptCredentialPresentationFactory = mock(DonationController.ReceiptCredentialPresentationFactory.class);
|
||||
receiptCredentialPresentation = mock(ReceiptCredentialPresentation.class);
|
||||
|
||||
when(clock.millis()).thenReturn(nowEpochSeconds * 1000L);
|
||||
when(clock.instant()).thenReturn(Instant.ofEpochSecond(nowEpochSeconds));
|
||||
|
||||
try {
|
||||
when(receiptCredentialPresentationFactory.build(presentation)).thenReturn(receiptCredentialPresentation);
|
||||
} catch (InvalidInputException e) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.whispersystems.textsecuregcm.storage.AccountBadge;
|
|||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.storage.Device.DeviceCapabilities;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
|
||||
class AccountTest {
|
||||
|
||||
|
@ -442,8 +443,7 @@ class AccountTest {
|
|||
@Test
|
||||
void addAndRemoveBadges() {
|
||||
final Account account = AccountsHelper.generateTestAccount("+14151234567", UUID.randomUUID(), UUID.randomUUID(), List.of(createDevice(Device.MASTER_ID)), new byte[0]);
|
||||
final Clock clock = mock(Clock.class);
|
||||
when(clock.instant()).thenReturn(Instant.ofEpochSecond(40));
|
||||
final Clock clock = TestClock.pinned(Instant.ofEpochSecond(40));
|
||||
|
||||
account.addBadge(clock, new AccountBadge("foo", Instant.ofEpochSecond(42), false));
|
||||
account.addBadge(clock, new AccountBadge("bar", Instant.ofEpochSecond(44), true));
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.signal.libsignal.zkgroup.receipts.ReceiptSerial;
|
|||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtension;
|
||||
import org.whispersystems.textsecuregcm.storage.RedeemedReceiptsManager;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
|
@ -42,15 +43,12 @@ class RedeemedReceiptsManagerTest {
|
|||
.build())
|
||||
.build();
|
||||
|
||||
Clock clock;
|
||||
Clock clock = TestClock.pinned(Instant.ofEpochSecond(NOW_EPOCH_SECONDS));
|
||||
ReceiptSerial receiptSerial;
|
||||
RedeemedReceiptsManager redeemedReceiptsManager;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws InvalidInputException {
|
||||
clock = mock(Clock.class);
|
||||
when(clock.millis()).thenReturn(NOW_EPOCH_SECONDS * 1000L);
|
||||
when(clock.instant()).thenReturn(Instant.ofEpochSecond(NOW_EPOCH_SECONDS));
|
||||
byte[] receiptSerialBytes = new byte[ReceiptSerial.SIZE];
|
||||
SECURE_RANDOM.nextBytes(receiptSerialBytes);
|
||||
receiptSerial = new ReceiptSerial(receiptSerialBytes);
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package org.whispersystems.textsecuregcm.util;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Clock class specialized for testing.
|
||||
*
|
||||
* This clock can be pinned to a particular instant or can provide the "normal" time.
|
||||
*
|
||||
* Unlike normal clocks it can be dynamically pinned and unpinned to help with testing.
|
||||
* It should not be used in production.
|
||||
*/
|
||||
public class TestClock extends java.time.Clock {
|
||||
|
||||
private Optional<Instant> pinnedInstant;
|
||||
private final ZoneId zoneId;
|
||||
|
||||
private TestClock(Optional<Instant> maybePinned, ZoneId id) {
|
||||
this.pinnedInstant = maybePinned;
|
||||
this.zoneId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a test clock that returns the "real" time.
|
||||
*
|
||||
* The clock can later be pinned to an instant if desired.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static TestClock now() {
|
||||
return new TestClock(Optional.empty(), ZoneId.of("UTC"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a test clock pinned to a particular instant.
|
||||
*
|
||||
* The clock can later be pinned to a different instant or unpinned if desired.
|
||||
*
|
||||
* Unlike the fixed constructor no time zone is required (it defaults to UTC).
|
||||
*
|
||||
* @param instant
|
||||
* @return test clock pinned to the given instant.
|
||||
*/
|
||||
public static TestClock pinned(Instant instant) {
|
||||
return new TestClock(Optional.of(instant), ZoneId.of("UTC"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin this test clock to the given instance.
|
||||
*
|
||||
* This modifies the existing clock in-place.
|
||||
*
|
||||
* @param instant
|
||||
*/
|
||||
public void pin(Instant instant) {
|
||||
this.pinnedInstant = Optional.of(instant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpin this test clock so it will being returning the "real" time.
|
||||
*
|
||||
* This modifies the existing clock in-place.
|
||||
*/
|
||||
public void unpin() {
|
||||
this.pinnedInstant = Optional.empty();
|
||||
}
|
||||
|
||||
|
||||
public TestClock withZone(ZoneId id) {
|
||||
return new TestClock(pinnedInstant, id);
|
||||
}
|
||||
|
||||
public ZoneId getZone() {
|
||||
return zoneId;
|
||||
}
|
||||
|
||||
public Instant instant() {
|
||||
return pinnedInstant.orElseGet(Instant::now);
|
||||
}
|
||||
|
||||
public long millis() {
|
||||
return instant().toEpochMilli();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue