Consolidate profiles store tests and discard ProfilesStore interface

This commit is contained in:
Jon Chambers
2021-11-24 17:07:51 -05:00
committed by Jon Chambers
parent afa910bbd7
commit 064861b930
9 changed files with 155 additions and 200 deletions

View File

@@ -1,147 +0,0 @@
/*
* Copyright 2013-2021 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.storage;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
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 software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
class ProfilesDynamoDbTest extends ProfilesTest {
private static final String PROFILES_TABLE_NAME = "profiles_test";
@RegisterExtension
static DynamoDbExtension dynamoDbExtension = DynamoDbExtension.builder()
.tableName(PROFILES_TABLE_NAME)
.hashKey(ProfilesDynamoDb.KEY_ACCOUNT_UUID)
.rangeKey(ProfilesDynamoDb.ATTR_VERSION)
.attributeDefinition(AttributeDefinition.builder()
.attributeName(ProfilesDynamoDb.KEY_ACCOUNT_UUID)
.attributeType(ScalarAttributeType.B)
.build())
.attributeDefinition(AttributeDefinition.builder()
.attributeName(ProfilesDynamoDb.ATTR_VERSION)
.attributeType(ScalarAttributeType.S)
.build())
.build();
private ProfilesDynamoDb profiles;
@BeforeEach
void setUp() {
profiles = new ProfilesDynamoDb(dynamoDbExtension.getDynamoDbClient(),
dynamoDbExtension.getDynamoDbAsyncClient(),
PROFILES_TABLE_NAME);
}
@Override
protected ProfilesStore getProfilesStore() {
return profiles;
}
@ParameterizedTest
@MethodSource
void buildUpdateExpression(final VersionedProfile profile, final String expectedUpdateExpression) {
assertEquals(expectedUpdateExpression, ProfilesDynamoDb.buildUpdateExpression(profile));
}
private static Stream<Arguments> buildUpdateExpression() {
final byte[] commitment = "commitment".getBytes(StandardCharsets.UTF_8);
return Stream.of(
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", "about", "paymentAddress", commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #about = :about, #aboutEmoji = :aboutEmoji, #paymentAddress = :paymentAddress"),
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", "about", null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #about = :about, #aboutEmoji = :aboutEmoji REMOVE #paymentAddress"),
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", null, null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #aboutEmoji = :aboutEmoji REMOVE #about, #paymentAddress"),
Arguments.of(
new VersionedProfile("version", "name", "avatar", null, null, null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar REMOVE #about, #aboutEmoji, #paymentAddress"),
Arguments.of(
new VersionedProfile("version", "name", null, null, null, null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name REMOVE #avatar, #about, #aboutEmoji, #paymentAddress"),
Arguments.of(
new VersionedProfile("version", null, null, null, null, null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment) REMOVE #name, #avatar, #about, #aboutEmoji, #paymentAddress")
);
}
@ParameterizedTest
@MethodSource
void buildUpdateExpressionAttributeValues(final VersionedProfile profile, final Map<String, AttributeValue> expectedAttributeValues) {
assertEquals(expectedAttributeValues, ProfilesDynamoDb.buildUpdateExpressionAttributeValues(profile));
}
private static Stream<Arguments> buildUpdateExpressionAttributeValues() {
final byte[] commitment = "commitment".getBytes(StandardCharsets.UTF_8);
return Stream.of(
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", "about", "paymentAddress", commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"),
":avatar", AttributeValues.fromString("avatar"),
":aboutEmoji", AttributeValues.fromString("emoji"),
":about", AttributeValues.fromString("about"),
":paymentAddress", AttributeValues.fromString("paymentAddress"))),
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", "about", null, commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"),
":avatar", AttributeValues.fromString("avatar"),
":aboutEmoji", AttributeValues.fromString("emoji"),
":about", AttributeValues.fromString("about"))),
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", null, null, commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"),
":avatar", AttributeValues.fromString("avatar"),
":aboutEmoji", AttributeValues.fromString("emoji"))),
Arguments.of(
new VersionedProfile("version", "name", "avatar", null, null, null, commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"),
":avatar", AttributeValues.fromString("avatar"))),
Arguments.of(
new VersionedProfile("version", "name", null, null, null, null, commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"))),
Arguments.of(
new VersionedProfile("version", null, null, null, null, null, commitment),
Map.of(":commitment", AttributeValues.fromByteArray(commitment)))
);
}
}

View File

@@ -5,20 +5,56 @@
package org.whispersystems.textsecuregcm.storage;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
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 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;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import java.util.stream.Stream;
public abstract class ProfilesTest {
protected abstract ProfilesStore getProfilesStore();
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();
private Profiles profiles;
@BeforeEach
void setUp() {
profiles = new Profiles(dynamoDbExtension.getDynamoDbClient(),
dynamoDbExtension.getDynamoDbAsyncClient(),
PROFILES_TABLE_NAME);
}
@Test
void testSetGet() {
ProfilesStore profiles = getProfilesStore();
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", "emoji",
"the very model of a modern major general",
@@ -37,7 +73,6 @@ public abstract class ProfilesTest {
@Test
void testDeleteReset() {
ProfilesStore profiles = getProfilesStore();
UUID uuid = UUID.randomUUID();
profiles.set(uuid, new VersionedProfile("123", "foo", "avatarLocation", "emoji",
"the very model of a modern major general",
@@ -62,7 +97,6 @@ public abstract class ProfilesTest {
@Test
void testSetGetNullOptionalFields() {
ProfilesStore profiles = getProfilesStore();
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("123", "foo", null, null, null, null,
"acommitment".getBytes());
@@ -80,7 +114,6 @@ public abstract class ProfilesTest {
@Test
void testSetReplace() {
ProfilesStore profiles = getProfilesStore();
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", null, null,
"paymentAddress", "acommitment".getBytes());
@@ -113,7 +146,6 @@ public abstract class ProfilesTest {
@Test
void testMultipleVersions() {
ProfilesStore profiles = getProfilesStore();
UUID uuid = UUID.randomUUID();
VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null,
null, "acommitmnet".getBytes());
@@ -145,7 +177,6 @@ public abstract class ProfilesTest {
@Test
void testMissing() {
ProfilesStore profiles = getProfilesStore();
UUID uuid = UUID.randomUUID();
VersionedProfile profile = new VersionedProfile("123", "foo", "avatarLocation", null, null,
null, "aDigest".getBytes());
@@ -158,7 +189,6 @@ public abstract class ProfilesTest {
@Test
void testDelete() {
ProfilesStore profiles = getProfilesStore();
UUID uuid = UUID.randomUUID();
VersionedProfile profileOne = new VersionedProfile("123", "foo", "avatarLocation", null, null,
null, "aDigest".getBytes());
@@ -177,4 +207,96 @@ public abstract class ProfilesTest {
assertThat(retrieved.isPresent()).isFalse();
}
@ParameterizedTest
@MethodSource
void buildUpdateExpression(final VersionedProfile profile, final String expectedUpdateExpression) {
assertEquals(expectedUpdateExpression, Profiles.buildUpdateExpression(profile));
}
private static Stream<Arguments> buildUpdateExpression() {
final byte[] commitment = "commitment".getBytes(StandardCharsets.UTF_8);
return Stream.of(
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", "about", "paymentAddress", commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #about = :about, #aboutEmoji = :aboutEmoji, #paymentAddress = :paymentAddress"),
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", "about", null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #about = :about, #aboutEmoji = :aboutEmoji REMOVE #paymentAddress"),
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", null, null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar, #aboutEmoji = :aboutEmoji REMOVE #about, #paymentAddress"),
Arguments.of(
new VersionedProfile("version", "name", "avatar", null, null, null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name, #avatar = :avatar REMOVE #about, #aboutEmoji, #paymentAddress"),
Arguments.of(
new VersionedProfile("version", "name", null, null, null, null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment), #name = :name REMOVE #avatar, #about, #aboutEmoji, #paymentAddress"),
Arguments.of(
new VersionedProfile("version", null, null, null, null, null, commitment),
"SET #commitment = if_not_exists(#commitment, :commitment) REMOVE #name, #avatar, #about, #aboutEmoji, #paymentAddress")
);
}
@ParameterizedTest
@MethodSource
void buildUpdateExpressionAttributeValues(final VersionedProfile profile, final Map<String, AttributeValue> expectedAttributeValues) {
assertEquals(expectedAttributeValues, Profiles.buildUpdateExpressionAttributeValues(profile));
}
private static Stream<Arguments> buildUpdateExpressionAttributeValues() {
final byte[] commitment = "commitment".getBytes(StandardCharsets.UTF_8);
return Stream.of(
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", "about", "paymentAddress", commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"),
":avatar", AttributeValues.fromString("avatar"),
":aboutEmoji", AttributeValues.fromString("emoji"),
":about", AttributeValues.fromString("about"),
":paymentAddress", AttributeValues.fromString("paymentAddress"))),
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", "about", null, commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"),
":avatar", AttributeValues.fromString("avatar"),
":aboutEmoji", AttributeValues.fromString("emoji"),
":about", AttributeValues.fromString("about"))),
Arguments.of(
new VersionedProfile("version", "name", "avatar", "emoji", null, null, commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"),
":avatar", AttributeValues.fromString("avatar"),
":aboutEmoji", AttributeValues.fromString("emoji"))),
Arguments.of(
new VersionedProfile("version", "name", "avatar", null, null, null, commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"),
":avatar", AttributeValues.fromString("avatar"))),
Arguments.of(
new VersionedProfile("version", "name", null, null, null, null, commitment),
Map.of(
":commitment", AttributeValues.fromByteArray(commitment),
":name", AttributeValues.fromString("name"))),
Arguments.of(
new VersionedProfile("version", null, null, null, null, null, commitment),
Map.of(":commitment", AttributeValues.fromByteArray(commitment)))
);
}
}

View File

@@ -25,14 +25,14 @@ import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.whispersystems.textsecuregcm.redis.FaultTolerantRedisCluster;
import org.whispersystems.textsecuregcm.storage.ProfilesDynamoDb;
import org.whispersystems.textsecuregcm.storage.Profiles;
import org.whispersystems.textsecuregcm.storage.ProfilesManager;
import org.whispersystems.textsecuregcm.storage.VersionedProfile;
import org.whispersystems.textsecuregcm.tests.util.RedisClusterHelper;
public class ProfilesManagerTest {
private ProfilesDynamoDb profiles;
private Profiles profiles;
private RedisAdvancedClusterCommands<String, String> commands;
private ProfilesManager profilesManager;
@@ -43,7 +43,7 @@ public class ProfilesManagerTest {
commands = mock(RedisAdvancedClusterCommands.class);
final FaultTolerantRedisCluster cacheCluster = RedisClusterHelper.buildMockRedisCluster(commands);
profiles = mock(ProfilesDynamoDb.class);
profiles = mock(Profiles.class);
profilesManager = new ProfilesManager(profiles, cacheCluster);
}