diff --git a/.github/smoke/Smoke.java b/.github/smoke/Smoke.java new file mode 100644 index 0000000..fee1f38 --- /dev/null +++ b/.github/smoke/Smoke.java @@ -0,0 +1,56 @@ +///usr/bin/env jbang "$0" "$@" ; exit $? +//JAVA 25 +//RUNTIME_OPTIONS --enable-native-access=ALL-UNNAMED +// Dependencies are supplied at run time via `jbang --deps ...` so the workflow +// can pin the released version and the per-arch native jar from the matrix. + +import io.github.dfa1.zstd.Zstd; +import io.github.dfa1.zstd.ZstdCompressCtx; +import io.github.dfa1.zstd.ZstdDecompressCtx; +import io.github.dfa1.zstd.ZstdDictionary; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/// Smoke test for a published zstd-java release: proves the bundled native +/// library loads on the host OS/arch and the core + dictionary paths work. +/// Run against a release from Maven Central, one arch per CI matrix leg. +public class Smoke { + + public static void main(String[] args) { + String platform = System.getProperty("os.name") + "/" + System.getProperty("os.arch"); + + // 1. Core round-trip — proves the native library loaded and compress/decompress work. + byte[] original = "the quick brown fox ".repeat(2000).getBytes(); + byte[] compressed = Zstd.compress(original, 9); + byte[] restored = Zstd.decompress(compressed); + if (!Arrays.equals(original, restored)) { + throw new AssertionError("core round-trip mismatch on " + platform); + } + if (compressed.length >= original.length) { + throw new AssertionError("expected compression to shrink the input on " + platform); + } + + // 2. Dictionary round-trip — exercises the ZDICT training path (the library's differentiator). + List samples = new ArrayList<>(); + for (int i = 0; i < 2000; i++) { + samples.add(("{\"id\":" + i + ",\"user\":\"user_" + (i % 100) + "\",\"event\":\"click\"}").getBytes()); + } + ZstdDictionary dict = ZstdDictionary.train(samples, 8 * 1024); + try (ZstdCompressCtx cctx = new ZstdCompressCtx(); + ZstdDecompressCtx dctx = new ZstdDecompressCtx()) { + byte[] message = samples.get(7); + byte[] dictCompressed = cctx.compress(message, dict); + byte[] dictRestored = dctx.decompress(dictCompressed, message.length, dict); + if (!Arrays.equals(message, dictRestored)) { + throw new AssertionError("dictionary round-trip mismatch on " + platform); + } + } + + System.out.println("OK " + platform + + " | zstd " + Zstd.version() + + " | core " + original.length + " -> " + compressed.length + " bytes" + + " | dictionary round-trip passed"); + } +} diff --git a/.github/workflows/release-smoke.yml b/.github/workflows/release-smoke.yml new file mode 100644 index 0000000..b617150 --- /dev/null +++ b/.github/workflows/release-smoke.yml @@ -0,0 +1,82 @@ +name: Release smoke test + +# Verifies a PUBLISHED release on Maven Central actually loads and runs on every +# supported OS/arch — one runner per native classifier. Pulls the release jars +# from Central (no source build, no submodule, no zig), so it tests exactly what +# users consume. Trigger manually and pass the version to check. + +on: + workflow_dispatch: + inputs: + version: + description: Version to smoke-test. Leave blank to use the latest release on Maven Central. + required: false + default: "" + schedule: + # Weekly, Mondays 06:00 UTC. No input on scheduled runs, so the resolve job + # picks the latest release on Maven Central — catches Central / runner-image + # drift against the published release without a manual trigger. + - cron: "0 6 * * 1" + +permissions: + contents: read + +jobs: + resolve: + name: resolve version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.pick.outputs.version }} + steps: + - name: Resolve version (input, else latest on Maven Central) + id: pick + shell: bash + run: | + version="${{ inputs.version }}" + if [ -z "$version" ]; then + # in maven-metadata.xml is the latest non-snapshot release. + version=$(curl -fsSL https://repo1.maven.org/maven2/io/github/dfa1/zstd/zstd/maven-metadata.xml \ + | grep -oE '[^<]+' | sed -E 's/<\/?release>//g') + fi + if [ -z "$version" ]; then + echo "could not resolve a version from Maven Central" >&2 + exit 1 + fi + echo "Smoke-testing version: $version" + echo "version=$version" >> "$GITHUB_OUTPUT" + + smoke: + name: ${{ matrix.classifier }} + needs: resolve + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-latest, classifier: linux-x86_64 } + - { os: ubuntu-24.04-arm, classifier: linux-aarch64 } + - { os: macos-13, classifier: osx-x86_64 } + - { os: macos-14, classifier: osx-aarch64 } + - { os: windows-latest, classifier: windows-x86_64 } + - { os: windows-11-arm, classifier: windows-aarch64 } + runs-on: ${{ matrix.os }} + steps: + - name: Checkout (smoke sources only) + uses: actions/checkout@v4 + + - name: Set up JDK 25 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '25' + + - name: Set up JBang + uses: jbangdev/setup-jbang@main + + - name: Smoke-test ${{ needs.resolve.outputs.version }} on ${{ matrix.classifier }} + shell: bash + env: + VERSION: ${{ needs.resolve.outputs.version }} + run: | + jbang --java 25 \ + --deps "io.github.dfa1.zstd:zstd:${VERSION},io.github.dfa1.zstd:zstd-native-${{ matrix.classifier }}:${VERSION}" \ + .github/smoke/Smoke.java