Skip to content

Commit a12d9b1

Browse files
authored
GH-1502 Add a spring-boot wrapper to allow the server and workbench to be run from a single place (#5570)
2 parents 3a22f57 + c5b7e27 commit a12d9b1

File tree

46 files changed

+3345
-53
lines changed

Some content is hidden

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

46 files changed

+3345
-53
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
**/.classpath
66
.settings
77
**/.settings
8-
bin
9-
**/bin
108
**/.factorypath
119

1210
# Eclipse Plug-In Settings
@@ -56,3 +54,4 @@ e2e/test-results
5654
/tools/server/.lwjgl/
5755
.m2_repo/
5856
.serena/
57+
.vscode

AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ Why this is mandatory
300300
* `mvn -o -Dmaven.repo.local=.m2_repo -Pquick install | tail -200`
301301
3. **Format (Java, imports, XML)**
302302
* `mvn -o -Dmaven.repo.local=.m2_repo -q -T 2C formatter:format impsort:sort xml-format:xml-format`
303+
* Ensure every touched Java file has the correct agent signature comment (`// Some portions generated by Codex` for Codex, `// Some portions generated by Co-Pilot` for GitHub Co-Pilot) inserted immediately below the header before formatting.
304+
* Before invoking the formatter, `cd scripts && ./checkCopyrightPresent.sh` (or use `pushd/popd`) to ensure every new or edited source file still carries the required header; fix any findings before formatting.
303305
4. **Targeted tests (tight loops)**
304306
* Module: `mvn -o -Dmaven.repo.local=.m2_repo -pl <module> verify | tail -500`
305307
* Class: `mvn -o -Dmaven.repo.local=.m2_repo -pl <module> -Dtest=ClassName verify | tail -500`
@@ -509,6 +511,10 @@ Hint: get the current year with `date +%Y`.
509511
510512
Do **not** modify existing headers’ years.
511513
514+
Right below the header block, insert an agent signature comment: Codex agents must add `// Some portions generated by Codex`, and GitHub Co-Pilot agents must add `// Some portions generated by Co-Pilot`. Align the wording with whatever agent name you are currently operating under.
515+
516+
Immediately after creating any new Java source file, add the signature comment (per rule above) and run `cd scripts && ./checkCopyrightPresent.sh` (or an equivalent pushd/popd invocation) so you catch missing copyright/SPDX lines before moving on.
517+
512518
---
513519
514520
## Pre‑Commit Checklist

core/common/iterator/src/main/java/org/eclipse/rdf4j/common/iteration/DualUnionIteration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ public final void close() {
220220
if (!closed) {
221221
closed = true;
222222
nextElement = null;
223+
var iteration1 = this.iteration1;
224+
var iteration2 = this.iteration2;
223225
try {
224226
if (iteration1 != null) {
225227
iteration1.close();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Eclipse RDF4J contributors.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Distribution License v1.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/org/documents/edl-v10.php.
8+
*
9+
* SPDX-License-Identifier: BSD-3-Clause
10+
*******************************************************************************/
11+
package org.eclipse.rdf4j.common.transaction;
12+
13+
import java.util.Optional;
14+
15+
/**
16+
* {@link TransactionSettingFactory} for {@link IsolationLevel}s exposed by the RDF4J API.
17+
*/
18+
public class IsolationLevelFactory implements TransactionSettingFactory {
19+
20+
@Override
21+
public String getName() {
22+
return IsolationLevel.NAME;
23+
}
24+
25+
@Override
26+
public Optional<TransactionSetting> getTransactionSetting(String value) {
27+
if (value == null || value.isBlank()) {
28+
return Optional.empty();
29+
}
30+
try {
31+
return Optional.of(IsolationLevels.valueOf(value.trim()));
32+
} catch (IllegalArgumentException e) {
33+
return Optional.empty();
34+
}
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.eclipse.rdf4j.common.transaction.IsolationLevelFactory

docker/build.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ if [ -z ${SKIP_BUILD+x} ]; then
2121

2222
#Clean, format and package
2323
echo "Building with Maven"
24-
mvn clean
2524
mvn -T 2C formatter:format impsort:sort && mvn xml-format:xml-format
26-
mvn install -DskipTests
25+
mvn install -Pquick
2726
mvn -Passembly package -DskipTests -Dmaven.javadoc.skip=true -Dformatter.skip=true -Dimpsort.skip=true -Dxml-format.skip=true -Djapicmp.skip -Denforcer.skip=true -Dbuildnumber.plugin.phase=none -Danimal.sniffer.skip=true
2827

2928
# find .zip file

e2e/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules/
22
/test-results/
33
/playwright-report/
44
/playwright/.cache/
5+
/.npm-cache/

e2e/README.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
# End-to-end tests
22

3-
This directory contains end-to-end tests for the project. These tests use docker to run the RDF4J server and workbench.
3+
This directory contains end-to-end tests for the project. The suite now boots the RDF4J Server and Workbench using a Spring Boot wrapper with an embedded Tomcat instance, so Docker is no longer required.
44

5-
The tests are written using Microsoft Playwright and interact with the server and workbench using the browser.
5+
The tests are written using Microsoft Playwright and interact with the server and workbench in a real browser.
66

77
## Running the tests
88

99
Requirements:
10-
- docker
1110
- java
1211
- maven
1312
- npm
1413
- npx
1514

16-
The tests can be run using the `run.sh` script. This script will build the project, start the server and workbench and run the tests.
15+
The tests can be run using the `run.sh` script. The script builds the Spring Boot runner, launches it in the background, waits until the HTTP endpoints are reachable, and then executes the Playwright test suite.
1716

1817
To run the tests interactively use `npx playwright test --ui`
19-
20-
The RDF4J server and workbench can be started independently using the `run.sh` script in the `docker` directory.

e2e/run.sh

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env bash
22
#
3-
# Copyright (c) 2023 Eclipse RDF4J contributors.
3+
# Copyright (c) 2025 Eclipse RDF4J contributors.
44
#
55
# All rights reserved. This program and the accompanying materials
66
# are made available under the terms of the Eclipse Distribution License v1.0
@@ -12,45 +12,87 @@
1212

1313
set -e
1414

15+
SERVER_PID=""
16+
17+
cleanup() {
18+
if [ -z "${SERVER_PID:-}" ]; then
19+
return
20+
fi
21+
22+
# If the process is already gone, nothing to do
23+
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
24+
return
25+
fi
26+
27+
echo "Sending SIGINT to server-boot module (pid=$SERVER_PID)"
28+
kill -s INT "$SERVER_PID" 2>/dev/null || true
29+
30+
# Wait for graceful shutdown after SIGINT
31+
for i in 1 2 3 4 5 6 7 8 9 10; do
32+
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
33+
echo "server-boot module stopped gracefully after SIGINT"
34+
wait "$SERVER_PID" 2>/dev/null || true
35+
return
36+
fi
37+
kill -s INT "$SERVER_PID" 2>/dev/null || true
38+
sleep 0.5
39+
done
40+
41+
# Still alive: send a more aggressive TERM
42+
echo "Sending SIGTERM to server-boot module (pid=$SERVER_PID)"
43+
kill "$SERVER_PID" 2>/dev/null || true
44+
45+
# Wait for graceful shutdown after SIGTERM
46+
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
47+
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
48+
echo "server-boot module stopped after SIGTERM"
49+
wait "$SERVER_PID" 2>/dev/null || true
50+
return
51+
fi
52+
sleep 0.5
53+
done
54+
55+
# Still alive after: kill definitively
56+
echo "Sending SIGKILL to server-boot module (pid=$SERVER_PID)"
57+
kill -9 "$SERVER_PID" 2>/dev/null || true
58+
wait "$SERVER_PID" 2>/dev/null || true
59+
}
60+
61+
trap cleanup EXIT
62+
1563
npm install
1664

17-
for APP_SERVER in tomcat jetty; do
18-
export APP_SERVER
65+
cd ..
1966

20-
cd ..
21-
cd docker
22-
./run.sh
23-
./waitForDocker.sh
24-
cd ..
25-
cd e2e
67+
mvn -q install -Pquick
2668

27-
sleep 10
69+
mvn -pl tools/server-boot spring-boot:run &
70+
SERVER_PID=$!
71+
# server-boot module will be stopped automatically on script exit (see cleanup trap above).
2872

29-
if [ ! -d 'node_modules' ]; then
30-
echo "npm ci"
31-
npm ci
32-
fi
73+
cd e2e
3374

34-
docker ps
75+
sleep 10
3576

36-
npx playwright install --with-deps # install browsers
37-
npx playwright test
77+
if [ ! -d 'node_modules' ]; then
78+
echo "npm ci"
79+
npm ci
80+
fi
3881

39-
status_npx=$?
82+
npx playwright install --with-deps # install browsers
83+
npx playwright test
4084

41-
cd ..
42-
cd docker
43-
./shutdown.sh
85+
status_npx=$?
4486

45-
# test for error code
46-
if [ $status_npx -ne 0 ] ; then
47-
echo "Error in E2E test for $APP_SERVER"
48-
exit $status_npx
49-
fi
87+
cd ..
5088

51-
echo "E2E test for $APP_SERVER OK"
89+
# test for error code
90+
if [ $status_npx -ne 0 ]; then
91+
echo "Error in E2E test"
92+
exit $status_npx
93+
fi
5294

53-
# don't redo the whole build process just for making another docker image
54-
export SKIP_BUILD="skip"
55-
done
95+
echo "E2E test OK"
5696

97+
# don't redo the whole build process just for making another docker image
98+
export SKIP_BUILD="skip"

e2e/tests/workbench.spec.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,33 @@ test('SPARQL update', async ({page}) => {
8383

8484
});
8585

86+
87+
test('Add Turtle data to repository', async ({page}) => {
88+
await page.goto('http://localhost:8080/rdf4j-workbench/');
89+
page.on('dialog', dialog => {
90+
console.log(dialog.message());
91+
dialog.dismiss();
92+
});
93+
94+
await createRepo(page);
95+
96+
await page.getByText('Add').click();
97+
await page.waitForSelector('#text');
98+
99+
await page.locator('#source-text').check();
100+
await page.locator('#baseURI').fill('http://example.org/ns#');
101+
await page.locator('#Content-Type').selectOption('text/turtle');
102+
103+
const turtleData = '@prefix ex: <http://example.org/ns#> .\n\n' +
104+
'ex:alice a ex:Person ;\n' +
105+
' ex:name "Alice" .';
106+
107+
await page.locator('#text').fill(turtleData);
108+
109+
await page.getByRole('button', { name: 'Upload' }).click();
110+
111+
await page.getByText('Types').click();
112+
113+
let type = await page.getByText('ex:Person');
114+
await expect(type).toHaveText('ex:Person');
115+
});

0 commit comments

Comments
 (0)