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.storage.Device;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.Pair;
|
import org.whispersystems.textsecuregcm.util.Pair;
|
||||||
|
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||||
|
|
||||||
class BaseAccountAuthenticatorTest {
|
class BaseAccountAuthenticatorTest {
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
|
|
||||||
private AccountsManager accountsManager;
|
private AccountsManager accountsManager;
|
||||||
private BaseAccountAuthenticator baseAccountAuthenticator;
|
private BaseAccountAuthenticator baseAccountAuthenticator;
|
||||||
private Clock clock;
|
private TestClock clock;
|
||||||
private Account acct1;
|
private Account acct1;
|
||||||
private Account acct2;
|
private Account acct2;
|
||||||
private Account oldAccount;
|
private Account oldAccount;
|
||||||
|
@ -55,7 +56,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setup() {
|
void setup() {
|
||||||
accountsManager = mock(AccountsManager.class);
|
accountsManager = mock(AccountsManager.class);
|
||||||
clock = mock(Clock.class);
|
clock = TestClock.now();
|
||||||
baseAccountAuthenticator = new BaseAccountAuthenticator(accountsManager, clock);
|
baseAccountAuthenticator = new BaseAccountAuthenticator(accountsManager, clock);
|
||||||
|
|
||||||
// We use static UUIDs here because the UUID affects the "date last seen" offset
|
// We use static UUIDs here because the UUID affects the "date last seen" offset
|
||||||
|
@ -76,7 +77,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testUpdateLastSeenMiddleOfDay() {
|
void testUpdateLastSeenMiddleOfDay() {
|
||||||
when(clock.instant()).thenReturn(Instant.ofEpochMilli(currentTime));
|
clock.pin(Instant.ofEpochMilli(currentTime));
|
||||||
|
|
||||||
final Device device1 = acct1.getDevices().stream().findFirst().get();
|
final Device device1 = acct1.getDevices().stream().findFirst().get();
|
||||||
final Device device2 = acct2.getDevices().stream().findFirst().get();
|
final Device device2 = acct2.getDevices().stream().findFirst().get();
|
||||||
|
@ -96,7 +97,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testUpdateLastSeenStartOfDay() {
|
void testUpdateLastSeenStartOfDay() {
|
||||||
when(clock.instant()).thenReturn(Instant.ofEpochMilli(today));
|
clock.pin(Instant.ofEpochMilli(today));
|
||||||
|
|
||||||
final Device device1 = acct1.getDevices().stream().findFirst().get();
|
final Device device1 = acct1.getDevices().stream().findFirst().get();
|
||||||
final Device device2 = acct2.getDevices().stream().findFirst().get();
|
final Device device2 = acct2.getDevices().stream().findFirst().get();
|
||||||
|
@ -116,7 +117,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testUpdateLastSeenEndOfDay() {
|
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 device1 = acct1.getDevices().stream().findFirst().get();
|
||||||
final Device device2 = acct2.getDevices().stream().findFirst().get();
|
final Device device2 = acct2.getDevices().stream().findFirst().get();
|
||||||
|
@ -136,7 +137,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNeverWriteYesterday() {
|
void testNeverWriteYesterday() {
|
||||||
when(clock.instant()).thenReturn(Instant.ofEpochMilli(today));
|
clock.pin(Instant.ofEpochMilli(today));
|
||||||
|
|
||||||
final Device device = oldAccount.getDevices().stream().findFirst().get();
|
final Device device = oldAccount.getDevices().stream().findFirst().get();
|
||||||
|
|
||||||
|
@ -157,7 +158,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
final Device device = mock(Device.class);
|
final Device device = mock(Device.class);
|
||||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||||
|
|
||||||
when(clock.instant()).thenReturn(Instant.now());
|
clock.unpin();
|
||||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||||
when(account.getUuid()).thenReturn(uuid);
|
when(account.getUuid()).thenReturn(uuid);
|
||||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||||
|
@ -187,7 +188,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
final Device device = mock(Device.class);
|
final Device device = mock(Device.class);
|
||||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||||
|
|
||||||
when(clock.instant()).thenReturn(Instant.now());
|
clock.unpin();
|
||||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||||
when(account.getUuid()).thenReturn(uuid);
|
when(account.getUuid()).thenReturn(uuid);
|
||||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||||
|
@ -218,7 +219,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
final Device device = mock(Device.class);
|
final Device device = mock(Device.class);
|
||||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||||
|
|
||||||
when(clock.instant()).thenReturn(Instant.now());
|
clock.unpin();
|
||||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||||
when(account.getUuid()).thenReturn(uuid);
|
when(account.getUuid()).thenReturn(uuid);
|
||||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||||
|
@ -251,7 +252,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
final Device device = mock(Device.class);
|
final Device device = mock(Device.class);
|
||||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||||
|
|
||||||
when(clock.instant()).thenReturn(Instant.now());
|
clock.unpin();
|
||||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||||
when(account.getUuid()).thenReturn(uuid);
|
when(account.getUuid()).thenReturn(uuid);
|
||||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||||
|
@ -288,7 +289,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
final Device device = mock(Device.class);
|
final Device device = mock(Device.class);
|
||||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||||
|
|
||||||
when(clock.instant()).thenReturn(Instant.now());
|
clock.unpin();
|
||||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||||
when(account.getUuid()).thenReturn(uuid);
|
when(account.getUuid()).thenReturn(uuid);
|
||||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
||||||
|
@ -316,7 +317,7 @@ class BaseAccountAuthenticatorTest {
|
||||||
final Device device = mock(Device.class);
|
final Device device = mock(Device.class);
|
||||||
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
final AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
|
||||||
|
|
||||||
when(clock.instant()).thenReturn(Instant.now());
|
clock.unpin();
|
||||||
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
when(accountsManager.getByAccountIdentifier(uuid)).thenReturn(Optional.of(account));
|
||||||
when(account.getUuid()).thenReturn(uuid);
|
when(account.getUuid()).thenReturn(uuid);
|
||||||
when(account.getDevice(deviceId)).thenReturn(Optional.of(device));
|
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.BadgeSvg;
|
||||||
import org.whispersystems.textsecuregcm.entities.SelfBadge;
|
import org.whispersystems.textsecuregcm.entities.SelfBadge;
|
||||||
import org.whispersystems.textsecuregcm.storage.AccountBadge;
|
import org.whispersystems.textsecuregcm.storage.AccountBadge;
|
||||||
|
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||||
|
|
||||||
public class ConfiguredProfileBadgeConverterTest {
|
public class ConfiguredProfileBadgeConverterTest {
|
||||||
|
|
||||||
private Clock clock;
|
private final Clock clock = TestClock.pinned(Instant.ofEpochSecond(42));
|
||||||
private ResourceBundleFactory resourceBundleFactory;
|
private ResourceBundleFactory resourceBundleFactory;
|
||||||
private ResourceBundle resourceBundle;
|
private ResourceBundle resourceBundle;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
private void beforeEach() {
|
private void beforeEach() {
|
||||||
clock = mock(Clock.class);
|
|
||||||
resourceBundleFactory = mock(ResourceBundleFactory.class, (invocation) -> {
|
resourceBundleFactory = mock(ResourceBundleFactory.class, (invocation) -> {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
});
|
});
|
||||||
|
|
||||||
when(clock.instant()).thenReturn(Instant.ofEpochSecond(42));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String idFor(int i) {
|
private static String idFor(int i) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.security.SecureRandom;
|
||||||
import java.time.Clock;
|
import java.time.Clock;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
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.AccountsHelper;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
||||||
|
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||||
import org.whispersystems.textsecuregcm.util.Util;
|
import org.whispersystems.textsecuregcm.util.Util;
|
||||||
import software.amazon.awssdk.services.s3.S3Client;
|
import software.amazon.awssdk.services.s3.S3Client;
|
||||||
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
|
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
|
||||||
|
@ -112,7 +114,7 @@ import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
|
||||||
@ExtendWith(DropwizardExtensionsSupport.class)
|
@ExtendWith(DropwizardExtensionsSupport.class)
|
||||||
class ProfileControllerTest {
|
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 AccountsManager accountsManager = mock(AccountsManager.class);
|
||||||
private static final ProfilesManager profilesManager = mock(ProfilesManager.class);
|
private static final ProfilesManager profilesManager = mock(ProfilesManager.class);
|
||||||
private static final RateLimiters rateLimiters = mock(RateLimiters.class);
|
private static final RateLimiters rateLimiters = mock(RateLimiters.class);
|
||||||
|
@ -172,8 +174,6 @@ class ProfileControllerTest {
|
||||||
void setup() {
|
void setup() {
|
||||||
reset(s3client);
|
reset(s3client);
|
||||||
|
|
||||||
when(clock.instant()).thenReturn(Instant.ofEpochSecond(42));
|
|
||||||
|
|
||||||
AccountsHelper.setupMockUpdate(accountsManager);
|
AccountsHelper.setupMockUpdate(accountsManager);
|
||||||
|
|
||||||
dynamicPaymentsConfiguration = mock(DynamicPaymentsConfiguration.class);
|
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.AccountsManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device;
|
import org.whispersystems.textsecuregcm.storage.Device;
|
||||||
import org.whispersystems.textsecuregcm.util.Pair;
|
import org.whispersystems.textsecuregcm.util.Pair;
|
||||||
|
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||||
|
|
||||||
class ApnPushNotificationSchedulerTest {
|
class ApnPushNotificationSchedulerTest {
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ class ApnPushNotificationSchedulerTest {
|
||||||
private Device device;
|
private Device device;
|
||||||
|
|
||||||
private APNSender apnSender;
|
private APNSender apnSender;
|
||||||
private Clock clock;
|
private TestClock clock;
|
||||||
|
|
||||||
private ApnPushNotificationScheduler apnPushNotificationScheduler;
|
private ApnPushNotificationScheduler apnPushNotificationScheduler;
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ class ApnPushNotificationSchedulerTest {
|
||||||
when(accountsManager.getByAccountIdentifier(ACCOUNT_UUID)).thenReturn(Optional.of(account));
|
when(accountsManager.getByAccountIdentifier(ACCOUNT_UUID)).thenReturn(Optional.of(account));
|
||||||
|
|
||||||
apnSender = mock(APNSender.class);
|
apnSender = mock(APNSender.class);
|
||||||
clock = mock(Clock.class);
|
clock = TestClock.now();
|
||||||
|
|
||||||
apnPushNotificationScheduler = new ApnPushNotificationScheduler(REDIS_CLUSTER_EXTENSION.getRedisCluster(), apnSender, accountsManager, clock);
|
apnPushNotificationScheduler = new ApnPushNotificationScheduler(REDIS_CLUSTER_EXTENSION.getRedisCluster(), apnSender, accountsManager, clock);
|
||||||
}
|
}
|
||||||
|
@ -83,10 +84,10 @@ class ApnPushNotificationSchedulerTest {
|
||||||
assertTrue(
|
assertTrue(
|
||||||
apnPushNotificationScheduler.getPendingDestinationsForRecurringVoipNotifications(SlotHash.getSlot(endpoint), 1).isEmpty());
|
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);
|
apnPushNotificationScheduler.scheduleRecurringVoipNotification(account, device);
|
||||||
|
|
||||||
when(clock.millis()).thenReturn(currentTimeMillis);
|
clock.pin(Instant.ofEpochMilli(currentTimeMillis));
|
||||||
final List<String> pendingDestinations = apnPushNotificationScheduler.getPendingDestinationsForRecurringVoipNotifications(SlotHash.getSlot(endpoint), 2);
|
final List<String> pendingDestinations = apnPushNotificationScheduler.getPendingDestinationsForRecurringVoipNotifications(SlotHash.getSlot(endpoint), 2);
|
||||||
assertEquals(1, pendingDestinations.size());
|
assertEquals(1, pendingDestinations.size());
|
||||||
|
|
||||||
|
@ -106,10 +107,10 @@ class ApnPushNotificationSchedulerTest {
|
||||||
final ApnPushNotificationScheduler.NotificationWorker worker = apnPushNotificationScheduler.new NotificationWorker();
|
final ApnPushNotificationScheduler.NotificationWorker worker = apnPushNotificationScheduler.new NotificationWorker();
|
||||||
final long currentTimeMillis = System.currentTimeMillis();
|
final long currentTimeMillis = System.currentTimeMillis();
|
||||||
|
|
||||||
when(clock.millis()).thenReturn(currentTimeMillis - 30_000);
|
clock.pin(Instant.ofEpochMilli(currentTimeMillis - 30_000));
|
||||||
apnPushNotificationScheduler.scheduleRecurringVoipNotification(account, device);
|
apnPushNotificationScheduler.scheduleRecurringVoipNotification(account, device);
|
||||||
|
|
||||||
when(clock.millis()).thenReturn(currentTimeMillis);
|
clock.pin(Instant.ofEpochMilli(currentTimeMillis));
|
||||||
|
|
||||||
final int slot = SlotHash.getSlot(ApnPushNotificationScheduler.getEndpointKey(account, device));
|
final int slot = SlotHash.getSlot(ApnPushNotificationScheduler.getEndpointKey(account, device));
|
||||||
|
|
||||||
|
@ -130,7 +131,7 @@ class ApnPushNotificationSchedulerTest {
|
||||||
@Test
|
@Test
|
||||||
void testScheduleBackgroundNotificationWithNoRecentNotification() {
|
void testScheduleBackgroundNotificationWithNoRecentNotification() {
|
||||||
final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
||||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
clock.pin(now);
|
||||||
|
|
||||||
assertEquals(Optional.empty(),
|
assertEquals(Optional.empty(),
|
||||||
apnPushNotificationScheduler.getLastBackgroundNotificationTimestamp(account, device));
|
apnPushNotificationScheduler.getLastBackgroundNotificationTimestamp(account, device));
|
||||||
|
@ -151,10 +152,10 @@ class ApnPushNotificationSchedulerTest {
|
||||||
now.minus(ApnPushNotificationScheduler.BACKGROUND_NOTIFICATION_PERIOD.dividedBy(2));
|
now.minus(ApnPushNotificationScheduler.BACKGROUND_NOTIFICATION_PERIOD.dividedBy(2));
|
||||||
|
|
||||||
// Insert a timestamp for a recently-sent background push notification
|
// 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);
|
apnPushNotificationScheduler.sendBackgroundNotification(account, device);
|
||||||
|
|
||||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
clock.pin(now);
|
||||||
apnPushNotificationScheduler.scheduleBackgroundNotification(account, device);
|
apnPushNotificationScheduler.scheduleBackgroundNotification(account, device);
|
||||||
|
|
||||||
final Instant expectedScheduledTimestamp =
|
final Instant expectedScheduledTimestamp =
|
||||||
|
@ -170,16 +171,16 @@ class ApnPushNotificationSchedulerTest {
|
||||||
|
|
||||||
final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
||||||
|
|
||||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
clock.pin(Instant.ofEpochMilli(now.toEpochMilli()));
|
||||||
apnPushNotificationScheduler.scheduleBackgroundNotification(account, device);
|
apnPushNotificationScheduler.scheduleBackgroundNotification(account, device);
|
||||||
|
|
||||||
final int slot =
|
final int slot =
|
||||||
SlotHash.getSlot(ApnPushNotificationScheduler.getPendingBackgroundNotificationQueueKey(account, device));
|
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));
|
assertEquals(0, worker.processScheduledBackgroundNotifications(slot));
|
||||||
|
|
||||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
clock.pin(now);
|
||||||
assertEquals(1, worker.processScheduledBackgroundNotifications(slot));
|
assertEquals(1, worker.processScheduledBackgroundNotifications(slot));
|
||||||
|
|
||||||
final ArgumentCaptor<PushNotification> notificationCaptor = ArgumentCaptor.forClass(PushNotification.class);
|
final ArgumentCaptor<PushNotification> notificationCaptor = ArgumentCaptor.forClass(PushNotification.class);
|
||||||
|
@ -203,7 +204,7 @@ class ApnPushNotificationSchedulerTest {
|
||||||
|
|
||||||
final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
||||||
|
|
||||||
when(clock.millis()).thenReturn(now.toEpochMilli());
|
clock.pin(now);
|
||||||
apnPushNotificationScheduler.scheduleBackgroundNotification(account, device);
|
apnPushNotificationScheduler.scheduleBackgroundNotification(account, device);
|
||||||
apnPushNotificationScheduler.cancelScheduledNotifications(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.tests.util.DevicesHelper;
|
||||||
import org.whispersystems.textsecuregcm.util.AttributeValues;
|
import org.whispersystems.textsecuregcm.util.AttributeValues;
|
||||||
import org.whispersystems.textsecuregcm.util.SystemMapper;
|
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.DynamoDbAsyncClient;
|
||||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||||
|
@ -78,7 +79,7 @@ class AccountsTest {
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private Clock mockClock;
|
private TestClock clock = TestClock.pinned(Instant.EPOCH);
|
||||||
private DynamicConfigurationManager<DynamicConfiguration> mockDynamicConfigManager;
|
private DynamicConfigurationManager<DynamicConfiguration> mockDynamicConfigManager;
|
||||||
private Accounts accounts;
|
private Accounts accounts;
|
||||||
|
|
||||||
|
@ -135,11 +136,8 @@ class AccountsTest {
|
||||||
when(mockDynamicConfigManager.getConfiguration())
|
when(mockDynamicConfigManager.getConfiguration())
|
||||||
.thenReturn(new DynamicConfiguration());
|
.thenReturn(new DynamicConfiguration());
|
||||||
|
|
||||||
mockClock = mock(Clock.class);
|
|
||||||
when(mockClock.instant()).thenReturn(Instant.EPOCH);
|
|
||||||
|
|
||||||
this.accounts = new Accounts(
|
this.accounts = new Accounts(
|
||||||
mockClock,
|
clock,
|
||||||
mockDynamicConfigManager,
|
mockDynamicConfigManager,
|
||||||
dynamoDbExtension.getDynamoDbClient(),
|
dynamoDbExtension.getDynamoDbClient(),
|
||||||
dynamoDbExtension.getDynamoDbAsyncClient(),
|
dynamoDbExtension.getDynamoDbAsyncClient(),
|
||||||
|
@ -810,12 +808,12 @@ class AccountsTest {
|
||||||
Supplier<UUID> take = () -> accounts.reserveUsername(account2, username, Duration.ofDays(2));
|
Supplier<UUID> take = () -> accounts.reserveUsername(account2, username, Duration.ofDays(2));
|
||||||
|
|
||||||
for (int i = 0; i <= 2; i++) {
|
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);
|
assertThrows(ContestedOptimisticLockException.class, take::get);
|
||||||
}
|
}
|
||||||
|
|
||||||
// after 2 days, can take the name
|
// 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();
|
final UUID token = take.get();
|
||||||
|
|
||||||
assertThrows(ContestedOptimisticLockException.class,
|
assertThrows(ContestedOptimisticLockException.class,
|
||||||
|
@ -840,12 +838,12 @@ class AccountsTest {
|
||||||
Runnable take = () -> accounts.setUsername(account2, username);
|
Runnable take = () -> accounts.setUsername(account2, username);
|
||||||
|
|
||||||
for (int i = 0; i <= 2; i++) {
|
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);
|
assertThrows(ContestedOptimisticLockException.class, take::run);
|
||||||
}
|
}
|
||||||
|
|
||||||
// after 2 days, can take the name
|
// 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();
|
take.run();
|
||||||
|
|
||||||
assertThrows(ContestedOptimisticLockException.class,
|
assertThrows(ContestedOptimisticLockException.class,
|
||||||
|
|
|
@ -61,6 +61,7 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
|
||||||
import org.whispersystems.textsecuregcm.storage.RedeemedReceiptsManager;
|
import org.whispersystems.textsecuregcm.storage.RedeemedReceiptsManager;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||||
|
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||||
|
|
||||||
class DonationControllerTest {
|
class DonationControllerTest {
|
||||||
|
|
||||||
|
@ -99,7 +100,7 @@ class DonationControllerTest {
|
||||||
Map.of(1L, "TEST1", 2L, "TEST2", 3L, "TEST3"));
|
Map.of(1L, "TEST1", 2L, "TEST2", 3L, "TEST3"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Clock clock;
|
Clock clock = TestClock.pinned(Instant.ofEpochSecond(nowEpochSeconds));
|
||||||
ServerZkReceiptOperations zkReceiptOperations;
|
ServerZkReceiptOperations zkReceiptOperations;
|
||||||
RedeemedReceiptsManager redeemedReceiptsManager;
|
RedeemedReceiptsManager redeemedReceiptsManager;
|
||||||
AccountsManager accountsManager;
|
AccountsManager accountsManager;
|
||||||
|
@ -112,7 +113,6 @@ class DonationControllerTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void beforeEach() throws Throwable {
|
void beforeEach() throws Throwable {
|
||||||
clock = mock(Clock.class);
|
|
||||||
zkReceiptOperations = mock(ServerZkReceiptOperations.class);
|
zkReceiptOperations = mock(ServerZkReceiptOperations.class);
|
||||||
redeemedReceiptsManager = mock(RedeemedReceiptsManager.class);
|
redeemedReceiptsManager = mock(RedeemedReceiptsManager.class);
|
||||||
accountsManager = mock(AccountsManager.class);
|
accountsManager = mock(AccountsManager.class);
|
||||||
|
@ -125,9 +125,6 @@ class DonationControllerTest {
|
||||||
receiptCredentialPresentationFactory = mock(DonationController.ReceiptCredentialPresentationFactory.class);
|
receiptCredentialPresentationFactory = mock(DonationController.ReceiptCredentialPresentationFactory.class);
|
||||||
receiptCredentialPresentation = mock(ReceiptCredentialPresentation.class);
|
receiptCredentialPresentation = mock(ReceiptCredentialPresentation.class);
|
||||||
|
|
||||||
when(clock.millis()).thenReturn(nowEpochSeconds * 1000L);
|
|
||||||
when(clock.instant()).thenReturn(Instant.ofEpochSecond(nowEpochSeconds));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
when(receiptCredentialPresentationFactory.build(presentation)).thenReturn(receiptCredentialPresentation);
|
when(receiptCredentialPresentationFactory.build(presentation)).thenReturn(receiptCredentialPresentation);
|
||||||
} catch (InvalidInputException e) {
|
} 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;
|
||||||
import org.whispersystems.textsecuregcm.storage.Device.DeviceCapabilities;
|
import org.whispersystems.textsecuregcm.storage.Device.DeviceCapabilities;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||||
|
import org.whispersystems.textsecuregcm.util.TestClock;
|
||||||
|
|
||||||
class AccountTest {
|
class AccountTest {
|
||||||
|
|
||||||
|
@ -442,8 +443,7 @@ class AccountTest {
|
||||||
@Test
|
@Test
|
||||||
void addAndRemoveBadges() {
|
void addAndRemoveBadges() {
|
||||||
final Account account = AccountsHelper.generateTestAccount("+14151234567", UUID.randomUUID(), UUID.randomUUID(), List.of(createDevice(Device.MASTER_ID)), new byte[0]);
|
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);
|
final Clock clock = TestClock.pinned(Instant.ofEpochSecond(40));
|
||||||
when(clock.instant()).thenReturn(Instant.ofEpochSecond(40));
|
|
||||||
|
|
||||||
account.addBadge(clock, new AccountBadge("foo", Instant.ofEpochSecond(42), false));
|
account.addBadge(clock, new AccountBadge("foo", Instant.ofEpochSecond(42), false));
|
||||||
account.addBadge(clock, new AccountBadge("bar", Instant.ofEpochSecond(44), true));
|
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.DynamoDbExtension;
|
||||||
import org.whispersystems.textsecuregcm.storage.RedeemedReceiptsManager;
|
import org.whispersystems.textsecuregcm.storage.RedeemedReceiptsManager;
|
||||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
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.AttributeDefinition;
|
||||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||||
|
|
||||||
|
@ -42,15 +43,12 @@ class RedeemedReceiptsManagerTest {
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Clock clock;
|
Clock clock = TestClock.pinned(Instant.ofEpochSecond(NOW_EPOCH_SECONDS));
|
||||||
ReceiptSerial receiptSerial;
|
ReceiptSerial receiptSerial;
|
||||||
RedeemedReceiptsManager redeemedReceiptsManager;
|
RedeemedReceiptsManager redeemedReceiptsManager;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void beforeEach() throws InvalidInputException {
|
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];
|
byte[] receiptSerialBytes = new byte[ReceiptSerial.SIZE];
|
||||||
SECURE_RANDOM.nextBytes(receiptSerialBytes);
|
SECURE_RANDOM.nextBytes(receiptSerialBytes);
|
||||||
receiptSerial = new ReceiptSerial(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