Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Matrix based CI builds for JPro Platform #44

Merged
merged 8 commits into from
Oct 1, 2024
23 changes: 0 additions & 23 deletions .github/workflows/linux.yml

This file was deleted.

42 changes: 42 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: CI build

on: [push]

jobs:
builds:
name: '${{ matrix.os }} with Java ${{ matrix.jdk }}'
runs-on: ${{ matrix.os }}
strategy:
matrix:
jdk: [17, 21, 23]
os: [ubuntu-latest, windows-latest] #, macos-13]
fail-fast: false
max-parallel: 6
timeout-minutes: 30

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Java ${{ matrix.jdk }}
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: ${{ matrix.jdk }}

- name: Compile
run: |
./gradlew jar
./gradlew example:jar

- name: Test
run: |
if [[ "$RUNNER_OS" == "Linux" ]]; then
export DISPLAY=:99.0 && /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16;
fi
./gradlew -DciTest=true test
shell: bash

- name: Javadoc
run: |
./gradlew javadoc
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
#### Improvements
* Updated **JPro** to version `2024.3.3`.

#### Bugfixes
* Fixed the binding of the port in the local server implementation inside the `jpro-core` module to occur only when
necessary, rather than during server creation.

----------------------

### 0.4.1 (August 29, 2024)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# JPro Platform
![Build](https://github.com/jpro-one/jpro-platform/actions/workflows/linux.yml/badge.svg)
![Build](https://github.com/jpro-one/jpro-platform/actions/workflows/main.yml/badge.svg)
[![JPro supported](https://img.shields.io/badge/JPro-supported-brightgreen.svg)](https://www.jpro.one/)

The JPro Platform represents the foundation of cross-platform application development,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,22 +61,27 @@ public void runAsync() throws IOException {
} else {
commandRunner.addArgs("ls", "build.gradle");
}
Process process = commandRunner.runAsync("ls");
Process process = commandRunner.runAsync("async-ls");
assertThat(process.getClass()).isAssignableTo(Process.class);
}

@Test
public void runAsyncWithMockDirectoryThrowsException() {
if (PlatformUtils.isWindows()) {
commandRunner.addArgs("cmd", "/c", "dir", "/b", "build.gradle");
assertThatThrownBy(() -> commandRunner.runAsync("async-cmd-dir", mockFile))
.hasMessageContaining("Cannot run program \"cmd\"")
.hasMessageContaining("CreateProcess error=267, The directory name is invalid")
.hasRootCauseMessage("CreateProcess error=267, The directory name is invalid")
.hasCauseInstanceOf(IOException.class);
} else {
commandRunner.addArgs("ls", "build.gradle");
assertThatThrownBy(() -> commandRunner.runAsync("async-ls", mockFile))
.hasMessageContaining("Cannot run program \"ls\"")
.hasMessageContaining("error=2, No such file or directory")
.hasRootCauseMessage("error=2, No such file or directory")
.hasCauseInstanceOf(IOException.class);
}
assertThatThrownBy(() -> commandRunner.runAsync("ls", mockFile))
.hasMessageContaining("Cannot run program \"ls\"")
.hasMessageContaining("error=2, No such file or directory")
.hasRootCauseMessage("error=2, No such file or directory")
.hasCauseInstanceOf(IOException.class);
}

@Test
Expand All @@ -102,7 +107,7 @@ public void runAsyncWithDirectoryAndOutput() throws IOException, InterruptedExce
} else {
commandRunner.addArgs("mkdir", "runner");
}
Process process = commandRunner.runAsync("dir", tempDir.toFile());
Process process = commandRunner.runAsync("async-dir-list", tempDir.toFile());
int result = process.waitFor();
assertThat(result).isEqualTo(0); // Successful execution
assertThat(commandRunner.getLastResponse()).isEqualTo("");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -52,6 +53,8 @@ public final class HttpServerImpl implements HttpServer {
static final byte[] CRLF = "\r\n".getBytes();

private String uri;
private boolean isReusePortSupported;
private boolean isPortBound;

@Nullable
private final Stage stage;
Expand Down Expand Up @@ -116,11 +119,9 @@ public HttpServerImpl(@Nullable final Stage stage, @NotNull final HttpOptions op
thread = new Thread(this::run, "http-server-thread");
thread.setDaemon(true);

InetSocketAddress address = options.getHost() == null
? new InetSocketAddress(options.getPort()) // wildcard address
: new InetSocketAddress(options.getHost(), options.getPort());

serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);

final Set<SocketOption<?>> supportedOptions = serverSocketChannel.supportedOptions();
if (options.isReuseAddr()) {
if (supportedOptions.contains(StandardSocketOptions.SO_REUSEADDR)) {
Expand All @@ -132,26 +133,46 @@ public HttpServerImpl(@Nullable final Stage stage, @NotNull final HttpOptions op
if (options.isReusePort()) {
if (supportedOptions.contains(StandardSocketOptions.SO_REUSEPORT)) {
serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEPORT, options.isReusePort());
isReusePortSupported = true;
} else {
isReusePortSupported = false;
logger.warn("The 'SO_REUSEPORT' option is not supported on this platform.");
}
}
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(address, options.getAcceptLength());
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
}

private byte[] getResourceAsBytes(@NotNull final String name) throws IOException {
try (InputStream is = HttpServer.class.getResourceAsStream(name)) {
if (is != null) {
return is.readAllBytes();
// Read all bytes from the input stream
byte[] bytes = is.readAllBytes();
// Convert bytes to a string, normalize line endings, and convert back to bytes
String content = new String(bytes, StandardCharsets.UTF_8);
String normalizedContent = content.replace("\r\n", "\n")
.replace("\r", "\n");
return normalizedContent.getBytes(StandardCharsets.UTF_8);
}
}
return SPACE;
}

@Override
public void start() {
if (!isReusePortSupported && isPortBound) {
// Reuse port is not supported, so we cannot bind the port again
return;
} else {
try {
final InetSocketAddress address = options.getHost() == null
? new InetSocketAddress(options.getPort()) // wildcard address
: new InetSocketAddress(options.getHost(), options.getPort());
serverSocketChannel.bind(address, options.getAcceptLength());
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
isPortBound = true;
} catch (IOException ex) {
throw new HttpServerException(ex);
}
}
thread.start();
connectionEventLoops.forEach(ConnectionEventLoop::start);
logger.info("Starting server on port: {}", getServerPort());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,20 @@ public void testHttpServer() throws IOException, InterruptedException {
assertEquals(HttpStatus.OK, HttpStatus.fromCode(httpResponse.statusCode()));
assertEquals(HttpMethod.GET, HttpMethod.valueOf(request.method()));
assertEquals(URI.create("http://localhost:8080/auth?foo&bar=HTTP/1.1"), request.uri());
assertEquals("<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta http-equiv=\"Content-Type\" content=\"text/html\" charset=\"UTF-8\">\n" +
" <title>Authentication</title>\n" +
"</head>\n" +
"<body>\n" +
" <div style=\"text-align: center; font-family: sans-serif; margin-top: 20px;\">\n" +
" <h3>Authentication Successful</h3>\n" +
" <i>Please close the page.</i>\n" +
" </div>\n" +
"</body>\n" +
"</html>", httpResponse.body());
assertEquals("""
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html" charset="UTF-8">
<title>Authentication</title>
</head>
<body>
<div style="text-align: center; font-family: sans-serif; margin-top: 20px;">
<h3>Authentication Successful</h3>
<i>Please close the page.</i>
</div>
</body>
</html>""", httpResponse.body());
assertEquals("{ {content-length=[350], content-type=[text/html]} }",
"{ " + httpResponse.headers().map() + " }");
assertEquals("localhost", httpServer.getServerHost());
Expand Down
9 changes: 9 additions & 0 deletions jpro-mail/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,13 @@ dependencies {
api "org.eclipse.collections:eclipse-collections-api:$ECLIPSE_COLLECTIONS_VERSION"
implementation "org.eclipse.collections:eclipse-collections:$ECLIPSE_COLLECTIONS_VERSION"
api "org.slf4j:slf4j-api:$SLF4J_API_VERSION"
}

javadoc {
options {
encoding = 'UTF-8'
version = true
author = true
// addStringOption('Xdoclint:none', '-quiet')
}
}
21 changes: 15 additions & 6 deletions jpro-mdfx/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
plugins {
id 'org.javamodularity.moduleplugin' version "$MODULE_PLUGIN_VERSION"
id 'org.javamodularity.moduleplugin' version "$MODULE_PLUGIN_VERSION"
}

dependencies {
implementation project(':jpro-youtube')
implementation "com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:$FLEXMARK_VERSION"
implementation "com.vladsch.flexmark:flexmark-ext-gfm-tasklist:$FLEXMARK_VERSION"
implementation "com.vladsch.flexmark:flexmark-ext-tables:$FLEXMARK_VERSION"
implementation "com.vladsch.flexmark:flexmark-ext-attributes:$FLEXMARK_VERSION"
implementation project(':jpro-youtube')
implementation "com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:$FLEXMARK_VERSION"
implementation "com.vladsch.flexmark:flexmark-ext-gfm-tasklist:$FLEXMARK_VERSION"
implementation "com.vladsch.flexmark:flexmark-ext-tables:$FLEXMARK_VERSION"
implementation "com.vladsch.flexmark:flexmark-ext-attributes:$FLEXMARK_VERSION"
}

javadoc {
options {
encoding = 'UTF-8'
version = true
author = true
// addStringOption('Xdoclint:none', '-quiet')
}
}