diff --git a/.github/workflows/tck-vtl-tf.yml b/.github/workflows/tck-vtl-tf-spark3.yml similarity index 79% rename from .github/workflows/tck-vtl-tf.yml rename to .github/workflows/tck-vtl-tf-spark3.yml index 6afe70322..0bd571b06 100644 --- a/.github/workflows/tck-vtl-tf.yml +++ b/.github/workflows/tck-vtl-tf-spark3.yml @@ -1,4 +1,4 @@ -name: Run VTL TF TCK +name: Run VTL TF TCK (Spark 3) on: push: @@ -7,8 +7,11 @@ on: branches: [ master, develop ] jobs: - test: + tck-spark3: + name: TCK VTL v2.1 (Spark 3) runs-on: ubuntu-latest + env: + TCK_REPORT_TITLE: 'TCK VTL v2.1 (Spark 3)' steps: - name: Checkout main project @@ -53,31 +56,31 @@ jobs: uses: actions/cache@v5 with: path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + key: ${{ runner.os }}-maven-tck-spark3-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - - name: Build and run tests + - name: Build dependencies and run TCK (coverage only) continue-on-error: true - run: mvn clean test --batch-mode + run: | + mvn clean install -pl coverage -am -DskipTests --batch-mode + mvn test -pl coverage --batch-mode - # dorny/test-reporter titles come from Surefire ; rewrite TCK names so - # passed tests show "Test N" + newline + tab + path (see coverage/scripts/prettify_tck_surefire_xml.py). - name: Prettify TCK Surefire XML for GitHub if: always() run: python3 coverage/scripts/prettify_tck_surefire_xml.py - # only-summary: table per XML only (no per-test expansion). max-annotations: 0 avoids PR file annotations. - name: Publish JUnit test results uses: dorny/test-reporter@v3 if: always() with: - name: JUnit Test Report + name: JUnit (Spark 3) path: coverage/target/surefire-reports/*.xml reporter: java-junit only-summary: 'true' max-annotations: 0 fail-on-error: 'false' + fail-on-empty: 'false' - name: Generate TCK scripts report if: always() @@ -87,6 +90,6 @@ jobs: if: always() uses: actions/upload-artifact@v7 with: - name: tck-scripts-report + name: tck-scripts-report-spark3 path: coverage/target/tck-scripts-report.md if-no-files-found: ignore diff --git a/.github/workflows/tck-vtl-tf-spark4.yml b/.github/workflows/tck-vtl-tf-spark4.yml new file mode 100644 index 000000000..6d188714e --- /dev/null +++ b/.github/workflows/tck-vtl-tf-spark4.yml @@ -0,0 +1,95 @@ +name: Run VTL TF TCK (Spark 4) + +on: + push: + branches: [ '**' ] + pull_request: + branches: [ master, develop ] + +jobs: + tck-spark4: + name: TCK VTL v2.1 (Spark 4) + runs-on: ubuntu-latest + env: + TCK_REPORT_TITLE: 'TCK VTL v2.1 (Spark 4)' + + steps: + - name: Checkout main project + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Clone vtl spec repo (branch fix/tck-2.1) + run: git clone --branch fix/tck-2.1 https://github.com/sdmx-twg/vtl.git + + - name: Install Python 3 + uses: actions/setup-python@v6 + with: + python-version: '3.11' + + - name: Run TCK generator script + run: | + DOC_VERSION=v2.1 python3 vtl/scripts/generate_tck_files.py + + - name: Move generated TCK zip to resources + run: | + mkdir -p coverage/src/main/resources + mv vtl/tck/v2.1.zip coverage/src/main/resources/ + + - name: Set up Java + uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '17' + + - uses: s4u/maven-settings-action@v4.0.0 + with: + githubServer: false + servers: | + [{ + "id": "Github", + "username": "${{ secrets.GH_PACKAGES_USERNAME }}", + "password": "${{ secrets.GH_PACKAGES_PASSWORD }}" + }] + + - name: Cache Maven packages + uses: actions/cache@v5 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-tck-spark4-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Build dependencies and run TCK (coverage only, Spark 4 profile) + continue-on-error: true + run: | + mvn clean install -pl coverage -am -DskipTests --batch-mode -Pspark4-tck + mvn test -pl coverage --batch-mode -Pspark4-tck + + - name: Prettify TCK Surefire XML for GitHub + if: always() + run: python3 coverage/scripts/prettify_tck_surefire_xml.py + + - name: Publish JUnit test results + uses: dorny/test-reporter@v3 + if: always() + with: + name: JUnit (Spark 4) + path: coverage/target/surefire-reports/*.xml + reporter: java-junit + only-summary: 'true' + max-annotations: 0 + fail-on-error: 'false' + fail-on-empty: 'false' + + - name: Generate TCK scripts report + if: always() + run: python3 coverage/scripts/render_tck_job_summary.py + + - name: Upload full TCK script report artifact + if: always() + uses: actions/upload-artifact@v7 + with: + name: tck-scripts-report-spark4 + path: coverage/target/tck-scripts-report.md + if-no-files-found: ignore diff --git a/coverage/pom.xml b/coverage/pom.xml index bc86b4215..8c56b1b5c 100644 --- a/coverage/pom.xml +++ b/coverage/pom.xml @@ -18,6 +18,9 @@ ${project.basedir}/../coverage/target/site/jacoco-aggregate/jacoco.xml + + vtl-spark + TCK VTL v2.1 (Spark 3) @@ -48,7 +51,7 @@ fr.insee.trevas - vtl-spark + ${trevas.spark.artifact} 2.4.0-SNAPSHOT @@ -70,6 +73,9 @@ 3.5.4 --add-exports java.base/sun.nio.ch=ALL-UNNAMED + + ${tck.suite.title} + + + + + spark4-tck + + vtl-spark4 + TCK VTL v2.1 (Spark 4) + + + \ No newline at end of file diff --git a/coverage/scripts/render_tck_job_summary.py b/coverage/scripts/render_tck_job_summary.py index fe7d30a71..13cb188a9 100644 --- a/coverage/scripts/render_tck_job_summary.py +++ b/coverage/scripts/render_tck_job_summary.py @@ -22,6 +22,8 @@ Writes: coverage/target/tck-scripts-report.md Appends to GITHUB_STEP_SUMMARY when set (after existing summary from test-reporter). + +Optional env TCK_REPORT_TITLE: prepended as Markdown H1 (e.g. TCK VTL v2.1 (Spark 4)). """ from __future__ import annotations @@ -444,11 +446,15 @@ def render_case_plain(i: int, display_path: str, script: str, row: dict[str, str def main() -> None: summary_path = os.environ.get("GITHUB_STEP_SUMMARY") zip_path = resolve_tck_zip() + report_title = os.environ.get("TCK_REPORT_TITLE", "").strip() FULL_REPORT_PATH.parent.mkdir(parents=True, exist_ok=True) if zip_path is None: - msg = ( + msg = "" + if report_title: + msg += f"# {report_title}\n\n" + msg += ( "TCK scripts output\n\n" "Source zip: (not found)\n\n" "Expected one of:\n" @@ -466,6 +472,8 @@ def main() -> None: results = parse_ordered_results(SUREFIRE_XML_PATH) chunks: list[str] = [] + if report_title: + chunks.append(f"# {report_title}\n\n") chunks.append("TCK scripts output\n") chunks.append("") chunks.append(f"Source zip: {zip_path_for_report(zip_path)}\n") diff --git a/coverage/src/test/java/fr/insee/vtl/coverage/TCKTest.java b/coverage/src/test/java/fr/insee/vtl/coverage/TCKTest.java index b33bd2689..3fa0f1a63 100644 --- a/coverage/src/test/java/fr/insee/vtl/coverage/TCKTest.java +++ b/coverage/src/test/java/fr/insee/vtl/coverage/TCKTest.java @@ -14,7 +14,7 @@ import org.apache.spark.sql.SparkSession; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.Named; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -24,7 +24,7 @@ * Spark-backed conformance run against the packaged TCK ({@code v2.1.zip}). Orchestration only — * discovery, naming, and assertions live under {@code fr.insee.vtl.coverage.tck}. */ -@DisplayName("TCK v2.1 (Spark)") +@DisplayNameGeneration(TckSuiteDisplayNameGenerator.class) class TCKTest { private TckCaseExecutor executor; diff --git a/coverage/src/test/java/fr/insee/vtl/coverage/TckSuiteDisplayNameGenerator.java b/coverage/src/test/java/fr/insee/vtl/coverage/TckSuiteDisplayNameGenerator.java new file mode 100644 index 000000000..48b0a392e --- /dev/null +++ b/coverage/src/test/java/fr/insee/vtl/coverage/TckSuiteDisplayNameGenerator.java @@ -0,0 +1,37 @@ +package fr.insee.vtl.coverage; + +import java.lang.reflect.Method; +import java.util.List; +import org.junit.jupiter.api.DisplayNameGenerator; + +/** + * JUnit suite title from {@code -Dtck.suite.title=…} (set by Maven profile in CI for Spark 3 vs 4). + */ +public final class TckSuiteDisplayNameGenerator implements DisplayNameGenerator { + + private static final DisplayNameGenerator DEFAULT = new DisplayNameGenerator.Standard(); + + @Override + public String generateDisplayNameForClass(Class testClass) { + if (testClass == TCKTest.class) { + return System.getProperty("tck.suite.title", "TCK VTL v2.1 (Spark 3)"); + } + return DEFAULT.generateDisplayNameForClass(testClass); + } + + @Override + public String generateDisplayNameForNestedClass(Class nestedClass) { + return DEFAULT.generateDisplayNameForNestedClass(nestedClass); + } + + @Override + public String generateDisplayNameForMethod(Class testClass, Method testMethod) { + return DEFAULT.generateDisplayNameForMethod(testClass, testMethod); + } + + @Override + public String generateDisplayNameForMethod( + List> enclosingInstanceTypes, Class testClass, Method testMethod) { + return DEFAULT.generateDisplayNameForMethod(enclosingInstanceTypes, testClass, testMethod); + } +}