DynamoDBExtension refactor and helpers for our schema (#1327)
There's a lot of boilerplate involved in setting up a DynamoDBExtension, and some tests were creating several extensions rather than one with several tables, which is probably slower than it has to be. This change adds a new DynamoDbExtensionSchema class in which we can define the Dynamo schema for tests, and refactors DynamoDbExtension to make it easy to instantiate a single extension with all the tables one wants (and no more, both to minimize test startup time and to ensure we explicitly test our dependencies and lack thereof). Tests requiring a DynamoDbExtension with a table schema that's not part of the normal Signal schema can instantiate a DynamoDbExtension.RawSchema instead. Test timings are unaffected, at least on my machine. Before: ```[INFO] service ............................................ SUCCESS [01:18 min]``` After: ```[INFO] service ............................................ SUCCESS [01:18 min]``` Co-authored-by: Jonathan Klabunde Tomer <jkt@viola.signal.org>
This commit is contained in:
parent
f5726f63bd
commit
48ebafa4e0
|
@ -45,11 +45,17 @@ import software.amazon.awssdk.services.dynamodb.model.WriteRequest;
|
|||
|
||||
public class MessagesDynamoDb extends AbstractDynamoDbStore {
|
||||
|
||||
private static final String KEY_PARTITION = "H";
|
||||
private static final String KEY_SORT = "S";
|
||||
@VisibleForTesting
|
||||
static final String KEY_PARTITION = "H";
|
||||
|
||||
private static final String LOCAL_INDEX_MESSAGE_UUID_NAME = "Message_UUID_Index";
|
||||
private static final String LOCAL_INDEX_MESSAGE_UUID_KEY_SORT = "U";
|
||||
@VisibleForTesting
|
||||
static final String KEY_SORT = "S";
|
||||
|
||||
@VisibleForTesting
|
||||
static final String LOCAL_INDEX_MESSAGE_UUID_NAME = "Message_UUID_Index";
|
||||
|
||||
@VisibleForTesting
|
||||
static final String LOCAL_INDEX_MESSAGE_UUID_KEY_SORT = "U";
|
||||
|
||||
private static final String KEY_TTL = "E";
|
||||
private static final String KEY_ENVELOPE_BYTES = "EB";
|
||||
|
|
|
@ -34,78 +34,28 @@ import org.whispersystems.textsecuregcm.securebackup.SecureBackupClient;
|
|||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecovery2Client;
|
||||
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GlobalSecondaryIndex;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.Projection;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Indexes;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
|
||||
class AccountsManagerChangeNumberIntegrationTest {
|
||||
|
||||
private static final String ACCOUNTS_TABLE_NAME = "accounts_test";
|
||||
private static final String NUMBERS_TABLE_NAME = "numbers_test";
|
||||
private static final String PNI_ASSIGNMENT_TABLE_NAME = "pni_assignment_test";
|
||||
private static final String USERNAMES_TABLE_NAME = "usernames_test";
|
||||
private static final String PNI_TABLE_NAME = "pni_test";
|
||||
private static final String NEEDS_RECONCILIATION_INDEX_NAME = "needs_reconciliation_test";
|
||||
private static final String DELETED_ACCOUNTS_LOCK_TABLE_NAME = "deleted_accounts_lock_test";
|
||||
private static final int SCAN_PAGE_SIZE = 1;
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension ACCOUNTS_DYNAMO_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(ACCOUNTS_TABLE_NAME)
|
||||
.hashKey(Accounts.KEY_ACCOUNT_UUID)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(
|
||||
Tables.ACCOUNTS,
|
||||
Tables.DELETED_ACCOUNTS,
|
||||
Tables.DELETED_ACCOUNTS_LOCK,
|
||||
Tables.NUMBERS,
|
||||
Tables.PNI,
|
||||
Tables.PNI_ASSIGNMENTS,
|
||||
Tables.USERNAMES);
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension DELETED_ACCOUNTS_DYNAMO_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName("deleted_accounts_test")
|
||||
.hashKey(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S).build())
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.ATTR_NEEDS_CDS_RECONCILIATION)
|
||||
.attributeType(ScalarAttributeType.N)
|
||||
.build())
|
||||
.globalSecondaryIndex(GlobalSecondaryIndex.builder()
|
||||
.indexName(NEEDS_RECONCILIATION_INDEX_NAME)
|
||||
.keySchema(KeySchemaElement.builder().attributeName(DeletedAccounts.KEY_ACCOUNT_E164).keyType(KeyType.HASH).build(),
|
||||
KeySchemaElement.builder().attributeName(DeletedAccounts.ATTR_NEEDS_CDS_RECONCILIATION).keyType(KeyType.RANGE).build())
|
||||
.projection(Projection.builder().projectionType(ProjectionType.INCLUDE).nonKeyAttributes(DeletedAccounts.ATTR_ACCOUNT_UUID).build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension DELETED_ACCOUNTS_LOCK_DYNAMO_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(DELETED_ACCOUNTS_LOCK_TABLE_NAME)
|
||||
.hashKey(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S).build())
|
||||
.build();
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension PNI_DYNAMO_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(PNI_TABLE_NAME)
|
||||
.hashKey(PhoneNumberIdentifiers.KEY_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(PhoneNumberIdentifiers.KEY_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
@RegisterExtension
|
||||
static RedisClusterExtension CACHE_CLUSTER_EXTENSION = RedisClusterExtension.builder().build();
|
||||
static final RedisClusterExtension CACHE_CLUSTER_EXTENSION = RedisClusterExtension.builder().build();
|
||||
|
||||
private ClientPresenceManager clientPresenceManager;
|
||||
private DeletedAccounts deletedAccounts;
|
||||
|
@ -115,40 +65,6 @@ class AccountsManagerChangeNumberIntegrationTest {
|
|||
@BeforeEach
|
||||
void setup() throws InterruptedException {
|
||||
|
||||
{
|
||||
CreateTableRequest createNumbersTableRequest = CreateTableRequest.builder()
|
||||
.tableName(NUMBERS_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_ACCOUNT_E164)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient().createTable(createNumbersTableRequest);
|
||||
}
|
||||
|
||||
{
|
||||
CreateTableRequest createPhoneNumberIdentifierTableRequest = CreateTableRequest.builder()
|
||||
.tableName(PNI_ASSIGNMENT_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_PNI_UUID)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_PNI_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient().createTable(createPhoneNumberIdentifierTableRequest);
|
||||
}
|
||||
|
||||
{
|
||||
@SuppressWarnings("unchecked") final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager =
|
||||
mock(DynamicConfigurationManager.class);
|
||||
|
@ -157,21 +73,21 @@ class AccountsManagerChangeNumberIntegrationTest {
|
|||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(dynamicConfiguration);
|
||||
|
||||
final Accounts accounts = new Accounts(
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient(),
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbAsyncClient(),
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getTableName(),
|
||||
NUMBERS_TABLE_NAME,
|
||||
PNI_ASSIGNMENT_TABLE_NAME,
|
||||
USERNAMES_TABLE_NAME,
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
Tables.ACCOUNTS.tableName(),
|
||||
Tables.NUMBERS.tableName(),
|
||||
Tables.PNI_ASSIGNMENTS.tableName(),
|
||||
Tables.USERNAMES.tableName(),
|
||||
SCAN_PAGE_SIZE);
|
||||
|
||||
deletedAccounts = new DeletedAccounts(DELETED_ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient(),
|
||||
DELETED_ACCOUNTS_DYNAMO_EXTENSION.getTableName(),
|
||||
NEEDS_RECONCILIATION_INDEX_NAME);
|
||||
deletedAccounts = new DeletedAccounts(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
Tables.DELETED_ACCOUNTS.tableName(),
|
||||
Indexes.DELETED_ACCOUNTS_NEEDS_RECONCILIATION.indexName());
|
||||
|
||||
final DeletedAccountsManager deletedAccountsManager = new DeletedAccountsManager(deletedAccounts,
|
||||
DELETED_ACCOUNTS_LOCK_DYNAMO_EXTENSION.getLegacyDynamoClient(),
|
||||
DELETED_ACCOUNTS_LOCK_DYNAMO_EXTENSION.getTableName());
|
||||
DYNAMO_DB_EXTENSION.getLegacyDynamoClient(),
|
||||
Tables.DELETED_ACCOUNTS_LOCK.tableName());
|
||||
|
||||
final SecureStorageClient secureStorageClient = mock(SecureStorageClient.class);
|
||||
when(secureStorageClient.deleteStoredData(any())).thenReturn(CompletableFuture.completedFuture(null));
|
||||
|
@ -185,7 +101,7 @@ class AccountsManagerChangeNumberIntegrationTest {
|
|||
clientPresenceManager = mock(ClientPresenceManager.class);
|
||||
|
||||
final PhoneNumberIdentifiers phoneNumberIdentifiers =
|
||||
new PhoneNumberIdentifiers(PNI_DYNAMO_EXTENSION.getDynamoDbClient(), PNI_TABLE_NAME);
|
||||
new PhoneNumberIdentifiers(DYNAMO_DB_EXTENSION.getDynamoDbClient(), Tables.PNI.tableName());
|
||||
|
||||
accountsManager = new AccountsManager(
|
||||
accounts,
|
||||
|
|
|
@ -48,34 +48,23 @@ import org.whispersystems.textsecuregcm.securebackup.SecureBackupClient;
|
|||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecovery2Client;
|
||||
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.tests.util.DevicesHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.JsonHelpers;
|
||||
import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
|
||||
class AccountsManagerConcurrentModificationIntegrationTest {
|
||||
|
||||
private static final String ACCOUNTS_TABLE_NAME = "accounts_test";
|
||||
private static final String NUMBERS_TABLE_NAME = "numbers_test";
|
||||
private static final String PNI_TABLE_NAME = "pni_test";
|
||||
private static final String USERNAMES_TABLE_NAME = "usernames_test";
|
||||
|
||||
private static final int SCAN_PAGE_SIZE = 1;
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName(ACCOUNTS_TABLE_NAME)
|
||||
.hashKey(Accounts.KEY_ACCOUNT_UUID)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(
|
||||
Tables.ACCOUNTS,
|
||||
Tables.NUMBERS,
|
||||
Tables.PNI_ASSIGNMENTS
|
||||
);
|
||||
|
||||
private Accounts accounts;
|
||||
|
||||
|
@ -88,51 +77,17 @@ class AccountsManagerConcurrentModificationIntegrationTest {
|
|||
@BeforeEach
|
||||
void setup() throws InterruptedException {
|
||||
|
||||
{
|
||||
CreateTableRequest createNumbersTableRequest = CreateTableRequest.builder()
|
||||
.tableName(NUMBERS_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_ACCOUNT_E164)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
dynamoDbExtension.getDynamoDbClient().createTable(createNumbersTableRequest);
|
||||
}
|
||||
|
||||
{
|
||||
CreateTableRequest createPhoneNumberIdentifierTableRequest = CreateTableRequest.builder()
|
||||
.tableName(PNI_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_PNI_UUID)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_PNI_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
dynamoDbExtension.getDynamoDbClient().createTable(createPhoneNumberIdentifierTableRequest);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") final DynamicConfigurationManager<DynamicConfiguration> dynamicConfigurationManager =
|
||||
mock(DynamicConfigurationManager.class);
|
||||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(new DynamicConfiguration());
|
||||
|
||||
accounts = new Accounts(
|
||||
dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(),
|
||||
dynamoDbExtension.getTableName(),
|
||||
NUMBERS_TABLE_NAME,
|
||||
PNI_TABLE_NAME,
|
||||
USERNAMES_TABLE_NAME,
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
Tables.ACCOUNTS.tableName(),
|
||||
Tables.NUMBERS.tableName(),
|
||||
Tables.PNI_ASSIGNMENTS.tableName(),
|
||||
Tables.USERNAMES.tableName(),
|
||||
SCAN_PAGE_SIZE);
|
||||
|
||||
{
|
||||
|
|
|
@ -45,23 +45,14 @@ import org.whispersystems.textsecuregcm.securebackup.SecureBackupClient;
|
|||
import org.whispersystems.textsecuregcm.securestorage.SecureStorageClient;
|
||||
import org.whispersystems.textsecuregcm.securevaluerecovery.SecureValueRecovery2Client;
|
||||
import org.whispersystems.textsecuregcm.sqs.DirectoryQueue;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.util.AttributeValues;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
||||
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
|
||||
|
||||
class AccountsManagerUsernameIntegrationTest {
|
||||
|
||||
private static final String ACCOUNTS_TABLE_NAME = "accounts_test";
|
||||
private static final String NUMBERS_TABLE_NAME = "numbers_test";
|
||||
private static final String PNI_ASSIGNMENT_TABLE_NAME = "pni_assignment_test";
|
||||
private static final String USERNAMES_TABLE_NAME = "usernames_test";
|
||||
private static final String PNI_TABLE_NAME = "pni_test";
|
||||
private static final String BASE_64_URL_USERNAME_HASH_1 = "9p6Tip7BFefFOJzv4kv4GyXEYsBVfk_WbjNejdlOvQE";
|
||||
private static final String BASE_64_URL_USERNAME_HASH_2 = "NLUom-CHwtemcdvOTTXdmXmzRIV7F05leS8lwkVK_vc";
|
||||
private static final int SCAN_PAGE_SIZE = 1;
|
||||
|
@ -69,24 +60,12 @@ class AccountsManagerUsernameIntegrationTest {
|
|||
private static final byte[] USERNAME_HASH_2 = Base64.getUrlDecoder().decode(BASE_64_URL_USERNAME_HASH_2);
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension ACCOUNTS_DYNAMO_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(ACCOUNTS_TABLE_NAME)
|
||||
.hashKey(Accounts.KEY_ACCOUNT_UUID)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension PNI_DYNAMO_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(PNI_TABLE_NAME)
|
||||
.hashKey(PhoneNumberIdentifiers.KEY_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(PhoneNumberIdentifiers.KEY_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(
|
||||
Tables.ACCOUNTS,
|
||||
Tables.NUMBERS,
|
||||
Tables.USERNAMES,
|
||||
Tables.PNI,
|
||||
Tables.PNI_ASSIGNMENTS);
|
||||
|
||||
@RegisterExtension
|
||||
static RedisClusterExtension CACHE_CLUSTER_EXTENSION = RedisClusterExtension.builder().build();
|
||||
|
@ -96,48 +75,6 @@ class AccountsManagerUsernameIntegrationTest {
|
|||
|
||||
@BeforeEach
|
||||
void setup() throws InterruptedException {
|
||||
CreateTableRequest createNumbersTableRequest = CreateTableRequest.builder()
|
||||
.tableName(NUMBERS_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_ACCOUNT_E164)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient().createTable(createNumbersTableRequest);
|
||||
CreateTableRequest createUsernamesTableRequest = CreateTableRequest.builder()
|
||||
.tableName(USERNAMES_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_USERNAME_HASH)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_USERNAME_HASH)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient().createTable(createUsernamesTableRequest);
|
||||
CreateTableRequest createPhoneNumberIdentifierTableRequest = CreateTableRequest.builder()
|
||||
.tableName(PNI_ASSIGNMENT_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_PNI_UUID)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_PNI_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient().createTable(createPhoneNumberIdentifierTableRequest);
|
||||
buildAccountsManager(1, 2, 10);
|
||||
}
|
||||
|
||||
|
@ -150,12 +87,12 @@ class AccountsManagerUsernameIntegrationTest {
|
|||
when(dynamicConfigurationManager.getConfiguration()).thenReturn(dynamicConfiguration);
|
||||
|
||||
accounts = Mockito.spy(new Accounts(
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient(),
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbAsyncClient(),
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getTableName(),
|
||||
NUMBERS_TABLE_NAME,
|
||||
PNI_ASSIGNMENT_TABLE_NAME,
|
||||
USERNAMES_TABLE_NAME,
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
Tables.ACCOUNTS.tableName(),
|
||||
Tables.NUMBERS.tableName(),
|
||||
Tables.PNI_ASSIGNMENTS.tableName(),
|
||||
Tables.USERNAMES.tableName(),
|
||||
SCAN_PAGE_SIZE));
|
||||
|
||||
final DeletedAccountsManager deletedAccountsManager = mock(DeletedAccountsManager.class);
|
||||
|
@ -167,7 +104,7 @@ class AccountsManagerUsernameIntegrationTest {
|
|||
}).when(deletedAccountsManager).lockAndTake(any(), any());
|
||||
|
||||
final PhoneNumberIdentifiers phoneNumberIdentifiers =
|
||||
new PhoneNumberIdentifiers(PNI_DYNAMO_EXTENSION.getDynamoDbClient(), PNI_TABLE_NAME);
|
||||
new PhoneNumberIdentifiers(DYNAMO_DB_EXTENSION.getDynamoDbClient(), Tables.PNI.tableName());
|
||||
|
||||
final ExperimentEnrollmentManager experimentEnrollmentManager = mock(ExperimentEnrollmentManager.class);
|
||||
when(experimentEnrollmentManager.isEnrolled(any(UUID.class), eq(AccountsManager.USERNAME_EXPERIMENT_NAME)))
|
||||
|
@ -207,8 +144,8 @@ class AccountsManagerUsernameIntegrationTest {
|
|||
AttributeValues.fromLong(Instant.now().plus(Duration.ofMinutes(1)).getEpochSecond()));
|
||||
}
|
||||
i++;
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient().putItem(PutItemRequest.builder()
|
||||
.tableName(USERNAMES_TABLE_NAME)
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient().putItem(PutItemRequest.builder()
|
||||
.tableName(Tables.USERNAMES.tableName())
|
||||
.item(item)
|
||||
.build());
|
||||
}
|
||||
|
@ -222,8 +159,8 @@ class AccountsManagerUsernameIntegrationTest {
|
|||
new ArrayList<>());
|
||||
ArrayList<byte[]> usernameHashes = new ArrayList<>(Arrays.asList(USERNAME_HASH_1, USERNAME_HASH_2));
|
||||
for (byte[] hash : usernameHashes) {
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient().putItem(PutItemRequest.builder()
|
||||
.tableName(USERNAMES_TABLE_NAME)
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient().putItem(PutItemRequest.builder()
|
||||
.tableName(Tables.USERNAMES.tableName())
|
||||
.item(Map.of(
|
||||
Accounts.KEY_ACCOUNT_UUID, AttributeValues.fromUUID(UUID.randomUUID()),
|
||||
Accounts.ATTR_USERNAME_HASH, AttributeValues.fromByteArray(hash)))
|
||||
|
@ -287,8 +224,8 @@ class AccountsManagerUsernameIntegrationTest {
|
|||
|
||||
long past = Instant.now().minus(Duration.ofMinutes(1)).getEpochSecond();
|
||||
// force expiration
|
||||
ACCOUNTS_DYNAMO_EXTENSION.getDynamoDbClient().updateItem(UpdateItemRequest.builder()
|
||||
.tableName(USERNAMES_TABLE_NAME)
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient().updateItem(UpdateItemRequest.builder()
|
||||
.tableName(Tables.USERNAMES.tableName())
|
||||
.key(Map.of(Accounts.ATTR_USERNAME_HASH, AttributeValues.fromByteArray(USERNAME_HASH_1)))
|
||||
.updateExpression("SET #ttl = :ttl")
|
||||
.expressionAttributeNames(Map.of("#ttl", Accounts.ATTR_TTL))
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
|||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AccountsHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.DevicesHelper;
|
||||
import org.whispersystems.textsecuregcm.util.AttributeValues;
|
||||
|
@ -45,18 +46,13 @@ 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;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
|
||||
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.Put;
|
||||
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ReturnValuesOnConditionCheckFailure;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.TransactWriteItem;
|
||||
import software.amazon.awssdk.services.dynamodb.model.TransactWriteItemsRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.TransactionCanceledException;
|
||||
|
@ -65,10 +61,6 @@ import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
|
|||
|
||||
class AccountsTest {
|
||||
|
||||
private static final String ACCOUNTS_TABLE_NAME = "accounts_test";
|
||||
private static final String NUMBER_CONSTRAINT_TABLE_NAME = "numbers_test";
|
||||
private static final String PNI_CONSTRAINT_TABLE_NAME = "pni_test";
|
||||
private static final String USERNAME_CONSTRAINT_TABLE_NAME = "username_test";
|
||||
private static final String BASE_64_URL_USERNAME_HASH_1 = "9p6Tip7BFefFOJzv4kv4GyXEYsBVfk_WbjNejdlOvQE";
|
||||
private static final String BASE_64_URL_USERNAME_HASH_2 = "NLUom-CHwtemcdvOTTXdmXmzRIV7F05leS8lwkVK_vc";
|
||||
private static final byte[] USERNAME_HASH_1 = Base64.getUrlDecoder().decode(BASE_64_URL_USERNAME_HASH_1);
|
||||
|
@ -77,16 +69,12 @@ class AccountsTest {
|
|||
private static final int SCAN_PAGE_SIZE = 1;
|
||||
|
||||
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName(ACCOUNTS_TABLE_NAME)
|
||||
.hashKey(Accounts.KEY_ACCOUNT_UUID)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(
|
||||
Tables.ACCOUNTS,
|
||||
Tables.NUMBERS,
|
||||
Tables.PNI_ASSIGNMENTS,
|
||||
Tables.USERNAMES);
|
||||
|
||||
private final TestClock clock = TestClock.pinned(Instant.EPOCH);
|
||||
private DynamicConfigurationManager<DynamicConfiguration> mockDynamicConfigManager;
|
||||
|
@ -94,50 +82,6 @@ class AccountsTest {
|
|||
|
||||
@BeforeEach
|
||||
void setupAccountsDao() {
|
||||
CreateTableRequest createNumbersTableRequest = CreateTableRequest.builder()
|
||||
.tableName(NUMBER_CONSTRAINT_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_ACCOUNT_E164)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
dynamoDbExtension.getDynamoDbClient().createTable(createNumbersTableRequest);
|
||||
|
||||
CreateTableRequest createPhoneNumberIdentifierTableRequest = CreateTableRequest.builder()
|
||||
.tableName(PNI_CONSTRAINT_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_PNI_UUID)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_PNI_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
dynamoDbExtension.getDynamoDbClient().createTable(createPhoneNumberIdentifierTableRequest);
|
||||
|
||||
CreateTableRequest createUsernamesTableRequest = CreateTableRequest.builder()
|
||||
.tableName(USERNAME_CONSTRAINT_TABLE_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(Accounts.ATTR_USERNAME_HASH)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.attributeDefinitions(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_USERNAME_HASH)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.provisionedThroughput(DynamoDbExtension.DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
dynamoDbExtension.getDynamoDbClient().createTable(createUsernamesTableRequest);
|
||||
|
||||
@SuppressWarnings("unchecked") DynamicConfigurationManager<DynamicConfiguration> m = mock(DynamicConfigurationManager.class);
|
||||
mockDynamicConfigManager = m;
|
||||
|
@ -147,12 +91,12 @@ class AccountsTest {
|
|||
|
||||
this.accounts = new Accounts(
|
||||
clock,
|
||||
dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(),
|
||||
dynamoDbExtension.getTableName(),
|
||||
NUMBER_CONSTRAINT_TABLE_NAME,
|
||||
PNI_CONSTRAINT_TABLE_NAME,
|
||||
USERNAME_CONSTRAINT_TABLE_NAME,
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
Tables.ACCOUNTS.tableName(),
|
||||
Tables.NUMBERS.tableName(),
|
||||
Tables.PNI_ASSIGNMENTS.tableName(),
|
||||
Tables.USERNAMES.tableName(),
|
||||
SCAN_PAGE_SIZE);
|
||||
}
|
||||
|
||||
|
@ -247,7 +191,7 @@ class AccountsTest {
|
|||
final TransactWriteItem phoneNumberConstraintPut = TransactWriteItem.builder()
|
||||
.put(
|
||||
Put.builder()
|
||||
.tableName(NUMBER_CONSTRAINT_TABLE_NAME)
|
||||
.tableName(Tables.NUMBERS.tableName())
|
||||
.item(Map.of(
|
||||
Accounts.ATTR_ACCOUNT_E164, AttributeValues.fromString(account.getNumber()),
|
||||
Accounts.KEY_ACCOUNT_UUID, AttributeValues.fromUUID(account.getUuid())))
|
||||
|
@ -264,7 +208,7 @@ class AccountsTest {
|
|||
|
||||
final TransactWriteItem accountPut = TransactWriteItem.builder()
|
||||
.put(Put.builder()
|
||||
.tableName(ACCOUNTS_TABLE_NAME)
|
||||
.tableName(Tables.ACCOUNTS.tableName())
|
||||
.conditionExpression("attribute_not_exists(#number) OR #number = :number")
|
||||
.expressionAttributeNames(Map.of("#number", Accounts.ATTR_ACCOUNT_E164))
|
||||
.expressionAttributeValues(Map.of(":number", AttributeValues.fromString(account.getNumber())))
|
||||
|
@ -277,7 +221,7 @@ class AccountsTest {
|
|||
.build())
|
||||
.build();
|
||||
|
||||
dynamoDbExtension.getDynamoDbClient().transactWriteItems(TransactWriteItemsRequest.builder()
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient().transactWriteItems(TransactWriteItemsRequest.builder()
|
||||
.transactItems(phoneNumberConstraintPut, accountPut)
|
||||
.build());
|
||||
}
|
||||
|
@ -389,8 +333,8 @@ class AccountsTest {
|
|||
|
||||
final DynamoDbAsyncClient dynamoDbAsyncClient = mock(DynamoDbAsyncClient.class);
|
||||
accounts = new Accounts(mock(DynamoDbClient.class),
|
||||
dynamoDbAsyncClient, dynamoDbExtension.getTableName(),
|
||||
NUMBER_CONSTRAINT_TABLE_NAME, PNI_CONSTRAINT_TABLE_NAME, USERNAME_CONSTRAINT_TABLE_NAME, SCAN_PAGE_SIZE);
|
||||
dynamoDbAsyncClient, Tables.ACCOUNTS.tableName(),
|
||||
Tables.NUMBERS.tableName(), Tables.PNI_ASSIGNMENTS.tableName(), Tables.USERNAMES.tableName(), SCAN_PAGE_SIZE);
|
||||
|
||||
Exception e = TransactionConflictException.builder().build();
|
||||
e = wrapException ? new CompletionException(e) : e;
|
||||
|
@ -612,8 +556,8 @@ class AccountsTest {
|
|||
final UUID existingPhoneNumberIdentifier = UUID.randomUUID();
|
||||
|
||||
// Artificially inject a conflicting PNI entry
|
||||
dynamoDbExtension.getDynamoDbClient().putItem(PutItemRequest.builder()
|
||||
.tableName(PNI_CONSTRAINT_TABLE_NAME)
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient().putItem(PutItemRequest.builder()
|
||||
.tableName(Tables.PNI_ASSIGNMENTS.tableName())
|
||||
.item(Map.of(
|
||||
Accounts.ATTR_PNI_UUID, AttributeValues.fromUUID(existingPhoneNumberIdentifier),
|
||||
Accounts.KEY_ACCOUNT_UUID, AttributeValues.fromUUID(existingAccountIdentifier)))
|
||||
|
@ -649,9 +593,9 @@ class AccountsTest {
|
|||
accounts.confirmUsernameHash(account, USERNAME_HASH_2);
|
||||
|
||||
assertThat(accounts.getByUsernameHash(USERNAME_HASH_1)).isEmpty();
|
||||
assertThat(dynamoDbExtension.getDynamoDbClient()
|
||||
assertThat(DYNAMO_DB_EXTENSION.getDynamoDbClient()
|
||||
.getItem(GetItemRequest.builder()
|
||||
.tableName(USERNAME_CONSTRAINT_TABLE_NAME)
|
||||
.tableName(Tables.USERNAMES.tableName())
|
||||
.key(Map.of(Accounts.ATTR_USERNAME_HASH, AttributeValues.fromByteArray(USERNAME_HASH_1)))
|
||||
.build())
|
||||
.item()).isEmpty();
|
||||
|
@ -775,9 +719,9 @@ class AccountsTest {
|
|||
assertArrayEquals(account1.getUsernameHash().orElseThrow(), USERNAME_HASH_1);
|
||||
assertThat(accounts.getByUsernameHash(USERNAME_HASH_1).get().getUuid()).isEqualTo(account1.getUuid());
|
||||
|
||||
final Map<String, AttributeValue> usernameConstraintRecord = dynamoDbExtension.getDynamoDbClient()
|
||||
final Map<String, AttributeValue> usernameConstraintRecord = DYNAMO_DB_EXTENSION.getDynamoDbClient()
|
||||
.getItem(GetItemRequest.builder()
|
||||
.tableName(USERNAME_CONSTRAINT_TABLE_NAME)
|
||||
.tableName(Tables.USERNAMES.tableName())
|
||||
.key(Map.of(Accounts.ATTR_USERNAME_HASH, AttributeValues.fromByteArray(USERNAME_HASH_1)))
|
||||
.build())
|
||||
.item();
|
||||
|
@ -892,9 +836,9 @@ class AccountsTest {
|
|||
}
|
||||
|
||||
private void assertPhoneNumberConstraintExists(final String number, final UUID uuid) {
|
||||
final GetItemResponse numberConstraintResponse = dynamoDbExtension.getDynamoDbClient().getItem(
|
||||
final GetItemResponse numberConstraintResponse = DYNAMO_DB_EXTENSION.getDynamoDbClient().getItem(
|
||||
GetItemRequest.builder()
|
||||
.tableName(NUMBER_CONSTRAINT_TABLE_NAME)
|
||||
.tableName(Tables.NUMBERS.tableName())
|
||||
.key(Map.of(Accounts.ATTR_ACCOUNT_E164, AttributeValues.fromString(number)))
|
||||
.build());
|
||||
|
||||
|
@ -903,9 +847,9 @@ class AccountsTest {
|
|||
}
|
||||
|
||||
private void assertPhoneNumberConstraintDoesNotExist(final String number) {
|
||||
final GetItemResponse numberConstraintResponse = dynamoDbExtension.getDynamoDbClient().getItem(
|
||||
final GetItemResponse numberConstraintResponse = DYNAMO_DB_EXTENSION.getDynamoDbClient().getItem(
|
||||
GetItemRequest.builder()
|
||||
.tableName(NUMBER_CONSTRAINT_TABLE_NAME)
|
||||
.tableName(Tables.NUMBERS.tableName())
|
||||
.key(Map.of(Accounts.ATTR_ACCOUNT_E164, AttributeValues.fromString(number)))
|
||||
.build());
|
||||
|
||||
|
@ -913,9 +857,9 @@ class AccountsTest {
|
|||
}
|
||||
|
||||
private void assertPhoneNumberIdentifierConstraintExists(final UUID phoneNumberIdentifier, final UUID uuid) {
|
||||
final GetItemResponse pniConstraintResponse = dynamoDbExtension.getDynamoDbClient().getItem(
|
||||
final GetItemResponse pniConstraintResponse = DYNAMO_DB_EXTENSION.getDynamoDbClient().getItem(
|
||||
GetItemRequest.builder()
|
||||
.tableName(PNI_CONSTRAINT_TABLE_NAME)
|
||||
.tableName(Tables.PNI_ASSIGNMENTS.tableName())
|
||||
.key(Map.of(Accounts.ATTR_PNI_UUID, AttributeValues.fromUUID(phoneNumberIdentifier)))
|
||||
.build());
|
||||
|
||||
|
@ -924,9 +868,9 @@ class AccountsTest {
|
|||
}
|
||||
|
||||
private void assertPhoneNumberIdentifierConstraintDoesNotExist(final UUID phoneNumberIdentifier) {
|
||||
final GetItemResponse pniConstraintResponse = dynamoDbExtension.getDynamoDbClient().getItem(
|
||||
final GetItemResponse pniConstraintResponse = DYNAMO_DB_EXTENSION.getDynamoDbClient().getItem(
|
||||
GetItemRequest.builder()
|
||||
.tableName(PNI_CONSTRAINT_TABLE_NAME)
|
||||
.tableName(Tables.PNI_ASSIGNMENTS.tableName())
|
||||
.key(Map.of(Accounts.ATTR_PNI_UUID, AttributeValues.fromUUID(phoneNumberIdentifier)))
|
||||
.build());
|
||||
|
||||
|
@ -934,10 +878,10 @@ class AccountsTest {
|
|||
}
|
||||
|
||||
private void verifyStoredState(String number, UUID uuid, UUID pni, byte[] usernameHash, Account expecting, boolean canonicallyDiscoverable) {
|
||||
final DynamoDbClient db = dynamoDbExtension.getDynamoDbClient();
|
||||
final DynamoDbClient db = DYNAMO_DB_EXTENSION.getDynamoDbClient();
|
||||
|
||||
final GetItemResponse get = db.getItem(GetItemRequest.builder()
|
||||
.tableName(dynamoDbExtension.getTableName())
|
||||
.tableName(Tables.ACCOUNTS.tableName())
|
||||
.key(Map.of(Accounts.KEY_ACCOUNT_UUID, AttributeValues.fromUUID(uuid)))
|
||||
.consistentRead(true)
|
||||
.build());
|
||||
|
|
|
@ -19,75 +19,27 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GlobalSecondaryIndex;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.Projection;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Indexes;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
|
||||
class DeletedAccountsManagerTest {
|
||||
|
||||
private static final String NEEDS_RECONCILIATION_INDEX_NAME = "needs_reconciliation_test";
|
||||
|
||||
@RegisterExtension
|
||||
static final DynamoDbExtension DELETED_ACCOUNTS_DYNAMODB_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName("deleted_accounts_test")
|
||||
.hashKey(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S).build())
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.ATTR_NEEDS_CDS_RECONCILIATION)
|
||||
.attributeType(ScalarAttributeType.N)
|
||||
.build())
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.ATTR_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.globalSecondaryIndex(GlobalSecondaryIndex.builder()
|
||||
.indexName(NEEDS_RECONCILIATION_INDEX_NAME)
|
||||
.keySchema(
|
||||
KeySchemaElement.builder().attributeName(DeletedAccounts.KEY_ACCOUNT_E164).keyType(KeyType.HASH).build(),
|
||||
KeySchemaElement.builder().attributeName(DeletedAccounts.ATTR_NEEDS_CDS_RECONCILIATION)
|
||||
.keyType(KeyType.RANGE).build())
|
||||
.projection(Projection.builder().projectionType(ProjectionType.INCLUDE)
|
||||
.nonKeyAttributes(DeletedAccounts.ATTR_ACCOUNT_UUID).build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build())
|
||||
.build())
|
||||
.globalSecondaryIndex(GlobalSecondaryIndex.builder()
|
||||
.indexName(DeletedAccounts.UUID_TO_E164_INDEX_NAME)
|
||||
.keySchema(
|
||||
KeySchemaElement.builder().attributeName(DeletedAccounts.ATTR_ACCOUNT_UUID).keyType(KeyType.HASH).build()
|
||||
)
|
||||
.projection(Projection.builder().projectionType(ProjectionType.KEYS_ONLY).build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension DELETED_ACCOUNTS_LOCK_DYNAMODB_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName("deleted_accounts_lock_test")
|
||||
.hashKey(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S).build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION =
|
||||
new DynamoDbExtension(Tables.DELETED_ACCOUNTS, Tables.DELETED_ACCOUNTS_LOCK);
|
||||
|
||||
private DeletedAccounts deletedAccounts;
|
||||
private DeletedAccountsManager deletedAccountsManager;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
deletedAccounts = new DeletedAccounts(DELETED_ACCOUNTS_DYNAMODB_EXTENSION.getDynamoDbClient(),
|
||||
DELETED_ACCOUNTS_DYNAMODB_EXTENSION.getTableName(),
|
||||
NEEDS_RECONCILIATION_INDEX_NAME);
|
||||
deletedAccounts = new DeletedAccounts(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
Tables.DELETED_ACCOUNTS.tableName(),
|
||||
Indexes.DELETED_ACCOUNTS_NEEDS_RECONCILIATION.indexName());
|
||||
|
||||
deletedAccountsManager = new DeletedAccountsManager(deletedAccounts,
|
||||
DELETED_ACCOUNTS_LOCK_DYNAMODB_EXTENSION.getLegacyDynamoClient(),
|
||||
DELETED_ACCOUNTS_LOCK_DYNAMODB_EXTENSION.getTableName());
|
||||
DYNAMO_DB_EXTENSION.getLegacyDynamoClient(),
|
||||
Tables.DELETED_ACCOUNTS_LOCK.tableName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -16,62 +16,22 @@ import java.util.UUID;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Indexes;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GlobalSecondaryIndex;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.Projection;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
class DeletedAccountsTest {
|
||||
|
||||
private static final String NEEDS_RECONCILIATION_INDEX_NAME = "needs_reconciliation_test";
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName("deleted_accounts_test")
|
||||
.hashKey(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S).build())
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.ATTR_NEEDS_CDS_RECONCILIATION)
|
||||
.attributeType(ScalarAttributeType.N)
|
||||
.build())
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.ATTR_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.globalSecondaryIndex(GlobalSecondaryIndex.builder()
|
||||
.indexName(NEEDS_RECONCILIATION_INDEX_NAME)
|
||||
.keySchema(
|
||||
KeySchemaElement.builder().attributeName(DeletedAccounts.KEY_ACCOUNT_E164).keyType(KeyType.HASH).build(),
|
||||
KeySchemaElement.builder().attributeName(DeletedAccounts.ATTR_NEEDS_CDS_RECONCILIATION)
|
||||
.keyType(KeyType.RANGE).build())
|
||||
.projection(Projection.builder().projectionType(ProjectionType.INCLUDE)
|
||||
.nonKeyAttributes(DeletedAccounts.ATTR_ACCOUNT_UUID).build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build())
|
||||
.build())
|
||||
.globalSecondaryIndex(GlobalSecondaryIndex.builder()
|
||||
.indexName(DeletedAccounts.UUID_TO_E164_INDEX_NAME)
|
||||
.keySchema(
|
||||
KeySchemaElement.builder().attributeName(DeletedAccounts.ATTR_ACCOUNT_UUID).keyType(KeyType.HASH).build()
|
||||
)
|
||||
.projection(Projection.builder().projectionType(ProjectionType.KEYS_ONLY).build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build())
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.DELETED_ACCOUNTS);
|
||||
|
||||
private DeletedAccounts deletedAccounts;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
deletedAccounts = new DeletedAccounts(dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getTableName(),
|
||||
NEEDS_RECONCILIATION_INDEX_NAME);
|
||||
deletedAccounts = new DeletedAccounts(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
Tables.DELETED_ACCOUNTS.tableName(),
|
||||
Indexes.DELETED_ACCOUNTS_NEEDS_RECONCILIATION.indexName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
/*
|
||||
* Copyright 2021-2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import com.almworks.sqlite4java.SQLite;
|
||||
|
@ -31,7 +36,23 @@ import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
|
|||
|
||||
public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback {
|
||||
|
||||
static final String DEFAULT_TABLE_NAME = "test_table";
|
||||
public interface TableSchema {
|
||||
public String tableName();
|
||||
public String hashKeyName();
|
||||
public String rangeKeyName();
|
||||
public List<AttributeDefinition> attributeDefinitions();
|
||||
public List<GlobalSecondaryIndex> globalSecondaryIndexes();
|
||||
public List<LocalSecondaryIndex> localSecondaryIndexes();
|
||||
}
|
||||
|
||||
record RawSchema(
|
||||
String tableName,
|
||||
String hashKeyName,
|
||||
String rangeKeyName,
|
||||
List<AttributeDefinition> attributeDefinitions,
|
||||
List<GlobalSecondaryIndex> globalSecondaryIndexes,
|
||||
List<LocalSecondaryIndex> localSecondaryIndexes
|
||||
) implements TableSchema { }
|
||||
|
||||
static final ProvisionedThroughput DEFAULT_PROVISIONED_THROUGHPUT = ProvisionedThroughput.builder()
|
||||
.readCapacityUnits(20L)
|
||||
|
@ -42,42 +63,14 @@ public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback
|
|||
|
||||
private DynamoDBProxyServer server;
|
||||
private int port;
|
||||
|
||||
private final String tableName;
|
||||
private final String hashKeyName;
|
||||
private final String rangeKeyName;
|
||||
|
||||
private final List<AttributeDefinition> attributeDefinitions;
|
||||
private final List<GlobalSecondaryIndex> globalSecondaryIndexes;
|
||||
private final List<LocalSecondaryIndex> localSecondaryIndexes;
|
||||
|
||||
private final long readCapacityUnits;
|
||||
private final long writeCapacityUnits;
|
||||
|
||||
|
||||
private final List<TableSchema> schemas;
|
||||
private DynamoDbClient dynamoDB2;
|
||||
private DynamoDbAsyncClient dynamoAsyncDB2;
|
||||
private AmazonDynamoDB legacyDynamoClient;
|
||||
|
||||
private DynamoDbExtension(String tableName, String hashKey, String rangeKey,
|
||||
List<AttributeDefinition> attributeDefinitions, List<GlobalSecondaryIndex> globalSecondaryIndexes,
|
||||
final List<LocalSecondaryIndex> localSecondaryIndexes,
|
||||
long readCapacityUnits,
|
||||
long writeCapacityUnits) {
|
||||
|
||||
this.tableName = tableName;
|
||||
this.hashKeyName = hashKey;
|
||||
this.rangeKeyName = rangeKey;
|
||||
this.localSecondaryIndexes = localSecondaryIndexes;
|
||||
|
||||
this.readCapacityUnits = readCapacityUnits;
|
||||
this.writeCapacityUnits = writeCapacityUnits;
|
||||
|
||||
this.attributeDefinitions = attributeDefinitions;
|
||||
this.globalSecondaryIndexes = globalSecondaryIndexes;
|
||||
}
|
||||
|
||||
public static DynamoDbExtensionBuilder builder() {
|
||||
return new DynamoDbExtensionBuilder();
|
||||
public DynamoDbExtension(TableSchema... schemas) {
|
||||
this.schemas = List.of(schemas);
|
||||
}
|
||||
|
||||
private static void loadLibrary() {
|
||||
|
@ -114,32 +107,33 @@ public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback
|
|||
|
||||
initializeClient();
|
||||
|
||||
createTable();
|
||||
createTables();
|
||||
}
|
||||
|
||||
private void createTable() {
|
||||
private void createTables() {
|
||||
schemas.stream().forEach(this::createTable);
|
||||
}
|
||||
|
||||
private void createTable(TableSchema schema) {
|
||||
KeySchemaElement[] keySchemaElements;
|
||||
if (rangeKeyName == null) {
|
||||
if (schema.rangeKeyName() == null) {
|
||||
keySchemaElements = new KeySchemaElement[] {
|
||||
KeySchemaElement.builder().attributeName(hashKeyName).keyType(KeyType.HASH).build(),
|
||||
KeySchemaElement.builder().attributeName(schema.hashKeyName()).keyType(KeyType.HASH).build(),
|
||||
};
|
||||
} else {
|
||||
keySchemaElements = new KeySchemaElement[] {
|
||||
KeySchemaElement.builder().attributeName(hashKeyName).keyType(KeyType.HASH).build(),
|
||||
KeySchemaElement.builder().attributeName(rangeKeyName).keyType(KeyType.RANGE).build(),
|
||||
KeySchemaElement.builder().attributeName(schema.hashKeyName()).keyType(KeyType.HASH).build(),
|
||||
KeySchemaElement.builder().attributeName(schema.rangeKeyName()).keyType(KeyType.RANGE).build(),
|
||||
};
|
||||
}
|
||||
|
||||
final CreateTableRequest createTableRequest = CreateTableRequest.builder()
|
||||
.tableName(tableName)
|
||||
.tableName(schema.tableName())
|
||||
.keySchema(keySchemaElements)
|
||||
.attributeDefinitions(attributeDefinitions.isEmpty() ? null : attributeDefinitions)
|
||||
.globalSecondaryIndexes(globalSecondaryIndexes.isEmpty() ? null : globalSecondaryIndexes)
|
||||
.localSecondaryIndexes(localSecondaryIndexes.isEmpty() ? null : localSecondaryIndexes)
|
||||
.provisionedThroughput(ProvisionedThroughput.builder()
|
||||
.readCapacityUnits(readCapacityUnits)
|
||||
.writeCapacityUnits(writeCapacityUnits)
|
||||
.build())
|
||||
.attributeDefinitions(schema.attributeDefinitions().isEmpty() ? null : schema.attributeDefinitions())
|
||||
.globalSecondaryIndexes(schema.globalSecondaryIndexes().isEmpty() ? null : schema.globalSecondaryIndexes())
|
||||
.localSecondaryIndexes(schema.localSecondaryIndexes().isEmpty() ? null : schema.localSecondaryIndexes())
|
||||
.provisionedThroughput(DEFAULT_PROVISIONED_THROUGHPUT)
|
||||
.build();
|
||||
|
||||
getDynamoDbClient().createTable(createTableRequest);
|
||||
|
@ -178,60 +172,6 @@ public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback
|
|||
.build();
|
||||
}
|
||||
|
||||
public static class DynamoDbExtensionBuilder {
|
||||
|
||||
private String tableName = DEFAULT_TABLE_NAME;
|
||||
|
||||
private String hashKey;
|
||||
private String rangeKey;
|
||||
|
||||
private final List<AttributeDefinition> attributeDefinitions = new ArrayList<>();
|
||||
private final List<GlobalSecondaryIndex> globalSecondaryIndexes = new ArrayList<>();
|
||||
private final List<LocalSecondaryIndex> localSecondaryIndexes = new ArrayList<>();
|
||||
|
||||
private final long readCapacityUnits = DEFAULT_PROVISIONED_THROUGHPUT.readCapacityUnits();
|
||||
private final long writeCapacityUnits = DEFAULT_PROVISIONED_THROUGHPUT.writeCapacityUnits();
|
||||
|
||||
private DynamoDbExtensionBuilder() {
|
||||
|
||||
}
|
||||
|
||||
public DynamoDbExtensionBuilder tableName(String databaseName) {
|
||||
this.tableName = databaseName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamoDbExtensionBuilder hashKey(String hashKey) {
|
||||
this.hashKey = hashKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamoDbExtensionBuilder rangeKey(String rangeKey) {
|
||||
this.rangeKey = rangeKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamoDbExtensionBuilder attributeDefinition(AttributeDefinition attributeDefinition) {
|
||||
attributeDefinitions.add(attributeDefinition);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamoDbExtensionBuilder globalSecondaryIndex(GlobalSecondaryIndex index) {
|
||||
globalSecondaryIndexes.add(index);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamoDbExtensionBuilder localSecondaryIndex(LocalSecondaryIndex index) {
|
||||
localSecondaryIndexes.add(index);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DynamoDbExtension build() {
|
||||
return new DynamoDbExtension(tableName, hashKey, rangeKey,
|
||||
attributeDefinitions, globalSecondaryIndexes, localSecondaryIndexes, readCapacityUnits, writeCapacityUnits);
|
||||
}
|
||||
}
|
||||
|
||||
public DynamoDbClient getDynamoDbClient() {
|
||||
return dynamoDB2;
|
||||
}
|
||||
|
@ -243,8 +183,4 @@ public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback
|
|||
public AmazonDynamoDB getLegacyDynamoClient() {
|
||||
return legacyDynamoClient;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import java.util.List;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GlobalSecondaryIndex;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.LocalSecondaryIndex;
|
||||
import software.amazon.awssdk.services.dynamodb.model.Projection;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
public final class DynamoDbExtensionSchema {
|
||||
|
||||
public enum Indexes {
|
||||
|
||||
DELETED_ACCOUNTS_NEEDS_RECONCILIATION("needs_reconciliation_test");
|
||||
|
||||
private final String name;
|
||||
|
||||
public String indexName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
Indexes(final String name) { this.name = name; }
|
||||
|
||||
}
|
||||
|
||||
public enum Tables implements DynamoDbExtension.TableSchema {
|
||||
|
||||
ACCOUNTS("accounts_test",
|
||||
Accounts.KEY_ACCOUNT_UUID,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
DELETED_ACCOUNTS("deleted_accounts_test",
|
||||
DeletedAccounts.KEY_ACCOUNT_E164,
|
||||
null,
|
||||
List.of(
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S).build(),
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.ATTR_NEEDS_CDS_RECONCILIATION)
|
||||
.attributeType(ScalarAttributeType.N)
|
||||
.build(),
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.ATTR_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(
|
||||
GlobalSecondaryIndex.builder()
|
||||
.indexName(Indexes.DELETED_ACCOUNTS_NEEDS_RECONCILIATION.indexName())
|
||||
.keySchema(KeySchemaElement.builder().attributeName(DeletedAccounts.KEY_ACCOUNT_E164).keyType(KeyType.HASH).build(),
|
||||
KeySchemaElement.builder().attributeName(DeletedAccounts.ATTR_NEEDS_CDS_RECONCILIATION).keyType(KeyType.RANGE).build())
|
||||
.projection(Projection.builder().projectionType(ProjectionType.INCLUDE).nonKeyAttributes(DeletedAccounts.ATTR_ACCOUNT_UUID).build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build())
|
||||
.build(),
|
||||
GlobalSecondaryIndex.builder()
|
||||
.indexName(DeletedAccounts.UUID_TO_E164_INDEX_NAME)
|
||||
.keySchema(
|
||||
KeySchemaElement.builder().attributeName(DeletedAccounts.ATTR_ACCOUNT_UUID).keyType(KeyType.HASH).build()
|
||||
)
|
||||
.projection(Projection.builder().projectionType(ProjectionType.KEYS_ONLY).build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build())
|
||||
.build()),
|
||||
List.of()
|
||||
),
|
||||
|
||||
DELETED_ACCOUNTS_LOCK("deleted_accounts_lock_test",
|
||||
DeletedAccounts.KEY_ACCOUNT_E164,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(DeletedAccounts.KEY_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S).build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
NUMBERS("numbers_test",
|
||||
Accounts.ATTR_ACCOUNT_E164,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_ACCOUNT_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
KEYS("keys_test",
|
||||
Keys.KEY_ACCOUNT_UUID,
|
||||
Keys.KEY_DEVICE_ID_KEY_ID,
|
||||
List.of(
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(Keys.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build(),
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(Keys.KEY_DEVICE_ID_KEY_ID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
PNI("pni_test",
|
||||
PhoneNumberIdentifiers.KEY_E164,
|
||||
null,
|
||||
List.of(
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(PhoneNumberIdentifiers.KEY_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build(),
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(PhoneNumberIdentifiers.ATTR_PHONE_NUMBER_IDENTIFIER)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(GlobalSecondaryIndex.builder()
|
||||
.indexName(PhoneNumberIdentifiers.INDEX_NAME)
|
||||
.projection(Projection.builder()
|
||||
.projectionType(ProjectionType.KEYS_ONLY)
|
||||
.build())
|
||||
.keySchema(KeySchemaElement.builder().keyType(KeyType.HASH)
|
||||
.attributeName(PhoneNumberIdentifiers.ATTR_PHONE_NUMBER_IDENTIFIER)
|
||||
.build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build())
|
||||
.build()),
|
||||
List.of()),
|
||||
|
||||
PNI_ASSIGNMENTS("pni_assignment_test",
|
||||
Accounts.ATTR_PNI_UUID,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_PNI_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
ISSUED_RECEIPTS("issued_receipts_test",
|
||||
IssuedReceiptsManager.KEY_PROCESSOR_ITEM_ID,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(IssuedReceiptsManager.KEY_PROCESSOR_ITEM_ID)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
MESSAGES("messages_test",
|
||||
MessagesDynamoDb.KEY_PARTITION,
|
||||
MessagesDynamoDb.KEY_SORT,
|
||||
List.of(
|
||||
AttributeDefinition.builder().attributeName(MessagesDynamoDb.KEY_PARTITION).attributeType(ScalarAttributeType.B).build(),
|
||||
AttributeDefinition.builder().attributeName(MessagesDynamoDb.KEY_SORT).attributeType(ScalarAttributeType.B).build(),
|
||||
AttributeDefinition.builder().attributeName(MessagesDynamoDb.LOCAL_INDEX_MESSAGE_UUID_KEY_SORT)
|
||||
.attributeType(ScalarAttributeType.B).build()),
|
||||
List.of(),
|
||||
List.of(LocalSecondaryIndex.builder()
|
||||
.indexName(MessagesDynamoDb.LOCAL_INDEX_MESSAGE_UUID_NAME)
|
||||
.keySchema(
|
||||
KeySchemaElement.builder().attributeName(MessagesDynamoDb.KEY_PARTITION).keyType(KeyType.HASH).build(),
|
||||
KeySchemaElement.builder()
|
||||
.attributeName(MessagesDynamoDb.LOCAL_INDEX_MESSAGE_UUID_KEY_SORT)
|
||||
.keyType(KeyType.RANGE)
|
||||
.build())
|
||||
.projection(Projection.builder().projectionType(ProjectionType.KEYS_ONLY).build())
|
||||
.build())),
|
||||
|
||||
PROFILES("profiles_test",
|
||||
Profiles.KEY_ACCOUNT_UUID,
|
||||
Profiles.ATTR_VERSION,
|
||||
List.of(
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(Profiles.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build(),
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(Profiles.ATTR_VERSION)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
PUSH_CHALLENGES("push_challenge_test",
|
||||
PushChallengeDynamoDb.KEY_ACCOUNT_UUID,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(PushChallengeDynamoDb.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
REDEEMED_RECEIPTS("redeemed_receipts_test",
|
||||
RedeemedReceiptsManager.KEY_SERIAL,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(RedeemedReceiptsManager.KEY_SERIAL)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
REGISTRATION_RECOVERY_PASSWORDS("registration_recovery_passwords_test",
|
||||
RegistrationRecoveryPasswords.KEY_E164,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(RegistrationRecoveryPasswords.KEY_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
REMOTE_CONFIGS("remote_configs_test",
|
||||
RemoteConfigs.KEY_NAME,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(RemoteConfigs.KEY_NAME)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
REPORT_MESSAGES("report_messages_test",
|
||||
ReportMessageDynamoDb.KEY_HASH,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(ReportMessageDynamoDb.KEY_HASH)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
SUBSCRIPTIONS("subscriptions_test",
|
||||
SubscriptionManager.KEY_USER,
|
||||
null,
|
||||
List.of(
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(SubscriptionManager.KEY_USER)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build(),
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(SubscriptionManager.KEY_PROCESSOR_ID_CUSTOMER_ID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(GlobalSecondaryIndex.builder()
|
||||
.indexName(SubscriptionManager.INDEX_NAME)
|
||||
.keySchema(KeySchemaElement.builder()
|
||||
.attributeName(SubscriptionManager.KEY_PROCESSOR_ID_CUSTOMER_ID)
|
||||
.keyType(KeyType.HASH)
|
||||
.build())
|
||||
.projection(Projection.builder()
|
||||
.projectionType(ProjectionType.KEYS_ONLY)
|
||||
.build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder()
|
||||
.readCapacityUnits(20L)
|
||||
.writeCapacityUnits(20L)
|
||||
.build())
|
||||
.build()),
|
||||
List.of()),
|
||||
|
||||
USERNAMES("usernames_test",
|
||||
Accounts.ATTR_USERNAME_HASH,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(Accounts.ATTR_USERNAME_HASH)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
VERIFICATION_CODES("verification_codes_test",
|
||||
VerificationCodeStore.KEY_E164,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(VerificationCodeStore.KEY_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build()),
|
||||
List.of(), List.of()),
|
||||
|
||||
VERIFICATION_SESSIONS("verification_sessions_test",
|
||||
VerificationSessions.KEY_KEY,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(VerificationSessions.KEY_KEY)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build()),
|
||||
List.of(), List.of());
|
||||
|
||||
private final String tableName;
|
||||
private final String hashKeyName;
|
||||
private final String rangeKeyName;
|
||||
private final List<AttributeDefinition> attributeDefinitions;
|
||||
private final List<GlobalSecondaryIndex> globalSecondaryIndexes;
|
||||
private final List<LocalSecondaryIndex> localSecondaryIndexes;
|
||||
|
||||
Tables(
|
||||
final String tableName,
|
||||
final String hashKeyName,
|
||||
final String rangeKeyName,
|
||||
final List<AttributeDefinition> attributeDefinitions,
|
||||
final List<GlobalSecondaryIndex> globalSecondaryIndexes,
|
||||
final List<LocalSecondaryIndex> localSecondaryIndexes
|
||||
) {
|
||||
this.tableName = tableName;
|
||||
this.hashKeyName = hashKeyName;
|
||||
this.rangeKeyName = rangeKeyName;
|
||||
this.attributeDefinitions = attributeDefinitions;
|
||||
this.globalSecondaryIndexes = globalSecondaryIndexes;
|
||||
this.localSecondaryIndexes = localSecondaryIndexes;
|
||||
}
|
||||
|
||||
public String tableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public String hashKeyName() {
|
||||
return hashKeyName;
|
||||
}
|
||||
|
||||
public String rangeKeyName() {
|
||||
return rangeKeyName;
|
||||
}
|
||||
|
||||
public List<AttributeDefinition> attributeDefinitions() {
|
||||
return attributeDefinitions;
|
||||
}
|
||||
|
||||
public List<GlobalSecondaryIndex> globalSecondaryIndexes() {
|
||||
return globalSecondaryIndexes;
|
||||
}
|
||||
|
||||
public List<LocalSecondaryIndex> localSecondaryIndexes() {
|
||||
return localSecondaryIndexes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -20,24 +20,15 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialRequest;
|
||||
import org.whispersystems.textsecuregcm.subscriptions.SubscriptionProcessor;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
|
||||
class IssuedReceiptsManagerTest {
|
||||
|
||||
private static final long NOW_EPOCH_SECONDS = 1_500_000_000L;
|
||||
private static final String ISSUED_RECEIPTS_TABLE_NAME = "issued_receipts";
|
||||
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName(ISSUED_RECEIPTS_TABLE_NAME)
|
||||
.hashKey(IssuedReceiptsManager.KEY_PROCESSOR_ITEM_ID)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(IssuedReceiptsManager.KEY_PROCESSOR_ITEM_ID)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.ISSUED_RECEIPTS);
|
||||
|
||||
ReceiptCredentialRequest receiptCredentialRequest;
|
||||
IssuedReceiptsManager issuedReceiptsManager;
|
||||
|
@ -48,9 +39,9 @@ class IssuedReceiptsManagerTest {
|
|||
byte[] generator = new byte[16];
|
||||
SECURE_RANDOM.nextBytes(generator);
|
||||
issuedReceiptsManager = new IssuedReceiptsManager(
|
||||
ISSUED_RECEIPTS_TABLE_NAME,
|
||||
Tables.ISSUED_RECEIPTS.tableName(),
|
||||
Duration.ofDays(90),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
generator);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,38 +15,22 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.entities.PreKey;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
class KeysTest {
|
||||
|
||||
private static final String TABLE_NAME = "Signal_Keys_Test";
|
||||
|
||||
private Keys keys;
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName(TABLE_NAME)
|
||||
.hashKey(Keys.KEY_ACCOUNT_UUID)
|
||||
.rangeKey(Keys.KEY_DEVICE_ID_KEY_ID)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(Keys.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.attributeDefinition(
|
||||
AttributeDefinition.builder()
|
||||
.attributeName(Keys.KEY_DEVICE_ID_KEY_ID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.KEYS);
|
||||
|
||||
private static final UUID ACCOUNT_UUID = UUID.randomUUID();
|
||||
private static final long DEVICE_ID = 1L;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
keys = new Keys(dynamoDbExtension.getDynamoDbClient(), TABLE_NAME);
|
||||
keys = new Keys(DYNAMO_DB_EXTENSION.getDynamoDbClient(), Tables.KEYS.tableName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -35,7 +35,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
|||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.redis.RedisClusterExtension;
|
||||
import org.whispersystems.textsecuregcm.tests.util.MessagesDynamoDbExtension;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
|
||||
|
@ -44,7 +44,7 @@ import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
|
|||
class MessagePersisterIntegrationTest {
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = MessagesDynamoDbExtension.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.MESSAGES);
|
||||
|
||||
@RegisterExtension
|
||||
static final RedisClusterExtension REDIS_CLUSTER_EXTENSION = RedisClusterExtension.builder().build();
|
||||
|
@ -74,8 +74,8 @@ class MessagePersisterIntegrationTest {
|
|||
|
||||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messageDeletionExecutorService = Executors.newSingleThreadExecutor();
|
||||
final MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(), MessagesDynamoDbExtension.TABLE_NAME, Duration.ofDays(14),
|
||||
final MessagesDynamoDb messagesDynamoDb = new MessagesDynamoDb(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(), Tables.MESSAGES.tableName(), Duration.ofDays(14),
|
||||
messageDeletionExecutorService);
|
||||
final AccountsManager accountsManager = mock(AccountsManager.class);
|
||||
|
||||
|
@ -164,10 +164,10 @@ class MessagePersisterIntegrationTest {
|
|||
|
||||
messagePersister.stop();
|
||||
|
||||
DynamoDbClient dynamoDB = dynamoDbExtension.getDynamoDbClient();
|
||||
DynamoDbClient dynamoDB = DYNAMO_DB_EXTENSION.getDynamoDbClient();
|
||||
|
||||
final List<MessageProtos.Envelope> persistedMessages =
|
||||
dynamoDB.scan(ScanRequest.builder().tableName(MessagesDynamoDbExtension.TABLE_NAME).build()).items().stream()
|
||||
dynamoDB.scan(ScanRequest.builder().tableName(Tables.MESSAGES.tableName()).build()).items().stream()
|
||||
.map(item -> {
|
||||
try {
|
||||
return MessagesDynamoDb.convertItemToEnvelope(item);
|
||||
|
|
|
@ -26,8 +26,8 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.whispersystems.textsecuregcm.entities.MessageProtos;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.tests.util.MessageHelper;
|
||||
import org.whispersystems.textsecuregcm.tests.util.MessagesDynamoDbExtension;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
|
@ -77,13 +77,13 @@ class MessagesDynamoDbTest {
|
|||
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = MessagesDynamoDbExtension.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.MESSAGES);
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
messageDeletionExecutorService = Executors.newSingleThreadExecutor();
|
||||
messagesDynamoDb = new MessagesDynamoDb(dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(), MessagesDynamoDbExtension.TABLE_NAME, Duration.ofDays(14),
|
||||
messagesDynamoDb = new MessagesDynamoDb(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(), Tables.MESSAGES.tableName(), Duration.ofDays(14),
|
||||
messageDeletionExecutorService);
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ class MessagesDynamoDbTest {
|
|||
.thenRequest(halfOfMessageLoadLimit)
|
||||
.expectNextCount(halfOfMessageLoadLimit)
|
||||
// the first 100 should be fetched and buffered, but further requests should fail
|
||||
.then(() -> dynamoDbExtension.stopServer())
|
||||
.then(() -> DYNAMO_DB_EXTENSION.stopServer())
|
||||
.thenRequest(halfOfMessageLoadLimit)
|
||||
.expectNextCount(halfOfMessageLoadLimit)
|
||||
// we’ve consumed all the buffered messages, so a single request will fail
|
||||
|
|
|
@ -14,48 +14,19 @@ import java.util.UUID;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GlobalSecondaryIndex;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.Projection;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
|
||||
class PhoneNumberIdentifiersTest {
|
||||
|
||||
private static final String PNI_TABLE_NAME = "pni_test";
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension DYNAMO_DB_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(PNI_TABLE_NAME)
|
||||
.hashKey(PhoneNumberIdentifiers.KEY_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(PhoneNumberIdentifiers.KEY_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(PhoneNumberIdentifiers.ATTR_PHONE_NUMBER_IDENTIFIER)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.globalSecondaryIndex(GlobalSecondaryIndex.builder()
|
||||
.indexName(PhoneNumberIdentifiers.INDEX_NAME)
|
||||
.projection(Projection.builder()
|
||||
.projectionType(ProjectionType.KEYS_ONLY)
|
||||
.build())
|
||||
.keySchema(KeySchemaElement.builder().keyType(KeyType.HASH)
|
||||
.attributeName(PhoneNumberIdentifiers.ATTR_PHONE_NUMBER_IDENTIFIER)
|
||||
.build())
|
||||
.provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(10L).writeCapacityUnits(10L).build())
|
||||
.build())
|
||||
.build();
|
||||
static DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.PNI);
|
||||
|
||||
private PhoneNumberIdentifiers phoneNumberIdentifiers;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
phoneNumberIdentifiers = new PhoneNumberIdentifiers(DYNAMO_DB_EXTENSION.getDynamoDbClient(), PNI_TABLE_NAME);
|
||||
phoneNumberIdentifiers = new PhoneNumberIdentifiers(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
Tables.PNI.tableName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -12,9 +12,8 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.whispersystems.textsecuregcm.util.AttributeValues;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
@ -27,30 +26,16 @@ import java.util.stream.Stream;
|
|||
|
||||
public abstract class ProfilesTest {
|
||||
|
||||
private static final String PROFILES_TABLE_NAME = "profiles_test";
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName(PROFILES_TABLE_NAME)
|
||||
.hashKey(Profiles.KEY_ACCOUNT_UUID)
|
||||
.rangeKey(Profiles.ATTR_VERSION)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(Profiles.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(Profiles.ATTR_VERSION)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.PROFILES);
|
||||
|
||||
private Profiles profiles;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
profiles = new Profiles(dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(),
|
||||
PROFILES_TABLE_NAME);
|
||||
profiles = new Profiles(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
Tables.PROFILES.tableName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -18,8 +18,7 @@ import java.util.UUID;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
|
||||
class PushChallengeDynamoDbTest {
|
||||
|
||||
|
@ -28,22 +27,16 @@ class PushChallengeDynamoDbTest {
|
|||
private static final long CURRENT_TIME_MILLIS = 1_000_000_000;
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
private static final String TABLE_NAME = "push_challenge_test";
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName(TABLE_NAME)
|
||||
.hashKey(PushChallengeDynamoDb.KEY_ACCOUNT_UUID)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(PushChallengeDynamoDb.KEY_ACCOUNT_UUID)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.PUSH_CHALLENGES);
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.pushChallengeDynamoDb = new PushChallengeDynamoDb(dynamoDbExtension.getDynamoDbClient(), TABLE_NAME, Clock.fixed(
|
||||
Instant.ofEpochMilli(CURRENT_TIME_MILLIS), ZoneId.systemDefault()));
|
||||
this.pushChallengeDynamoDb = new PushChallengeDynamoDb(
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
Tables.PUSH_CHALLENGES.tableName(),
|
||||
Clock.fixed(Instant.ofEpochMilli(CURRENT_TIME_MILLIS), ZoneId.systemDefault()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -21,17 +21,14 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.auth.SaltedTokenHash;
|
||||
import org.whispersystems.textsecuregcm.util.AttributeValues;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.util.MockUtils;
|
||||
import org.whispersystems.textsecuregcm.util.MutableClock;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
public class RegistrationRecoveryTest {
|
||||
|
||||
private static final String TABLE_NAME = "registration_recovery_passwords";
|
||||
|
||||
private static final MutableClock CLOCK = MockUtils.mutableClock(0);
|
||||
|
||||
private static final Duration EXPIRATION = Duration.ofSeconds(1000);
|
||||
|
@ -43,14 +40,8 @@ public class RegistrationRecoveryTest {
|
|||
private static final SaltedTokenHash ANOTHER_HASH = SaltedTokenHash.generateFor("pass2");
|
||||
|
||||
@RegisterExtension
|
||||
private static final DynamoDbExtension DB_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(TABLE_NAME)
|
||||
.hashKey(RegistrationRecoveryPasswords.KEY_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(RegistrationRecoveryPasswords.KEY_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.build();
|
||||
private static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(
|
||||
Tables.REGISTRATION_RECOVERY_PASSWORDS);
|
||||
|
||||
private RegistrationRecoveryPasswords store;
|
||||
|
||||
|
@ -60,10 +51,10 @@ public class RegistrationRecoveryTest {
|
|||
public void before() throws Exception {
|
||||
CLOCK.setTimeMillis(Clock.systemUTC().millis());
|
||||
store = new RegistrationRecoveryPasswords(
|
||||
DB_EXTENSION.getTableName(),
|
||||
Tables.REGISTRATION_RECOVERY_PASSWORDS.tableName(),
|
||||
EXPIRATION,
|
||||
DB_EXTENSION.getDynamoDbClient(),
|
||||
DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
CLOCK
|
||||
);
|
||||
manager = new RegistrationRecoveryPasswordsManager(store);
|
||||
|
@ -147,8 +138,8 @@ public class RegistrationRecoveryTest {
|
|||
}
|
||||
|
||||
private static long fetchTimestamp(final String number) throws ExecutionException, InterruptedException {
|
||||
return DB_EXTENSION.getDynamoDbAsyncClient().getItem(GetItemRequest.builder()
|
||||
.tableName(DB_EXTENSION.getTableName())
|
||||
return DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient().getItem(GetItemRequest.builder()
|
||||
.tableName(Tables.REGISTRATION_RECOVERY_PASSWORDS.tableName())
|
||||
.key(Map.of(RegistrationRecoveryPasswords.KEY_E164, AttributeValues.fromString(number)))
|
||||
.build())
|
||||
.thenApply(getItemResponse -> {
|
||||
|
|
|
@ -9,8 +9,7 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -18,23 +17,14 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
|
||||
class RemoteConfigsTest {
|
||||
|
||||
private static final String REMOTE_CONFIGS_TABLE_NAME = "remote_configs_test";
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName(REMOTE_CONFIGS_TABLE_NAME)
|
||||
.hashKey(RemoteConfigs.KEY_NAME)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(RemoteConfigs.KEY_NAME)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.REMOTE_CONFIGS);
|
||||
|
||||
private RemoteConfigs remoteConfigs;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
remoteConfigs = new RemoteConfigs(dynamoDbExtension.getDynamoDbClient(), REMOTE_CONFIGS_TABLE_NAME);
|
||||
remoteConfigs = new RemoteConfigs(DYNAMO_DB_EXTENSION.getDynamoDbClient(), Tables.REMOTE_CONFIGS.tableName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -14,30 +14,23 @@ import java.util.UUID;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.util.UUIDUtil;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
class ReportMessageDynamoDbTest {
|
||||
|
||||
private ReportMessageDynamoDb reportMessageDynamoDb;
|
||||
|
||||
private static final String TABLE_NAME = "report_message_test";
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName(TABLE_NAME)
|
||||
.hashKey(ReportMessageDynamoDb.KEY_HASH)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(ReportMessageDynamoDb.KEY_HASH)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.build();
|
||||
static DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.REPORT_MESSAGES);
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.reportMessageDynamoDb = new ReportMessageDynamoDb(dynamoDbExtension.getDynamoDbClient(), TABLE_NAME, Duration.ofDays(1));
|
||||
this.reportMessageDynamoDb = new ReportMessageDynamoDb(
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
Tables.REPORT_MESSAGES.tableName(),
|
||||
Duration.ofDays(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -14,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -39,14 +40,17 @@ class SerializedExpireableJsonDynamoStoreTest {
|
|||
}
|
||||
|
||||
@RegisterExtension
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(TABLE_NAME)
|
||||
.hashKey(SerializedExpireableJsonDynamoStore.KEY_KEY)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(SerializedExpireableJsonDynamoStore.KEY_KEY)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(
|
||||
new DynamoDbExtension.RawSchema(
|
||||
TABLE_NAME,
|
||||
SerializedExpireableJsonDynamoStore.KEY_KEY,
|
||||
null,
|
||||
List.of(AttributeDefinition.builder()
|
||||
.attributeName(SerializedExpireableJsonDynamoStore.KEY_KEY)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build()),
|
||||
List.of(),
|
||||
List.of()));
|
||||
|
||||
private SerializedExpireableJsonDynamoStore<T> store;
|
||||
|
||||
|
|
|
@ -28,49 +28,16 @@ import org.whispersystems.textsecuregcm.storage.SubscriptionManager.GetResult;
|
|||
import org.whispersystems.textsecuregcm.storage.SubscriptionManager.Record;
|
||||
import org.whispersystems.textsecuregcm.subscriptions.ProcessorCustomer;
|
||||
import org.whispersystems.textsecuregcm.subscriptions.SubscriptionProcessor;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.GlobalSecondaryIndex;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.Projection;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
|
||||
class SubscriptionManagerTest {
|
||||
|
||||
private static final long NOW_EPOCH_SECONDS = 1_500_000_000L;
|
||||
private static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(3);
|
||||
private static final String SUBSCRIPTIONS_TABLE_NAME = "subscriptions";
|
||||
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder().
|
||||
tableName(SUBSCRIPTIONS_TABLE_NAME).
|
||||
hashKey(SubscriptionManager.KEY_USER).
|
||||
attributeDefinition(AttributeDefinition.builder().
|
||||
attributeName(SubscriptionManager.KEY_USER).
|
||||
attributeType(ScalarAttributeType.B).
|
||||
build()).
|
||||
attributeDefinition(AttributeDefinition.builder().
|
||||
attributeName(SubscriptionManager.KEY_PROCESSOR_ID_CUSTOMER_ID).
|
||||
attributeType(ScalarAttributeType.B).
|
||||
build()).
|
||||
globalSecondaryIndex(GlobalSecondaryIndex.builder().
|
||||
indexName(SubscriptionManager.INDEX_NAME).
|
||||
keySchema(KeySchemaElement.builder().
|
||||
attributeName(SubscriptionManager.KEY_PROCESSOR_ID_CUSTOMER_ID).
|
||||
keyType(KeyType.HASH).
|
||||
build()).
|
||||
projection(Projection.builder().
|
||||
projectionType(ProjectionType.KEYS_ONLY).
|
||||
build()).
|
||||
provisionedThroughput(ProvisionedThroughput.builder().
|
||||
readCapacityUnits(20L).
|
||||
writeCapacityUnits(20L).
|
||||
build()).
|
||||
build()).
|
||||
build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.SUBSCRIPTIONS);
|
||||
|
||||
byte[] user;
|
||||
byte[] password;
|
||||
|
@ -85,7 +52,7 @@ class SubscriptionManagerTest {
|
|||
customer = Base64.getEncoder().encodeToString(getRandomBytes(16));
|
||||
created = Instant.ofEpochSecond(NOW_EPOCH_SECONDS);
|
||||
subscriptionManager = new SubscriptionManager(
|
||||
SUBSCRIPTIONS_TABLE_NAME, dynamoDbExtension.getDynamoDbAsyncClient());
|
||||
Tables.SUBSCRIPTIONS.tableName(), DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -19,15 +19,12 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.auth.StoredVerificationCode;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
|
||||
class VerificationCodeStoreTest {
|
||||
|
||||
private VerificationCodeStore verificationCodeStore;
|
||||
|
||||
private static final String TABLE_NAME = "verification_code_test";
|
||||
|
||||
private static final String PHONE_NUMBER = "+14151112222";
|
||||
|
||||
private static final long VALID_TIMESTAMP = Instant.now().toEpochMilli();
|
||||
|
@ -35,18 +32,12 @@ class VerificationCodeStoreTest {
|
|||
Duration.ofHours(1)).toEpochMilli();
|
||||
|
||||
@RegisterExtension
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(TABLE_NAME)
|
||||
.hashKey(VerificationCodeStore.KEY_E164)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(VerificationCodeStore.KEY_E164)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.VERIFICATION_CODES);
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
verificationCodeStore = new VerificationCodeStore(DYNAMO_DB_EXTENSION.getDynamoDbClient(), TABLE_NAME);
|
||||
verificationCodeStore = new VerificationCodeStore(
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbClient(), Tables.VERIFICATION_CODES.tableName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -21,32 +21,23 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.registration.VerificationSession;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.util.ExceptionUtils;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
class VerificationSessionsTest {
|
||||
|
||||
private static final String TABLE_NAME = "verification_sessions_test";
|
||||
|
||||
private static final Clock clock = Clock.systemUTC();
|
||||
|
||||
@RegisterExtension
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = DynamoDbExtension.builder()
|
||||
.tableName(TABLE_NAME)
|
||||
.hashKey(VerificationSessions.KEY_KEY)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(VerificationSessions.KEY_KEY)
|
||||
.attributeType(ScalarAttributeType.S)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.VERIFICATION_SESSIONS);
|
||||
|
||||
private VerificationSessions verificationSessions;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
verificationSessions = new VerificationSessions(DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(), TABLE_NAME, clock);
|
||||
verificationSessions = new VerificationSessions(
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(), Tables.VERIFICATION_SESSIONS.tableName(), clock);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -21,27 +21,18 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
|||
import org.signal.libsignal.zkgroup.InvalidInputException;
|
||||
import org.signal.libsignal.zkgroup.receipts.ReceiptSerial;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtension;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
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;
|
||||
|
||||
class RedeemedReceiptsManagerTest {
|
||||
|
||||
private static final long NOW_EPOCH_SECONDS = 1_500_000_000L;
|
||||
private static final String REDEEMED_RECEIPTS_TABLE_NAME = "redeemed_receipts";
|
||||
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
|
||||
.tableName(REDEEMED_RECEIPTS_TABLE_NAME)
|
||||
.hashKey(RedeemedReceiptsManager.KEY_SERIAL)
|
||||
.attributeDefinition(AttributeDefinition.builder()
|
||||
.attributeName(RedeemedReceiptsManager.KEY_SERIAL)
|
||||
.attributeType(ScalarAttributeType.B)
|
||||
.build())
|
||||
.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.REDEEMED_RECEIPTS);
|
||||
|
||||
Clock clock = TestClock.pinned(Instant.ofEpochSecond(NOW_EPOCH_SECONDS));
|
||||
ReceiptSerial receiptSerial;
|
||||
|
@ -53,7 +44,10 @@ class RedeemedReceiptsManagerTest {
|
|||
SECURE_RANDOM.nextBytes(receiptSerialBytes);
|
||||
receiptSerial = new ReceiptSerial(receiptSerialBytes);
|
||||
redeemedReceiptsManager = new RedeemedReceiptsManager(
|
||||
clock, REDEEMED_RECEIPTS_TABLE_NAME, dynamoDbExtension.getDynamoDbAsyncClient(), Duration.ofDays(90));
|
||||
clock,
|
||||
Tables.REDEEMED_RECEIPTS.tableName(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(),
|
||||
Duration.ofDays(90));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.tests.util;
|
||||
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtension;
|
||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
|
||||
import software.amazon.awssdk.services.dynamodb.model.KeyType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.LocalSecondaryIndex;
|
||||
import software.amazon.awssdk.services.dynamodb.model.Projection;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
|
||||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
|
||||
|
||||
public class MessagesDynamoDbExtension {
|
||||
|
||||
public static final String TABLE_NAME = "Signal_Messages_UnitTest";
|
||||
|
||||
public static DynamoDbExtension build() {
|
||||
return DynamoDbExtension.builder()
|
||||
.tableName(TABLE_NAME)
|
||||
.hashKey("H")
|
||||
.rangeKey("S")
|
||||
.attributeDefinition(
|
||||
AttributeDefinition.builder().attributeName("H").attributeType(ScalarAttributeType.B).build())
|
||||
.attributeDefinition(
|
||||
AttributeDefinition.builder().attributeName("S").attributeType(ScalarAttributeType.B).build())
|
||||
.attributeDefinition(
|
||||
AttributeDefinition.builder().attributeName("U").attributeType(ScalarAttributeType.B).build())
|
||||
.localSecondaryIndex(LocalSecondaryIndex.builder().indexName("Message_UUID_Index")
|
||||
.keySchema(KeySchemaElement.builder().attributeName("H").keyType(KeyType.HASH).build(),
|
||||
KeySchemaElement.builder().attributeName("U").keyType(KeyType.RANGE).build())
|
||||
.projection(Projection.builder().projectionType(ProjectionType.KEYS_ONLY).build())
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
|
@ -51,11 +51,11 @@ import org.whispersystems.textsecuregcm.redis.RedisClusterExtension;
|
|||
import org.whispersystems.textsecuregcm.storage.Account;
|
||||
import org.whispersystems.textsecuregcm.storage.Device;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtension;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamoDbExtensionSchema.Tables;
|
||||
import org.whispersystems.textsecuregcm.storage.MessagesCache;
|
||||
import org.whispersystems.textsecuregcm.storage.MessagesDynamoDb;
|
||||
import org.whispersystems.textsecuregcm.storage.MessagesManager;
|
||||
import org.whispersystems.textsecuregcm.storage.ReportMessageManager;
|
||||
import org.whispersystems.textsecuregcm.tests.util.MessagesDynamoDbExtension;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import org.whispersystems.websocket.WebSocketClient;
|
||||
import org.whispersystems.websocket.messages.WebSocketResponseMessage;
|
||||
|
@ -65,7 +65,7 @@ import reactor.core.scheduler.Schedulers;
|
|||
class WebSocketConnectionIntegrationTest {
|
||||
|
||||
@RegisterExtension
|
||||
static DynamoDbExtension dynamoDbExtension = MessagesDynamoDbExtension.build();
|
||||
static final DynamoDbExtension DYNAMO_DB_EXTENSION = new DynamoDbExtension(Tables.MESSAGES);
|
||||
|
||||
@RegisterExtension
|
||||
static final RedisClusterExtension REDIS_CLUSTER_EXTENSION = RedisClusterExtension.builder().build();
|
||||
|
@ -90,8 +90,8 @@ class WebSocketConnectionIntegrationTest {
|
|||
messageDeliveryScheduler = Schedulers.newBoundedElastic(10, 10_000, "messageDelivery");
|
||||
messagesCache = new MessagesCache(REDIS_CLUSTER_EXTENSION.getRedisCluster(),
|
||||
REDIS_CLUSTER_EXTENSION.getRedisCluster(), sharedExecutorService, messageDeliveryScheduler, sharedExecutorService, Clock.systemUTC());
|
||||
messagesDynamoDb = new MessagesDynamoDb(dynamoDbExtension.getDynamoDbClient(),
|
||||
dynamoDbExtension.getDynamoDbAsyncClient(), MessagesDynamoDbExtension.TABLE_NAME, Duration.ofDays(7),
|
||||
messagesDynamoDb = new MessagesDynamoDb(DYNAMO_DB_EXTENSION.getDynamoDbClient(),
|
||||
DYNAMO_DB_EXTENSION.getDynamoDbAsyncClient(), Tables.MESSAGES.tableName(), Duration.ofDays(7),
|
||||
sharedExecutorService);
|
||||
reportMessageManager = mock(ReportMessageManager.class);
|
||||
account = mock(Account.class);
|
||||
|
|
Loading…
Reference in New Issue