Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
07438c9
2043 add first resilience tests using testcontainers and toxyproxy, r…
robfrank Mar 5, 2025
be86ad3
refactor: clean up DatabaseWrapper formatting and improve logger init…
robfrank May 3, 2025
17cc9f9
refactor: optimize import statements across multiple classes
robfrank May 4, 2025
1fa91c7
test: add unit tests for ReplicationLogFile functionality
robfrank May 5, 2025
ce11a9e
refactor: rename resilience test classes and update package structure
robfrank May 6, 2025
4e35d91
fix compilation error
robfrank May 10, 2025
a5ec801
test: add Java resilience tests to CI pipeline
robfrank May 11, 2025
5369a28
test: update resilience tests to run with integration profile
robfrank May 11, 2025
ecd5935
feat: add initial configuration and setup files for project
robfrank May 11, 2025
9521c10
feat: create directories for HA container setup
robfrank May 11, 2025
2fab0d2
feat: ensure created directories are writable for HA container setup
robfrank May 11, 2025
91fd7c1
feat: update container directory permissions to be non-writable for s…
robfrank May 11, 2025
39460e3
feat: modify container setup to set user ID and group ID for security
robfrank May 11, 2025
cc1bcdd
feat: ensure user ID and group ID are set for container creation
robfrank May 11, 2025
2dd918f
feat: set user ID and group ID for container creation using a consumer
robfrank May 11, 2025
7b6af7f
feat: update Dockerfile to use alpine image and modify user creation …
robfrank May 12, 2025
1edd797
feat: add method to create container directories in test template
robfrank May 12, 2025
a8b2b5a
refactor: remove commented-out code and clean up whitespace in utilit…
robfrank May 12, 2025
b2ef671
feat: add checks for user identity and permissions in CI pipeline
robfrank May 12, 2025
7d38c48
feat: add additional checks for database directory in CI pipeline
robfrank May 13, 2025
8b3658a
feat: update resilience tests command in CI configuration
robfrank May 13, 2025
46715f2
feat: add conditional execution for checks in CI configuration
robfrank May 13, 2025
dd6bfe4
feat: update file system binding to use copy to container method in C…
robfrank May 13, 2025
07547f1
feat: add cleanup commands for container databases and logs on stop
robfrank May 13, 2025
cb1ef30
feat: simplify resilience tests command in CI configuration
robfrank May 13, 2025
df83ee7
feat: exclude resilience tests from integration tests in CI configura…
robfrank May 13, 2025
462d435
wip
robfrank May 18, 2025
4347286
feat: remove database comparison after each test and improve cleanup …
robfrank May 30, 2025
9f87614
wip
robfrank Jun 5, 2025
2446a3f
wip
robfrank Jun 8, 2025
2c8759c
turn off FINE logging
robfrank Jun 13, 2025
b552a99
feat: comment out database comparison and cleanup logic in tests
robfrank Jun 13, 2025
707cc9f
fix missing import
robfrank Jun 15, 2025
16f871d
pre calculate totals
robfrank Jun 17, 2025
592cd69
feat: update photo count in load test and enhance database edge creation
robfrank Jun 23, 2025
2193e4c
feat: enhance load tests by adding friendship count assertion and imp…
robfrank Jun 24, 2025
19a7849
feat: refactor load test logic and improve friendship creation methods
robfrank Jun 24, 2025
9526d1c
rebased on main, use of perf-tests support
robfrank Oct 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion .github/workflows/mvn-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,50 +67,50 @@
key: maven-repo-${{ github.run_id }}-${{ github.run_attempt }}

unit-tests:
runs-on: ubuntu-latest
needs: build-and-package
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- name: Set up JDK 21
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
distribution: "temurin"
java-version: 21
cache: "maven"

- name: Restore Maven artifacts
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ~/.m2/repository
key: maven-repo-${{ github.run_id }}-${{ github.run_attempt }}

- name: Run Unit Tests with Coverage
# verify because it runs the tests and generates the coverage report, ITs are skipped
run: ./mvnw verify -Pcoverage --batch-mode --errors --fail-never --show-version -pl !e2e,!e2e-perf
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Unit Tests Reporter
uses: dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3 # v2.1.1
if: success() || failure()
with:
name: Unit Tests Report
path: "**/surefire-reports/TEST*.xml"
list-suites: "failed"
list-tests: "failed"
reporter: java-junit

- name: Upload unit test coverage reports
if: success() || failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: unit-coverage-reports
path: |
**/jacoco*.xml
retention-days: 1

integration-tests:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
runs-on: ubuntu-latest
needs: build-and-package
steps:
Expand All @@ -130,7 +130,7 @@
key: maven-repo-${{ github.run_id }}-${{ github.run_attempt }}

- name: Run Integration Tests with Coverage
run: ./mvnw verify -DskipTests -Pintegration -Pcoverage --batch-mode --errors --fail-never --show-version -pl !e2e,!e2e-perf
run: ./mvnw verify -DskipTests -Pintegration -Pcoverage --batch-mode --errors --fail-never --show-version -pl !e2e,!e2e-perf,!resilience
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Expand Down Expand Up @@ -241,6 +241,50 @@
list-tests: "failed"
reporter: java-junit

java-resilience-tests:
runs-on: ubuntu-latest
needs: build-and-package
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: "temurin"
java-version: 21
cache: "maven"

- name: Restore Maven artifacts
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: ~/.m2/repository
key: maven-repo-${{ github.run_id }}-${{ github.run_attempt }}

- name: Restore Docker image
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: /tmp/arcadedb-image.tar
key: docker-image-${{ github.run_id }}-${{ github.run_attempt }}

- name: Load Docker image
run: docker load < /tmp/arcadedb-image.tar

- name: Resilience Tests
run: ./mvnw verify -Pintegration -pl resilience
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ARCADEDB_DOCKER_IMAGE: ${{ needs.build-and-package.outputs.image-tag }}

- name: Resilinece Tests Reporter
uses: dorny/test-reporter@6e6a65b7a0bd2c9197df7d0ae36ac5cee784230c # v2.0.0
if: success() || failure()
with:
name: Java Resilience Tests Report
path: "resilience/target/failsafe-reports/TEST*.xml"
list-suites: "failed"
list-tests: "failed"
reporter: java-junit

js-e2e-tests:
runs-on: ubuntu-latest
needs: build-and-package
Expand Down
14 changes: 10 additions & 4 deletions e2e/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
</build>

<dependencies>
<dependency>
<groupId>com.arcadedb</groupId>
<artifactId>arcadedb-network</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
Expand All @@ -79,14 +85,14 @@
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<artifactId>toxiproxy</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.arcadedb</groupId>
<artifactId>arcadedb-network</artifactId>
<version>${project.parent.version}</version>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
4 changes: 2 additions & 2 deletions engine/src/main/java/com/arcadedb/database/Database.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
import com.arcadedb.schema.Schema;
import com.arcadedb.utility.ExcludeFromJacocoGeneratedReport;

import java.util.*;
import java.util.concurrent.*;
import java.util.Map;
import java.util.concurrent.Callable;

@ExcludeFromJacocoGeneratedReport
public interface Database extends BasicDatabase {
Expand Down
21 changes: 15 additions & 6 deletions engine/src/main/java/com/arcadedb/database/TransactionContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,21 @@
import com.arcadedb.log.LogManager;
import com.arcadedb.schema.LocalSchema;

import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import java.util.stream.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.stream.Collectors;

/**
* Manage the transaction context. When the transaction begins, the modifiedPages map is initialized. This allows to always delegate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,18 @@
import com.arcadedb.schema.EdgeType;
import com.conversantmedia.util.concurrent.PushPullBlockingQueue;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;

public class DatabaseAsyncExecutorImpl implements DatabaseAsyncExecutor {
private final DatabaseInternal database;
Expand All @@ -52,9 +60,9 @@ public class DatabaseAsyncExecutorImpl implements DatabaseAsyncExecutor {
private int parallelLevel = 1;
private int commitEvery;
private int backPressurePercentage = 0;
private boolean transactionUseWAL = true;
private WALFile.FlushType transactionSync = WALFile.FlushType.NO;
private long checkForStalledQueuesMaxDelay = 5_000;
private boolean transactionUseWAL = true;
private WALFile.FlushType transactionSync = WALFile.FlushType.NO;
private long checkForStalledQueuesMaxDelay = 5_000;
private final AtomicLong transactionCounter = new AtomicLong();
private final AtomicLong commandRoundRobinIndex = new AtomicLong();

Expand Down
11 changes: 0 additions & 11 deletions engine/src/main/java/com/arcadedb/utility/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -181,17 +181,6 @@ public static void deleteRecursively(final File rootFile) {
break;

} catch (final IOException e) {
// if (System.getProperty("os.name").toLowerCase().contains("win")) {
// // AVOID LOCKING UNDER WINDOWS
// try {
// LogManager.instance()
// .log(rootFile, Level.WARNING, "Cannot delete directory '%s'. Forcing GC cleanup and try again (attempt=%d)", e, rootFile, attempt);
// System.gc();
// Thread.sleep(1000);
// } catch (Exception ex) {
// // IGNORE IT
// }
// } else
LogManager.instance().log(rootFile, Level.WARNING, "Cannot delete directory '%s'", e, rootFile);
}
}
Expand Down
29 changes: 24 additions & 5 deletions network/src/main/java/com/arcadedb/network/HostUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,20 @@
*/

/**
* @author Luca Garulli ([email protected])
* Utility class for parsing host addresses.
*/
public class HostUtil {
public static final String CLIENT_DEFAULT_PORT = "2480";
public static final String HA_DEFAULT_PORT = "2424";

/**
* Parses the host address and returns the host and port. If the port is not specified, it returns the default port.
*
* @param host The host address to parse.
* @param defaultPort The default port to use if no port is specified in the host address.
*
* @return An array containing the host and port.
*/
public static String[] parseHostAddress(String host, final String defaultPort) {
if (host == null)
throw new IllegalArgumentException("Host null");
Expand All @@ -33,14 +41,25 @@ public static String[] parseHostAddress(String host, final String defaultPort) {
if (host.isEmpty())
throw new IllegalArgumentException("Host is empty");

String alias = "";
if (host.startsWith("{")) {
alias = host.substring(host.indexOf("{") + 1, host.indexOf("}"));
// REMOVE ALIAS
host = host.substring(host.indexOf("}") + 1);
}

final String[] parts = host.split(":");
if (parts.length == 1 || parts.length == 8)
if (parts.length == 1 || parts.length == 8) {
// ( IPV4 OR IPV6 ) NO PORT
return new String[] { host, defaultPort };
else if (parts.length == 2 || parts.length == 9) {
if (alias.isEmpty())
alias = host;
return new String[] { host, defaultPort, alias };
} else if (parts.length == 2 || parts.length == 9) {
// ( IPV4 OR IPV6 ) + PORT
final int pos = host.lastIndexOf(":");
return new String[] { host.substring(0, pos), host.substring(pos + 1) };
if (alias.isEmpty())
alias = host.substring(0, pos);
return new String[] { host.substring(0, pos), host.substring(pos + 1), alias };
}

throw new IllegalArgumentException("Invalid host " + host);
Expand Down
4 changes: 2 additions & 2 deletions network/src/main/java/com/arcadedb/remote/RemoteDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ public ResultSet command(final String language, final String command, final Cont
checkDatabaseIsOpen();
stats.commands.incrementAndGet();

return (ResultSet) databaseCommand("command", language, command, params, true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you setting false = not require a leader? This means the operation will go to any server, but if it's an update (query is idempotent) will bounce to the leader in 2 passes

return (ResultSet) databaseCommand("command", language, command, params, false,
(connection, response) -> createResultSet(response));
}

Expand All @@ -446,7 +446,7 @@ public ResultSet command(final String language, final String command, final Obje
stats.commands.incrementAndGet();

final Map<String, Object> params = mapArgs(args);
return (ResultSet) databaseCommand("command", language, command, params, true,
return (ResultSet) databaseCommand("command", language, command, params, false,
(connection, response) -> createResultSet(response));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,9 @@ Object httpCommand(final String method,
Pair<String, Integer> connectToServer =
leaderIsPreferable && leaderServer != null ? leaderServer : new Pair<>(currentServer, currentPort);

String server = null;

String server = connectToServer.getFirst() + ":" + connectToServer.getSecond();
String url = protocol + "://" + server + "/api/v" + apiVersion + "/" + operation;
for (int retry = 0; retry < maxRetry && connectToServer != null; ++retry) {
server = connectToServer.getFirst() + ":" + connectToServer.getSecond();
String url = protocol + "://" + server + "/api/v" + apiVersion + "/" + operation;

if (extendedURL != null)
url += "/" + extendedURL;
Expand Down Expand Up @@ -385,9 +383,9 @@ void requestClusterConfiguration() {
final String sHost = serverParts[0];
final int sPort = Integer.parseInt(serverParts[1]);

replicaServerList.add(new Pair(sHost, sPort));
replicaServerList.add(new Pair<>(sHost, sPort));
} catch (Exception e) {
LogManager.instance().log(this, Level.SEVERE, "Invalid replica server address '%s'", null, serverEntry);
LogManager.instance().log(this, Level.SEVERE, "Invalid replica server address '%s'", e, serverEntry);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public RemoteServer(final String server, final int port, final String userName,
}

public void create(final String databaseName) {
serverCommand("POST", "create database " + databaseName, true, true, null);
serverCommand("POST", "create database " + databaseName, false, true, null);
}

public List<String> databases() {
Expand Down
21 changes: 17 additions & 4 deletions network/src/test/java/com/arcadedb/HostUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,45 @@ public class HostUtilTest {
@Test
public void testIPv4() {
final String[] parts = HostUtil.parseHostAddress("10.33.5.22", HostUtil.CLIENT_DEFAULT_PORT);
assertThat(parts.length).isEqualTo(2);
assertThat(parts.length).isEqualTo(3);
assertThat(parts[0]).isEqualTo("10.33.5.22");
assertThat(parts[1]).isEqualTo(HostUtil.CLIENT_DEFAULT_PORT);
assertThat(parts[2]).isEqualTo("10.33.5.22");
}

@Test
public void testIPv4WithAliasAndPort() {
final String[] parts = HostUtil.parseHostAddress("{alias}10.33.5.22:1234", HostUtil.CLIENT_DEFAULT_PORT);
assertThat(parts.length).isEqualTo(3);
assertThat(parts[0]).isEqualTo("10.33.5.22");
assertThat(parts[1]).isEqualTo("1234");
assertThat(parts[2]).isEqualTo("alias");
}

@Test
public void testIPv4WithPort() {
final String[] parts = HostUtil.parseHostAddress("10.33.5.22:33", HostUtil.CLIENT_DEFAULT_PORT);
assertThat(parts.length).isEqualTo(2);
assertThat(parts.length).isEqualTo(3);
assertThat(parts[0]).isEqualTo("10.33.5.22");
assertThat(parts[1]).isEqualTo("33");
assertThat(parts[2]).isEqualTo("10.33.5.22");
}

@Test
public void testIPv6() {
final String[] parts = HostUtil.parseHostAddress("fe80:0:0:0:250:56ff:fe9a:6990", HostUtil.CLIENT_DEFAULT_PORT);
assertThat(parts.length).isEqualTo(2);
assertThat(parts.length).isEqualTo(3);
assertThat(parts[0]).isEqualTo("fe80:0:0:0:250:56ff:fe9a:6990");
assertThat(parts[1]).isEqualTo(HostUtil.CLIENT_DEFAULT_PORT);
assertThat(parts[2]).isEqualTo("fe80:0:0:0:250:56ff:fe9a:6990");
}

@Test
public void testIPv6WithPort() {
final String[] parts = HostUtil.parseHostAddress("fe80:0:0:0:250:56ff:fe9a:6990:22", HostUtil.CLIENT_DEFAULT_PORT);
assertThat(parts.length).isEqualTo(2);
assertThat(parts.length).isEqualTo(3);
assertThat(parts[0]).isEqualTo("fe80:0:0:0:250:56ff:fe9a:6990");
assertThat(parts[1]).isEqualTo("22");
assertThat(parts[2]).isEqualTo("fe80:0:0:0:250:56ff:fe9a:6990");
}
}
3 changes: 2 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
<module>package</module>
<module>e2e</module>
<module>e2e-perf</module>
<module>resilience</module>
</modules>

<build>
Expand Down Expand Up @@ -292,7 +293,7 @@
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
<excludeArtifacts>
arcadedb-coverage,arcadedb-e2e,arcadedb-e2e-perf
arcadedb-coverage,arcadedb-e2e,arcadedb-e2e-perf,arcadedb-resilience-tests
</excludeArtifacts>
</configuration>
</plugin>
Expand Down
Loading
Loading