Use AmazonDynamoDBLocal instead of DynamoDBProxyServer
This commit is contained in:
		
							parent
							
								
									59e0137816
								
							
						
					
					
						commit
						d6f890c7b9
					
				
							
								
								
									
										29
									
								
								pom.xml
								
								
								
								
							
							
						
						
									
										29
									
								
								pom.xml
								
								
								
								
							| 
						 | 
				
			
			@ -43,7 +43,7 @@
 | 
			
		|||
    <commons-io.version>2.17.0</commons-io.version>
 | 
			
		||||
    <dropwizard.version>4.0.10</dropwizard.version>
 | 
			
		||||
    <dropwizard-metrics-datadog.version>1.1.13</dropwizard-metrics-datadog.version>
 | 
			
		||||
    <!-- can be updated to latest version with Dropwizard 5 (Jetty 12) -->
 | 
			
		||||
    <!-- can be updated to latest version with Dropwizard 5 (Jetty 12); will then need to disable telemetry -->
 | 
			
		||||
    <dynamodblocal.version>2.2.1</dynamodblocal.version>
 | 
			
		||||
    <google-cloud-libraries.version>26.50.0</google-cloud-libraries.version>
 | 
			
		||||
    <grpc.version>1.61.1</grpc.version> <!-- should be kept in sync with the value from Google libraries-bom -->
 | 
			
		||||
| 
						 | 
				
			
			@ -482,33 +482,6 @@
 | 
			
		|||
        <groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
        <artifactId>maven-dependency-plugin</artifactId>
 | 
			
		||||
        <version>3.7.1</version>
 | 
			
		||||
        <executions>
 | 
			
		||||
          <execution>
 | 
			
		||||
            <id>copy</id>
 | 
			
		||||
            <phase>test-compile</phase>
 | 
			
		||||
            <goals>
 | 
			
		||||
              <goal>copy-dependencies</goal>
 | 
			
		||||
            </goals>
 | 
			
		||||
            <configuration>
 | 
			
		||||
              <includeScope>test</includeScope>
 | 
			
		||||
              <includeTypes>so,dll,dylib</includeTypes>
 | 
			
		||||
              <outputDirectory>${project.build.directory}/lib</outputDirectory>
 | 
			
		||||
            </configuration>
 | 
			
		||||
          </execution>
 | 
			
		||||
        </executions>
 | 
			
		||||
      </plugin>
 | 
			
		||||
 | 
			
		||||
      <plugin>
 | 
			
		||||
        <groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
        <artifactId>maven-surefire-plugin</artifactId>
 | 
			
		||||
        <configuration>
 | 
			
		||||
          <systemProperties>
 | 
			
		||||
            <property>
 | 
			
		||||
              <name>sqlite4java.library.path</name>
 | 
			
		||||
              <value>${project.build.directory}/lib</value>
 | 
			
		||||
            </property>
 | 
			
		||||
          </systemProperties>
 | 
			
		||||
        </configuration>
 | 
			
		||||
      </plugin>
 | 
			
		||||
 | 
			
		||||
      <plugin>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,6 @@
 | 
			
		|||
  <properties>
 | 
			
		||||
    <firebase-admin.version>9.4.1</firebase-admin.version>
 | 
			
		||||
    <java-uuid-generator.version>5.1.0</java-uuid-generator.version>
 | 
			
		||||
    <sqlite4java.version>1.0.392</sqlite4java.version>
 | 
			
		||||
    <google-androidpublisher.version>v3-rev20241016-2.0.0</google-androidpublisher.version>
 | 
			
		||||
    <storekit.version>3.2.0</storekit.version>
 | 
			
		||||
  </properties>
 | 
			
		||||
| 
						 | 
				
			
			@ -435,13 +434,6 @@
 | 
			
		|||
      <scope>test</scope>
 | 
			
		||||
    </dependency>
 | 
			
		||||
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>com.almworks.sqlite4java</groupId>
 | 
			
		||||
      <artifactId>sqlite4java</artifactId>
 | 
			
		||||
      <version>${sqlite4java.version}</version>
 | 
			
		||||
      <scope>test</scope>
 | 
			
		||||
    </dependency>
 | 
			
		||||
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>io.projectreactor</groupId>
 | 
			
		||||
      <artifactId>reactor-core</artifactId>
 | 
			
		||||
| 
						 | 
				
			
			@ -480,13 +472,6 @@
 | 
			
		|||
      <artifactId>DynamoDBLocal</artifactId>
 | 
			
		||||
      <scope>test</scope>
 | 
			
		||||
    </dependency>
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>io.github.ganadist.sqlite4java</groupId>
 | 
			
		||||
      <artifactId>libsqlite4java-osx-aarch64</artifactId>
 | 
			
		||||
      <version>${sqlite4java.version}</version>
 | 
			
		||||
      <type>dylib</type>
 | 
			
		||||
      <scope>test</scope>
 | 
			
		||||
    </dependency>
 | 
			
		||||
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>com.google.auth</groupId>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,8 +26,6 @@ public class LocalWhisperServerService {
 | 
			
		|||
 | 
			
		||||
    System.setProperty("secrets.bundle.filename",
 | 
			
		||||
        Resources.getResource("config/test-secrets-bundle.yml").getPath());
 | 
			
		||||
    System.setProperty("sqlite.dir", "service/target/lib");
 | 
			
		||||
    System.setProperty("aws.region", "local-test-region");
 | 
			
		||||
 | 
			
		||||
    final String config = Optional.ofNullable(System.getenv(SIGNAL_SERVER_CONFIG_ENV_VAR))
 | 
			
		||||
        .orElse(Resources.getResource("config/test.yml").getPath());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,8 +45,6 @@ class WhisperServerServiceTest {
 | 
			
		|||
  static {
 | 
			
		||||
    System.setProperty("secrets.bundle.filename",
 | 
			
		||||
        Resources.getResource("config/test-secrets-bundle.yml").getPath());
 | 
			
		||||
    // needed for AppConfigDataClient initialization
 | 
			
		||||
    System.setProperty("aws.region", "local-test-region");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static final DropwizardAppExtension<WhisperServerConfiguration> EXTENSION = new DropwizardAppExtension<>(
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +55,6 @@ class WhisperServerServiceTest {
 | 
			
		|||
  @AfterAll
 | 
			
		||||
  static void teardown() {
 | 
			
		||||
    System.clearProperty("secrets.bundle.filename");
 | 
			
		||||
    System.clearProperty("aws.region");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @BeforeEach
 | 
			
		||||
| 
						 | 
				
			
			@ -140,36 +137,35 @@ class WhisperServerServiceTest {
 | 
			
		|||
    final AwsCredentialsProvider awsCredentialsProvider = EXTENSION.getConfiguration().getAwsCredentialsConfiguration()
 | 
			
		||||
        .build();
 | 
			
		||||
 | 
			
		||||
    try (DynamoDbClient dynamoDbClient = EXTENSION.getConfiguration().getDynamoDbClientConfiguration()
 | 
			
		||||
        .buildSyncClient(awsCredentialsProvider, new NoopAwsSdkMetricPublisher())) {
 | 
			
		||||
    final DynamoDbClient dynamoDbClient = EXTENSION.getConfiguration().getDynamoDbClientConfiguration()
 | 
			
		||||
        .buildSyncClient(awsCredentialsProvider, new NoopAwsSdkMetricPublisher());
 | 
			
		||||
 | 
			
		||||
      final DynamoDbExtension.TableSchema numbers = DynamoDbExtensionSchema.Tables.NUMBERS;
 | 
			
		||||
      final AttributeValue numberAV = AttributeValues.s("+12125550001");
 | 
			
		||||
    final DynamoDbExtension.TableSchema numbers = DynamoDbExtensionSchema.Tables.NUMBERS;
 | 
			
		||||
    final AttributeValue numberAV = AttributeValues.s("+12125550001");
 | 
			
		||||
 | 
			
		||||
      final GetItemResponse notFoundResponse = dynamoDbClient.getItem(GetItemRequest.builder()
 | 
			
		||||
          .tableName(numbers.tableName())
 | 
			
		||||
          .key(Map.of(numbers.hashKeyName(), numberAV))
 | 
			
		||||
          .build());
 | 
			
		||||
    final GetItemResponse notFoundResponse = dynamoDbClient.getItem(GetItemRequest.builder()
 | 
			
		||||
        .tableName(numbers.tableName())
 | 
			
		||||
        .key(Map.of(numbers.hashKeyName(), numberAV))
 | 
			
		||||
        .build());
 | 
			
		||||
 | 
			
		||||
      assertFalse(notFoundResponse.hasItem());
 | 
			
		||||
    assertFalse(notFoundResponse.hasItem());
 | 
			
		||||
 | 
			
		||||
      dynamoDbClient.putItem(PutItemRequest.builder()
 | 
			
		||||
          .tableName(numbers.tableName())
 | 
			
		||||
          .item(Map.of(numbers.hashKeyName(), numberAV))
 | 
			
		||||
          .build());
 | 
			
		||||
    dynamoDbClient.putItem(PutItemRequest.builder()
 | 
			
		||||
        .tableName(numbers.tableName())
 | 
			
		||||
        .item(Map.of(numbers.hashKeyName(), numberAV))
 | 
			
		||||
        .build());
 | 
			
		||||
 | 
			
		||||
      final GetItemResponse foundResponse = dynamoDbClient.getItem(GetItemRequest.builder()
 | 
			
		||||
          .tableName(numbers.tableName())
 | 
			
		||||
          .key(Map.of(numbers.hashKeyName(), numberAV))
 | 
			
		||||
          .build());
 | 
			
		||||
    final GetItemResponse foundResponse = dynamoDbClient.getItem(GetItemRequest.builder()
 | 
			
		||||
        .tableName(numbers.tableName())
 | 
			
		||||
        .key(Map.of(numbers.hashKeyName(), numberAV))
 | 
			
		||||
        .build());
 | 
			
		||||
 | 
			
		||||
      assertTrue(foundResponse.hasItem());
 | 
			
		||||
    assertTrue(foundResponse.hasItem());
 | 
			
		||||
 | 
			
		||||
      dynamoDbClient.deleteItem(DeleteItemRequest.builder()
 | 
			
		||||
          .tableName(numbers.tableName())
 | 
			
		||||
          .key(Map.of(numbers.hashKeyName(), numberAV))
 | 
			
		||||
          .build());
 | 
			
		||||
    }
 | 
			
		||||
    dynamoDbClient.deleteItem(DeleteItemRequest.builder()
 | 
			
		||||
        .tableName(numbers.tableName())
 | 
			
		||||
        .key(Map.of(numbers.hashKeyName(), numberAV))
 | 
			
		||||
        .build());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,8 +16,7 @@ import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
 | 
			
		|||
@JsonTypeName("local")
 | 
			
		||||
public class LocalDynamoDbFactory implements DynamoDbClientFactory {
 | 
			
		||||
 | 
			
		||||
  private static final DynamoDbExtension EXTENSION = new DynamoDbExtension(System.getProperty("sqlite.dir"),
 | 
			
		||||
      DynamoDbExtensionSchema.Tables.values());
 | 
			
		||||
  private static final DynamoDbExtension EXTENSION = new DynamoDbExtension(DynamoDbExtensionSchema.Tables.values());
 | 
			
		||||
 | 
			
		||||
  static {
 | 
			
		||||
    try {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,21 +5,12 @@
 | 
			
		|||
 | 
			
		||||
package org.whispersystems.textsecuregcm.storage;
 | 
			
		||||
 | 
			
		||||
import com.almworks.sqlite4java.SQLite;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.local.main.ServerRunner;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.local.server.DynamoDBProxyServer;
 | 
			
		||||
import java.net.ServerSocket;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.time.Duration;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.local.shared.access.AmazonDynamoDBLocal;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.concurrent.atomic.AtomicBoolean;
 | 
			
		||||
import org.junit.jupiter.api.extension.AfterEachCallback;
 | 
			
		||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
 | 
			
		||||
import org.junit.jupiter.api.extension.ExtensionContext;
 | 
			
		||||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
 | 
			
		||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
 | 
			
		||||
import software.amazon.awssdk.regions.Region;
 | 
			
		||||
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
 | 
			
		||||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
 | 
			
		||||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
 | 
			
		||||
| 
						 | 
				
			
			@ -29,12 +20,9 @@ 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.ProvisionedThroughput;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
 | 
			
		||||
public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback {
 | 
			
		||||
 | 
			
		||||
  private static final String DEFAULT_LIBRARY_PATH = "target/lib";
 | 
			
		||||
 | 
			
		||||
  public interface TableSchema {
 | 
			
		||||
    String tableName();
 | 
			
		||||
    String hashKeyName();
 | 
			
		||||
| 
						 | 
				
			
			@ -58,36 +46,15 @@ public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback
 | 
			
		|||
      .writeCapacityUnits(20L)
 | 
			
		||||
      .build();
 | 
			
		||||
 | 
			
		||||
  private static final AtomicBoolean libraryLoaded = new AtomicBoolean();
 | 
			
		||||
 | 
			
		||||
  private DynamoDBProxyServer server;
 | 
			
		||||
  private int port;
 | 
			
		||||
 | 
			
		||||
  private final String libraryPath;
 | 
			
		||||
  private AmazonDynamoDBLocal embedded;
 | 
			
		||||
  private final List<TableSchema> schemas;
 | 
			
		||||
  private DynamoDbClient dynamoDB2;
 | 
			
		||||
  private DynamoDbAsyncClient dynamoAsyncDB2;
 | 
			
		||||
 | 
			
		||||
  public DynamoDbExtension(TableSchema... schemas) {
 | 
			
		||||
    this(DEFAULT_LIBRARY_PATH, schemas);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public DynamoDbExtension(@Nullable final String libraryPath, TableSchema... schemas) {
 | 
			
		||||
    this.libraryPath = Optional.ofNullable(libraryPath).orElse(DEFAULT_LIBRARY_PATH);
 | 
			
		||||
    this.schemas = List.of(schemas);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void loadLibrary() {
 | 
			
		||||
    // to avoid noise in the logs from “library already loaded” warnings, we make sure we only set it once
 | 
			
		||||
    if (libraryLoaded.get()) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (libraryLoaded.compareAndSet(false, true)) {
 | 
			
		||||
      // if you see a library failed to load error, you need to run mvn test-compile at least once first
 | 
			
		||||
      SQLite.setLibraryPath(this.libraryPath);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void afterEach(ExtensionContext context) {
 | 
			
		||||
    stopServer();
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +65,7 @@ public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback
 | 
			
		|||
   */
 | 
			
		||||
  public void stopServer() {
 | 
			
		||||
    try {
 | 
			
		||||
      server.stop();
 | 
			
		||||
      embedded.shutdown();
 | 
			
		||||
    } catch (Exception e) {
 | 
			
		||||
      throw new RuntimeException(e);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -106,9 +73,6 @@ public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback
 | 
			
		|||
 | 
			
		||||
  @Override
 | 
			
		||||
  public void beforeEach(ExtensionContext context) throws Exception {
 | 
			
		||||
 | 
			
		||||
    startServer();
 | 
			
		||||
 | 
			
		||||
    initializeClient();
 | 
			
		||||
 | 
			
		||||
    createTables();
 | 
			
		||||
| 
						 | 
				
			
			@ -143,35 +107,10 @@ public class DynamoDbExtension implements BeforeEachCallback, AfterEachCallback
 | 
			
		|||
    getDynamoDbClient().createTable(createTableRequest);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void startServer() throws Exception {
 | 
			
		||||
    loadLibrary();
 | 
			
		||||
    try (ServerSocket serverSocket = new ServerSocket(0)) {
 | 
			
		||||
      port = serverSocket.getLocalPort();
 | 
			
		||||
    }
 | 
			
		||||
    server = ServerRunner.createServerFromCommandLineArgs(
 | 
			
		||||
        new String[]{"-disableTelemetry", "-inMemory", "-port", String.valueOf(port)});
 | 
			
		||||
    server.start();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void initializeClient() {
 | 
			
		||||
    dynamoDB2 = DynamoDbClient.builder()
 | 
			
		||||
        .endpointOverride(URI.create("http://localhost:" + port))
 | 
			
		||||
        .region(Region.of("local-test-region"))
 | 
			
		||||
        .credentialsProvider(StaticCredentialsProvider.create(
 | 
			
		||||
            AwsBasicCredentials.create("accessKey", "secretKey")))
 | 
			
		||||
        .overrideConfiguration(builder ->
 | 
			
		||||
            builder.apiCallTimeout(Duration.ofSeconds(1))
 | 
			
		||||
                .apiCallAttemptTimeout(Duration.ofSeconds(1)))
 | 
			
		||||
        .build();
 | 
			
		||||
    dynamoAsyncDB2 = DynamoDbAsyncClient.builder()
 | 
			
		||||
        .endpointOverride(URI.create("http://localhost:" + port))
 | 
			
		||||
        .region(Region.of("local-test-region"))
 | 
			
		||||
        .credentialsProvider(StaticCredentialsProvider.create(
 | 
			
		||||
            AwsBasicCredentials.create("accessKey", "secretKey")))
 | 
			
		||||
        .overrideConfiguration(builder ->
 | 
			
		||||
            builder.apiCallTimeout(Duration.ofSeconds(1))
 | 
			
		||||
                .apiCallAttemptTimeout(Duration.ofSeconds(1)))
 | 
			
		||||
        .build();
 | 
			
		||||
    embedded = DynamoDBEmbedded.create();
 | 
			
		||||
    dynamoDB2 = embedded.dynamoDbClient();
 | 
			
		||||
    dynamoAsyncDB2 = embedded.dynamoDbAsyncClient();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public DynamoDbClient getDynamoDbClient() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue