Skip to content

Commit 7bffe9a

Browse files
authored
Add support for testing against multiple FDB clusters (#3575)
This changes the way we specify cluster files in tests. It replaces the `fdb-environment.properties` with `fdb-environment.yaml`. The new format allows for specifying multiple cluster files. The majority of tests now randomly chose a file at the start of the test from the list of the available ones. The following sub-projects set the environment variable in the gradle task because getting the project under test to support custom cluster files seemed like a bigger task: - fdb-relational-cli - fdb-relational-jdbc Our CI builds also, now, setup two FDB clusters, and create an `fdb-environment.properties`. I added one new "test" to validate this all works. It connects to two different clusters. It `assume`s that there are at least two clusters. At some point in the future we will want to make that a stronger contract to ensure that a bug in our CI setup doesn't cause us to not run all the multi-cluster tests. I created Draft PR: #3623 to ensure that everything still works if you don't specify `fdb-environment.yaml` I also created this PR off the same version of main to confirm the test counts didn't change: #3621 Apparently we do merge main to do the tests so PR #3621 saw fewer tests than this branch when it was last run. I re-ran and they may be the same depending on whether new tests were merged. I validated some of the differences, and they look to be expected. Resolves: #3574
1 parent 326de14 commit 7bffe9a

File tree

54 files changed

+590
-127
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+590
-127
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ protogen/
8080

8181
# Local FDB settings
8282
fdb-environment.properties
83+
fdb-environment.yaml
8384

8485
# Docker local support
8586
run/

actions/setup-fdb/action.yml

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,57 @@ runs:
3131
- name: Install FDB Server
3232
shell: bash
3333
run: sudo dpkg -i ~/.fdb-cache/${{ steps.fdb_filenames.outputs.client_deb }} ~/.fdb-cache/${{ steps.fdb_filenames.outputs.server_deb }}
34-
- name: Fix FDB Network Addresses
34+
- name: Stop default fdb
3535
shell: bash
36-
run: sudo sed -i -e "s/public_address = auto:\$ID/public_address = 127.0.0.1:\$ID/g" -e "s/listen_address = public/listen_address = 0.0.0.0:\$ID/g" /etc/foundationdb/foundationdb.conf
37-
- name: Start FDB Server
36+
run: sudo service foundationdb stop
37+
38+
- name: Create cluster1 config
39+
shell: bash
40+
run: |
41+
sudo cp /etc/foundationdb/foundationdb.conf /etc/foundationdb/foundationdb1.conf
42+
43+
sudo sed -i -e "s/\/etc\/foundationdb\/fdb.cluster/\/etc\/foundationdb\/fdb1.cluster/g" \
44+
-e "s/\/var\/log\/foundationdb/\/var\/log\/foundationdb1/" \
45+
-e "s/fdbserver.4500/fdbserver.4600/g" \
46+
/etc/foundationdb/foundationdb1.conf
47+
48+
sudo bash -c "echo 'fdb1:$(mktemp -u XXXXXXXX)@127.0.0.1:4600' > /etc/foundationdb/fdb1.cluster"
49+
- name: Create cluster2 config
3850
shell: bash
39-
run: sudo /usr/lib/foundationdb/fdbmonitor /etc/foundationdb/foundationdb.conf --daemonize
40-
- name: Switch FDB to SSD
51+
run: |
52+
sudo cp /etc/foundationdb/foundationdb.conf /etc/foundationdb/foundationdb2.conf
53+
54+
sudo sed -i -e "s/\/etc\/foundationdb\/fdb.cluster/\/etc\/foundationdb\/fdb2.cluster/g" \
55+
-e "s/\/var\/log\/foundationdb/\/var\/log\/foundationdb2/" \
56+
-e "s/fdbserver.4500/fdbserver.4700/g" \
57+
/etc/foundationdb/foundationdb2.conf
58+
59+
sudo bash -c "echo 'fdb2:$(mktemp -u XXXXXXXX)@127.0.0.1:4700' > /etc/foundationdb/fdb2.cluster"
60+
61+
- name: create dirs & set permissions
4162
shell: bash
42-
run: fdbcli --exec "configure single ssd storage_migration_type=aggressive; status"
63+
run: |
64+
sudo mkdir /var/log/foundationdb1 /var/log/foundationdb2
65+
sudo chown foundationdb:foundationdb /etc/foundationdb/fdb1.cluster /etc/foundationdb/fdb2.cluster /var/log/foundationdb1 /var/log/foundationdb2
66+
sudo chmod 664 /etc/foundationdb/fdb1.cluster /etc/foundationdb/fdb2.cluster
67+
sudo chmod 700 /var/log/foundationdb1 /var/log/foundationdb2
68+
69+
- name: Start FDB Server 1
70+
shell: bash
71+
run: sudo /usr/lib/foundationdb/fdbmonitor --conffile /etc/foundationdb/foundationdb1.conf --lockfile /var/run/fdbmonitor1.pid --loggroup fdb1 --daemonize
72+
- name: Start FDB Server 2
73+
shell: bash
74+
run: sudo /usr/lib/foundationdb/fdbmonitor --conffile /etc/foundationdb/foundationdb2.conf --lockfile /var/run/fdbmonitor2.pid --loggroup fdb2 --daemonize
75+
76+
- name: Switch FDB 1 to SSD
77+
shell: bash
78+
run: fdbcli -C /etc/foundationdb/fdb1.cluster --exec "configure new single ssd storage_migration_type=aggressive; status"
79+
- name: Switch FDB 2 to SSD
80+
shell: bash
81+
run: fdbcli -C /etc/foundationdb/fdb2.cluster --exec "configure new single ssd storage_migration_type=aggressive; status"
82+
- name: Create fdb-environment.yaml
83+
shell: bash
84+
run: |
85+
echo "clusterFiles: " >> fdb-environment.yaml
86+
echo " - /etc/foundationdb/fdb1.cluster" >> fdb-environment.yaml
87+
echo " - /etc/foundationdb/fdb2.cluster" >> fdb-environment.yaml

build.gradle

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
* limitations under the License.
1919
*/
2020

21+
import org.yaml.snakeyaml.Yaml
22+
23+
import org.apache.tools.ant.taskdefs.condition.Os
24+
2125
buildscript {
2226
repositories {
2327
if (Boolean.parseBoolean(mavenLocalEnabled)) {
@@ -29,6 +33,7 @@ buildscript {
2933

3034
dependencies {
3135
classpath 'org.jboss.tattletale:tattletale:1.2.0.Beta2'
36+
classpath libs.snakeyaml
3237
}
3338
}
3439

@@ -341,6 +346,8 @@ if (!JavaVersion.current().isJava8Compatible()) {
341346
throw new Exception("Java 8 is required to build fdb-record-layer")
342347
}
343348

349+
// fdb-environment.properties is the old way we configured the library path and cluster file, it does not scale well
350+
// to multiple cluster files, so is being replaced with a yaml file.
344351
def fdbEnvironmentFile = new File("${rootProject.projectDir}/fdb-environment.properties")
345352
if (fdbEnvironmentFile.exists()) {
346353
fdbEnvironmentFile.eachLine { line ->
@@ -356,3 +363,15 @@ if (!ext.fdbEnvironment.isEmpty()) {
356363
}
357364
}
358365
}
366+
367+
def fdbEnvironmentYamlFile = new File("${rootProject.projectDir}/fdb-environment.yaml")
368+
if (fdbEnvironmentYamlFile.exists()) {
369+
def libraryPath = new Yaml().loadAll(fdbEnvironmentYamlFile.newInputStream()).first().libraryPath
370+
def libraryPathVariable = Os.isFamily(Os.FAMILY_MAC) ? "DYLD_LIBRARY_PATH" : "LD_LIBRARY_PATH"
371+
allprojects {
372+
tasks.withType(Test) { task ->
373+
task.environment([(libraryPathVariable): libraryPath])
374+
task.environment(FDB_ENVIRONMENT_YAML: fdbEnvironmentYamlFile.absolutePath)
375+
}
376+
}
377+
}

docker-local/start.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ FDB_CLUSTER_FILE=${FDB_CLUSTER_FILE}
9595
${LIBRARY_PATH}=${RUNDIR}
9696
EOF
9797

98+
cat >${ROOTDIR}/fdb-environment.yaml <<EOF
99+
# docker-local
100+
clusterFiles:
101+
- ${FDB_CLUSTER_FILE}
102+
libraryPath: ${RUNDIR}
103+
EOF
104+
98105
cat ${ROOTDIR}/fdb-environment.properties
99106

100107
echo "Docker-based FDB cluster is now up."

docs/sphinx/source/Building.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,24 @@ If you enable the local repo in whatever uses the Record Layer, the following wi
6363
./gradlew publishToMavenLocal -PpublishBuild=true
6464
```
6565

66-
## Configuring tests for a non-standard FDB cluster file location
66+
## Configuring tests for a non-standard FDB cluster file location, or to run against multiple clusters
67+
68+
If a file `fdb-environment.yaml` exists in the root of the working directory, it contains the configuration for the C API library
69+
and a list of cluster files. Most tests will chose randomly from the provided cluster files when testing.
70+
71+
Here is an example file:
72+
``` yaml
73+
libraryPath: /Users/scott/fdb/bin/fdb-server-7.3.42-macos_arm64/lib
74+
clusterFiles:
75+
- /Users/scott/fdb/data/fdb-one.cluster
76+
- /Users/scott/fdb/data/fdb-two.cluster
77+
```
78+
79+
80+
81+
### deprecated properties file
82+
83+
[ this is being replaced by the yaml file described above, to better support multiple cluster files ]
6784
6885
If a file `fdb-environment.properties` exists in the root of the working directory, it contains environment variables that specify where to find
6986
the local FDB. These settings will apply when running inside IntelliJ as well as from a command line and so are easier to manage than a shell script.

fdb-extensions/fdb-extensions.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ dependencies {
3232

3333
testImplementation project(':fdb-test-utils')
3434
testImplementation(libs.bundles.test.impl)
35+
testImplementation(libs.snakeyaml)
3536
testRuntimeOnly(libs.bundles.test.runtime)
3637
testCompileOnly(libs.bundles.test.compileOnly)
3738
testAnnotationProcessor(libs.autoService)
3839

3940
testFixturesImplementation(libs.bundles.test.impl)
41+
testFixturesImplementation(libs.snakeyaml)
4042
testFixturesCompileOnly(libs.bundles.test.compileOnly)
4143
testFixturesImplementation(libs.slf4j.api)
4244
testFixturesAnnotationProcessor(libs.autoService)

fdb-record-layer-core/fdb-record-layer-core.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ dependencies {
4444
testImplementation(libs.junit.platform)
4545
testImplementation(libs.protobuf.util)
4646
testCompileOnly(libs.spotbugs.annotations)
47+
testImplementation(libs.snakeyaml)
4748

4849
testAnnotationProcessor(libs.autoService)
4950
}

fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/BlockingInAsyncDetectionTest.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.apple.foundationdb.record.RecordCoreException;
2525
import com.apple.foundationdb.record.TestHelpers;
2626
import com.apple.foundationdb.record.test.FDBDatabaseExtension;
27+
import com.apple.foundationdb.test.FDBTestEnvironment;
2728
import com.apple.test.Tags;
2829
import org.junit.jupiter.api.Tag;
2930
import org.junit.jupiter.api.Test;
@@ -57,7 +58,7 @@ void testBlockingInAsyncException() {
5758
// Make sure that we aren't holding on to previously created databases
5859
factory.clear();
5960

60-
FDBDatabase database = factory.getDatabase();
61+
FDBDatabase database = factory.getDatabase(FDBTestEnvironment.randomClusterFile());
6162
assertEquals(BlockingInAsyncDetection.IGNORE_COMPLETE_EXCEPTION_BLOCKING, database.getBlockingInAsyncDetection());
6263
assertThrows(BlockingInAsyncException.class, () -> callAsyncBlocking(database));
6364
}
@@ -68,7 +69,7 @@ void testBlockingInAsyncWarning() {
6869
factory.setBlockingInAsyncDetection(BlockingInAsyncDetection.IGNORE_COMPLETE_WARN_BLOCKING);
6970
factory.clear();
7071

71-
FDBDatabase database = factory.getDatabase();
72+
FDBDatabase database = factory.getDatabase(FDBTestEnvironment.randomClusterFile());
7273
TestHelpers.assertLogs(FDBDatabase.class, FDBDatabase.BLOCKING_IN_ASYNC_CONTEXT_MESSAGE,
7374
() -> {
7475
callAsyncBlocking(database, true);
@@ -82,7 +83,7 @@ void testCompletedBlockingInAsyncWarning() {
8283
factory.setBlockingInAsyncDetection(BlockingInAsyncDetection.WARN_COMPLETE_EXCEPTION_BLOCKING);
8384
factory.clear();
8485

85-
FDBDatabase database = factory.getDatabase();
86+
FDBDatabase database = factory.getDatabase(FDBTestEnvironment.randomClusterFile());
8687
TestHelpers.assertLogs(FDBDatabase.class, FDBDatabase.BLOCKING_IN_ASYNC_CONTEXT_MESSAGE,
8788
() -> database.asyncToSync(new FDBStoreTimer(), FDBStoreTimer.Waits.WAIT_ERROR_CHECK,
8889
CompletableFuture.supplyAsync(() ->
@@ -95,7 +96,7 @@ void testBlockingCreatingAsyncDetection() {
9596
factory.setBlockingInAsyncDetection(BlockingInAsyncDetection.WARN_COMPLETE_EXCEPTION_BLOCKING);
9697
factory.clear();
9798

98-
FDBDatabase database = factory.getDatabase();
99+
FDBDatabase database = factory.getDatabase(FDBTestEnvironment.randomClusterFile());
99100
TestHelpers.assertLogs(FDBDatabase.class, FDBDatabase.BLOCKING_RETURNING_ASYNC_MESSAGE,
100101
() -> returnAnAsync(database, MoreAsyncUtil.delayedFuture(200L, TimeUnit.MILLISECONDS, database.getScheduledExecutor())));
101102
}
@@ -106,7 +107,7 @@ void testCompletedBlockingCreatingAsyncDetection() {
106107
factory.setBlockingInAsyncDetection(BlockingInAsyncDetection.WARN_COMPLETE_EXCEPTION_BLOCKING);
107108
factory.clear();
108109

109-
FDBDatabase database = factory.getDatabase();
110+
FDBDatabase database = factory.getDatabase(FDBTestEnvironment.randomClusterFile());
110111
TestHelpers.assertDidNotLog(FDBDatabase.class, FDBDatabase.BLOCKING_RETURNING_ASYNC_MESSAGE,
111112
() -> returnAnAsync(database, CompletableFuture.completedFuture(10L)));
112113
}

fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/FDBDatabaseTest.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.apple.foundationdb.record.test.TestKeySpace;
3737
import com.apple.foundationdb.record.test.TestKeySpacePathManagerExtension;
3838
import com.apple.foundationdb.subspace.Subspace;
39+
import com.apple.foundationdb.test.FDBTestEnvironment;
3940
import com.apple.foundationdb.tuple.Tuple;
4041
import com.apple.test.BooleanSource;
4142
import com.apple.test.Tags;
@@ -54,6 +55,7 @@
5455

5556
import javax.annotation.Nonnull;
5657
import java.io.IOException;
58+
import java.util.UUID;
5759
import java.util.concurrent.CompletableFuture;
5860
import java.util.concurrent.ExecutionException;
5961
import java.util.concurrent.TimeUnit;
@@ -66,6 +68,7 @@
6668
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
6769
import static org.hamcrest.Matchers.lessThan;
6870
import static org.hamcrest.Matchers.lessThanOrEqualTo;
71+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
6972
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
7073
import static org.junit.jupiter.api.Assertions.assertEquals;
7174
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -240,7 +243,7 @@ void testJoinNowOnNonCompletedFuture(BlockingInAsyncDetection behavior) {
240243
if (behavior.throwExceptionOnBlocking()) {
241244
assertThrows(BlockingInAsyncException.class, () -> database.joinNow(new CompletableFuture<>()));
242245
} else {
243-
FDBDatabase database2 = factory.getDatabase();
246+
FDBDatabase database2 = factory.getDatabase(database.getClusterFile());
244247
TestHelpers.assertLogs(FDBDatabase.class, FDBDatabase.BLOCKING_FOR_FUTURE_MESSAGE, () -> {
245248
long val = database2.joinNow(MoreAsyncUtil.delayedFuture(100, TimeUnit.MILLISECONDS, database2.getScheduledExecutor())
246249
.thenApply(vignore -> 1066L));
@@ -494,4 +497,31 @@ void cannotChangeAPIVersionAfterInit() {
494497
assertEquals(initApiVersion, database.getAPIVersion());
495498
}
496499
}
500+
501+
@Test
502+
void canAccessMultipleClusters() {
503+
FDBTestEnvironment.assumeClusterCount(2);
504+
final FDBDatabase database0 = dbExtension.getDatabase(0);
505+
final FDBDatabase database1 = dbExtension.getDatabase(1);
506+
final byte[] key = Tuple.from(UUID.randomUUID()).pack();
507+
final byte[] value0 = Tuple.from("cluster0").pack();
508+
final byte[] value1 = Tuple.from("cluster1").pack();
509+
try (FDBRecordContext context0 = database0.openContext()) {
510+
context0.ensureActive().set(key, value0);
511+
context0.commit();
512+
}
513+
try (FDBRecordContext context1 = database1.openContext()) {
514+
assertNull(context1.ensureActive().get(key).join());
515+
context1.ensureActive().set(key, value1);
516+
context1.commit();
517+
}
518+
try (FDBRecordContext context0 = database0.openContext()) {
519+
assertArrayEquals(value0, context0.ensureActive().get(key).join());
520+
context0.commit();
521+
}
522+
try (FDBRecordContext context1 = database1.openContext()) {
523+
assertArrayEquals(value1, context1.ensureActive().get(key).join());
524+
context1.commit();
525+
}
526+
}
497527
}

fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/provider/foundationdb/FDBRecordContextTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.apple.foundationdb.record.test.TestKeySpacePathManagerExtension;
3535
import com.apple.foundationdb.record.util.pair.Pair;
3636
import com.apple.foundationdb.subspace.Subspace;
37+
import com.apple.foundationdb.test.FDBTestEnvironment;
3738
import com.apple.foundationdb.tuple.ByteArrayUtil;
3839
import com.apple.foundationdb.tuple.ByteArrayUtil2;
3940
import com.apple.foundationdb.tuple.Tuple;
@@ -433,7 +434,7 @@ public void logWithoutSettingId() {
433434
FDBDatabaseFactory factory = fdb.getFactory();
434435
factory.setTransactionIsTracedSupplier(() -> false);
435436
factory.clear();
436-
fdb = factory.getDatabase();
437+
fdb = factory.getDatabase(FDBTestEnvironment.randomClusterFile());
437438
}
438439
try (FDBRecordContext context = fdb.openContext()) {
439440
RecordCoreException err = assertThrows(RecordCoreException.class, context::logTransaction);
@@ -665,7 +666,8 @@ public void contextExecutor() {
665666
factory.setContextExecutor(exec -> new ThreadIdRestoringExecutor(exec, myThreadId));
666667
factory.clear();
667668

668-
FDBDatabase database = factory.getDatabase();
669+
670+
FDBDatabase database = factory.getDatabase(FDBTestEnvironment.randomClusterFile());
669671
try (FDBRecordContext context = database.openContext()) {
670672
context.ensureActive().get(new byte[] { 0 }).thenAccept( value -> {
671673
assertEquals(myThreadId, ThreadId.get());

0 commit comments

Comments
 (0)