Skip to content

Commit

Permalink
Enable native tests in CI for virtual thread tests
Browse files Browse the repository at this point in the history
Move JVM 19 tests to 20
  • Loading branch information
ozangunalp committed Jul 26, 2023
1 parent d0e3122 commit 6ab68f5
Show file tree
Hide file tree
Showing 20 changed files with 370 additions and 44 deletions.
51 changes: 51 additions & 0 deletions .github/filter-virtual-threads-tests-json.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash

# Purpose: Prints a filtered version of virtual-threads-tests.json, with "test-modules" reduced to the ones passed in as the first argument.
# This first argument is expected to the define one module per line.
# "include" elements that (after filtering) have no "test-modules" anymore are deleted entirely!
# Note: This script is only for CI and does therefore not aim to be compatible with BSD/macOS.

set -e -u -o pipefail
shopt -s failglob

# path of this shell script
PRG_PATH=$( cd "$(dirname "$0")" ; pwd -P )

JSON=$(cat ${PRG_PATH}/virtual-threads-tests.json)

# Step 0: print unfiltered json and exit in case the parameter is empty (assumption: full build)
if [ -z "$1" ]
then
echo "${JSON}"
exit 0
fi

# Step 1: build an expression for grep that will only extract the given modules from each "test-modules" list,
# including a trailing comma (if exists). Note: mvn doesn't mind something like -pl 'foo,'.
EXPR='((?:(?<=^)|(?<=,)|(?<=, ))('
while read -r impacted
do
EXPR+="${impacted}|"
done < <(echo -n "$1" | ggrep -Po '(?<=integration-tests/virtual-threads/).+')
EXPR+=')(,|$))+'

# Step 2: apply the filter expression via grep to each "test-modules" list and replace each original list with the filtered one
while read -r modules
do
# Notes:
# - trailing "|" (after EXPR) avoids grep return code > 0 if nothing matches (which is a valid case)
# - "paste" joins all matches to get a single line
FILTERED=$(echo -n "${modules}" | ggrep -Po "${EXPR}|" | paste -sd " " -)
JSON=$(echo -n "${JSON}" | sed "s|${modules}|${FILTERED}|")
done < <(echo -n "${JSON}" | jq -r '.include[] | ."test-modules"')

# Step 3: delete entire elements from "include" array that now have an empty "test-modules" list
JSON=$(echo "${JSON}" | jq 'del(.include[] | select(."test-modules" == ""))')

# Step 4: echo final result, printing only {} in case _all_ elements were removed from "include" array
if [ -z "$(echo "${JSON}" | jq '.include[]')" ]
then
echo -n '{}'
else
echo -n "${JSON}"
fi
4 changes: 2 additions & 2 deletions .github/matrix-jvm-tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"os-name": "ubuntu-latest"
}
, {
"name": "19",
"java-version": 19,
"name": "20",
"java-version": 20,
"maven_args": "$JVM_TEST_MAVEN_ARGS",
"maven_opts": "-Xmx2g -XX:MaxMetaspaceSize=1g",
"os-name": "ubuntu-latest"
Expand Down
16 changes: 16 additions & 0 deletions .github/virtual-threads-tests.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"include": [
{
"category": "Main",
"timeout": 45,
"test-modules": "grpc-virtual-threads, mailer-virtual-threads, redis-virtual-threads, rest-client-reactive-virtual-threads, resteasy-reactive-virtual-threads",
"os-name": "ubuntu-latest"
},
{
"category": "Messaging",
"timeout": 45,
"test-modules": "amqp-virtual-threads, jms-virtual-threads, kafka-virtual-threads",
"os-name": "ubuntu-latest"
}
]
}
47 changes: 29 additions & 18 deletions .github/workflows/ci-actions-incremental.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ jobs:
outputs:
native_matrix: ${{ steps.calc-native-matrix.outputs.matrix }}
jvm_matrix: ${{ steps.calc-jvm-matrix.outputs.matrix }}
virtual_threads_matrix: ${{ steps.calc-virtual_threads-matrix.outputs.matrix }}
run_jvm: ${{ steps.calc-run-flags.outputs.run_jvm }}
run_devtools: ${{ steps.calc-run-flags.outputs.run_devtools }}
run_gradle: ${{ steps.calc-run-flags.outputs.run_gradle }}
Expand All @@ -226,6 +227,13 @@ jobs:
json=$(.github/filter-jvm-tests-json.sh)
echo "${json}"
echo "matrix=${json}" >> $GITHUB_OUTPUT
- name: Calculate matrix from virtual-threads-tests.json
id: calc-virtual_threads-matrix
run: |
echo "GIB_IMPACTED_MODULES: ${GIB_IMPACTED_MODULES}"
json=$(.github/filter-virtual-threads-tests-json.sh "${GIB_IMPACTED_MODULES}" | tr -d '\n')
echo "${json}"
echo "matrix=${json}" >> $GITHUB_OUTPUT
- name: Calculate run flags
id: calc-run-flags
run: |
Expand Down Expand Up @@ -602,23 +610,17 @@ jobs:
quarkus-quickstarts/target/build-report.json
quarkus-quickstarts/LICENSE
retention-days: 2
virtual-thread-tests:
name: Virtual Thread Support Tests - JDK ${{matrix.java.name}}
runs-on: ${{matrix.java.os-name}}
virtual-thread-native-tests:
name: Virtual Thread Support Tests Native - ${{matrix.category}}
runs-on: ${{matrix.os-name}}
needs: [build-jdk11, calculate-test-jobs]
# Skip main in forks
if: "needs.calculate-test-jobs.outputs.run_quickstarts == 'true' && (github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main'))"
timeout-minutes: 90
if: "needs.calculate-test-jobs.outputs.virtual_threads_matrix != '{}' && (github.repository == 'quarkusio/quarkus' || !endsWith(github.ref, '/main'))"
timeout-minutes: ${{matrix.timeout}}
strategy:
max-parallel: 12
fail-fast: false
matrix:
java:
- {
name: "20",
java-version: 20,
os-name: "ubuntu-latest",
extra-args: "--enable-preview"
}
matrix: ${{ fromJson(needs.calculate-test-jobs.outputs.virtual_threads_matrix) }}
steps:
- uses: actions/checkout@v3
- name: Download Maven Repo
Expand All @@ -629,19 +631,28 @@ jobs:
- name: Extract Maven Repo
shell: bash
run: tar -xzf maven-repo.tgz -C ~
- name: Set up JDK ${{ matrix.java.java-version }}
- name: Set up JDK 20
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: ${{ matrix.java.java-version }}
- name: Run tests
java-version: 20
# We do this so we can get better analytics for the downloaded version of the build images
- name: Update Docker Client User Agent
shell: bash
run: |
cat <<< $(jq '.HttpHeaders += {"User-Agent": "Quarkus-CI-Docker-Client"}' ~/.docker/config.json) > ~/.docker/config.json
- name: Build
shell: bash
env:
TEST_MODULES: ${{matrix.test-modules}}
CONTAINER_BUILD: ${{startsWith(matrix.os-name, 'windows') && 'false' || 'true'}}
run: |
export LANG=en_US && ./mvnw -e -B -fae --settings .github/mvn-settings.xml -f integration-tests/virtual-threads clean verify -Dnative -Dextra-args=${{matrix.java.extra-args}} -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-20
export LANG=en_US && ./mvnw $COMMON_MAVEN_ARGS -f integration-tests/virtual-threads -pl "$TEST_MODULES" $NATIVE_TEST_MAVEN_ARGS -Dextra-args=--enable-preview -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-20
- name: Upload build reports (if build failed)
uses: actions/upload-artifact@v3
if: ${{ failure() || cancelled() }}
with:
name: "build-reports-Virtual Thread Support - JDK ${{matrix.java.name}}"
name: "build-reports-Virtual Thread Support Tests Native - ${{matrix.category}}"
path: |
integration-tests/virtual-threads/**/target/*-reports/TEST-*.xml
integration-tests/virtual-threads/target/build-report.json
Expand Down
16 changes: 2 additions & 14 deletions integration-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,8 @@
<module>istio</module>
<module>management-interface</module>
<module>management-interface-auth</module>
<!-- Virtual threads test -->
<module>virtual-threads</module>
</modules>
</profile>

Expand All @@ -405,20 +407,6 @@
</modules>
</profile>

<!-- Java 20+ test profile -->
<profile>
<id>java-20</id>
<activation>
<property>
<name>!no-test-modules</name>
</property>
<jdk>[20,)</jdk>
</activation>
<modules>
<module>virtual-threads</module>
</modules>
</profile>

<!-- Common native image test profile
WARNING: In this parent profile, you cannot override properties in a submodule!
Plugin config can only be overridden (to a certain point) via pluginManagement!
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.quarkus.it.vthreads.amqp;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
* An integration test reading the output of the unit test to verify that no tests where pinning the carrier thread.
* It reads the reports generated by surefire.
*/
public class NoPinningVerify {

@Test
void verify() throws IOException, ParserConfigurationException, SAXException {
var reports = new File("target", "surefire-reports");
Assertions.assertTrue(reports.isDirectory(),
"Unable to find " + reports.getAbsolutePath() + ", did you run the tests with Maven before?");
var list = reports.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith("TEST") && name.endsWith("Test.xml");
}
});
Assertions.assertNotNull(list,
"Unable to find " + reports.getAbsolutePath() + ", did you run the tests with Maven before?");

for (File report : list) {
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(report);
var suite = document.getFirstChild();
var cases = getChildren(suite.getChildNodes(), "testcase");
for (Node c : cases) {
verify(report, c);
}
}

}

private void verify(File file, Node ca) {
var fullname = ca.getAttributes().getNamedItem("classname").getTextContent() + "."
+ ca.getAttributes().getNamedItem("name").getTextContent();
var output = getChildren(ca.getChildNodes(), "system-out");
if (output.isEmpty()) {
return;
}
var sout = output.get(0).getTextContent();
if (sout.contains("VThreadContinuation.onPinned")) {
throw new AssertionError("The test case " + fullname + " pinned the carrier thread, check " + file.getAbsolutePath()
+ " for details (or the log of the test)");
}

}

private List<Node> getChildren(NodeList nodes, String name) {
List<Node> list = new ArrayList<>();
for (int i = 0; i < nodes.getLength(); i++) {
var node = nodes.item(i);
if (node.getNodeName().equalsIgnoreCase(name)) {
list.add(node);
}
}
return list;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.it.vthreads.amqp;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class VirtualThreadITCase extends VirtualThreadTest {
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* An integration test reading the output of the unit test to verify that no tests where pinning the carrier thread.
* It reads the reports generated by surefire.
*/
public class NoPinningIT {
public class NoPinningVerify {

@Test
void verify() throws IOException, ParserConfigurationException, SAXException {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.quarkus.it.vthreads.jms;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
* An integration test reading the output of the unit test to verify that no tests where pinning the carrier thread.
* It reads the reports generated by surefire.
*/
public class NoPinningVerify {

@Test
void verify() throws IOException, ParserConfigurationException, SAXException {
var reports = new File("target", "surefire-reports");
Assertions.assertTrue(reports.isDirectory(),
"Unable to find " + reports.getAbsolutePath() + ", did you run the tests with Maven before?");
var list = reports.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith("TEST") && name.endsWith("Test.xml");
}
});
Assertions.assertNotNull(list,
"Unable to find " + reports.getAbsolutePath() + ", did you run the tests with Maven before?");

for (File report : list) {
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(report);
var suite = document.getFirstChild();
var cases = getChildren(suite.getChildNodes(), "testcase");
for (Node c : cases) {
verify(report, c);
}
}

}

private void verify(File file, Node ca) {
var fullname = ca.getAttributes().getNamedItem("classname").getTextContent() + "."
+ ca.getAttributes().getNamedItem("name").getTextContent();
var output = getChildren(ca.getChildNodes(), "system-out");
if (output.isEmpty()) {
return;
}
var sout = output.get(0).getTextContent();
if (sout.contains("VThreadContinuation.onPinned")) {
throw new AssertionError("The test case " + fullname + " pinned the carrier thread, check " + file.getAbsolutePath()
+ " for details (or the log of the test)");
}

}

private List<Node> getChildren(NodeList nodes, String name) {
List<Node> list = new ArrayList<>();
for (int i = 0; i < nodes.getLength(); i++) {
var node = nodes.item(i);
if (node.getNodeName().equalsIgnoreCase(name)) {
list.add(node);
}
}
return list;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.it.vthreads.jms;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class VirtualThreadITCase extends VirtualThreadTest {
}

This file was deleted.

Loading

0 comments on commit 6ab68f5

Please sign in to comment.