mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-22 10:48:06 +01:00
Add test dependencies for FoundationDB
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import com.apple.foundationdb.Database;
|
||||
import com.apple.foundationdb.FDB;
|
||||
import java.io.IOException;
|
||||
|
||||
interface FoundationDbDatabaseLifecycleManager {
|
||||
|
||||
void initializeDatabase(final FDB fdb) throws IOException;
|
||||
|
||||
Database getDatabase();
|
||||
|
||||
void closeDatabase();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import com.apple.foundationdb.Database;
|
||||
import com.apple.foundationdb.FDB;
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
|
||||
class FoundationDbExtension implements BeforeAllCallback, ExtensionContext.Store.CloseableResource {
|
||||
|
||||
private static FoundationDbDatabaseLifecycleManager databaseLifecycleManager;
|
||||
|
||||
@Override
|
||||
public void beforeAll(final ExtensionContext context) throws IOException {
|
||||
if (databaseLifecycleManager == null) {
|
||||
final String serviceContainerName = System.getProperty("foundationDb.serviceContainerName");
|
||||
|
||||
databaseLifecycleManager = serviceContainerName != null
|
||||
? new ServiceContainerFoundationDbDatabaseLifecycleManager(serviceContainerName)
|
||||
: new TestcontainersFoundationDbDatabaseLifecycleManager();
|
||||
|
||||
databaseLifecycleManager.initializeDatabase(FDB.selectAPIVersion(730));
|
||||
|
||||
context.getRoot().getStore(ExtensionContext.Namespace.GLOBAL).put(getClass().getName(), this);
|
||||
}
|
||||
}
|
||||
|
||||
public Database getDatabase() {
|
||||
return databaseLifecycleManager.getDatabase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Throwable {
|
||||
if (databaseLifecycleManager != null) {
|
||||
databaseLifecycleManager.closeDatabase();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.whispersystems.textsecuregcm.util.TestRandomUtil;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
|
||||
public class FoundationDbTest {
|
||||
|
||||
@RegisterExtension
|
||||
static FoundationDbExtension FOUNDATION_DB_EXTENSION = new FoundationDbExtension();
|
||||
|
||||
@Test
|
||||
void setGetValue() {
|
||||
final byte[] key = "test".getBytes(StandardCharsets.UTF_8);
|
||||
final byte[] value = TestRandomUtil.nextBytes(16);
|
||||
|
||||
FOUNDATION_DB_EXTENSION.getDatabase().run(transaction -> {
|
||||
transaction.set(key, value);
|
||||
return null;
|
||||
});
|
||||
|
||||
final byte[] retrievedValue = FOUNDATION_DB_EXTENSION.getDatabase().run(transaction -> transaction.get(key).join());
|
||||
|
||||
assertArrayEquals(value, retrievedValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import com.apple.foundationdb.Database;
|
||||
import com.apple.foundationdb.FDB;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Manages the lifecycle of a database connected to a FoundationDB instance running as an external service container.
|
||||
*/
|
||||
class ServiceContainerFoundationDbDatabaseLifecycleManager implements FoundationDbDatabaseLifecycleManager {
|
||||
|
||||
private final String foundationDbServiceContainerName;
|
||||
|
||||
private Database database;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ServiceContainerFoundationDbDatabaseLifecycleManager.class);
|
||||
|
||||
ServiceContainerFoundationDbDatabaseLifecycleManager(final String foundationDbServiceContainerName) {
|
||||
log.info("Using FoundationDB service container: {}", foundationDbServiceContainerName);
|
||||
this.foundationDbServiceContainerName = foundationDbServiceContainerName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeDatabase(final FDB fdb) throws IOException {
|
||||
final File clusterFile = File.createTempFile("fdb.cluster", "");
|
||||
clusterFile.deleteOnExit();
|
||||
|
||||
try (final FileWriter fileWriter = new FileWriter(clusterFile)) {
|
||||
fileWriter.write(String.format("docker:docker@%s:4500", foundationDbServiceContainerName));
|
||||
}
|
||||
|
||||
// If we don't initialize the database before trying to use it, things will just hang in a mysterious, message-free
|
||||
// way. Note that the `new` keyword in `configure new single memory` means that we can't accidentally clobber an
|
||||
// existing database (though initialization may fail if there's already a database present).
|
||||
new ProcessBuilder("/usr/bin/fdbcli",
|
||||
"-C", clusterFile.getAbsolutePath(),
|
||||
"--exec", "configure new single memory")
|
||||
.start()
|
||||
.onExit()
|
||||
.join();
|
||||
|
||||
database = fdb.open(clusterFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Database getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeDatabase() {
|
||||
database.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
import com.apple.foundationdb.Database;
|
||||
import com.apple.foundationdb.FDB;
|
||||
import earth.adi.testcontainers.containers.FoundationDBContainer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
class TestcontainersFoundationDbDatabaseLifecycleManager implements FoundationDbDatabaseLifecycleManager {
|
||||
|
||||
private FoundationDBContainer foundationDBContainer;
|
||||
private Database database;
|
||||
|
||||
private static final String FOUNDATIONDB_IMAGE_NAME = "foundationdb/foundationdb:" +
|
||||
System.getProperty("foundationdb.version", "7.3.62");
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TestcontainersFoundationDbDatabaseLifecycleManager.class);
|
||||
|
||||
@Override
|
||||
public void initializeDatabase(final FDB fdb) {
|
||||
log.info("Using Testcontainers FoundationDB container: {}", FOUNDATIONDB_IMAGE_NAME);
|
||||
|
||||
foundationDBContainer = new FoundationDBContainer(DockerImageName.parse(FOUNDATIONDB_IMAGE_NAME));
|
||||
foundationDBContainer.start();
|
||||
|
||||
database = fdb.open(foundationDBContainer.getClusterFilePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Database getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeDatabase() {
|
||||
database.close();
|
||||
foundationDBContainer.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user