From c350f13af80fe3efd355539d0ad59e5d86879f5c Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Thu, 26 Mar 2026 15:46:32 +0200 Subject: [PATCH] Add unit test for Mandrel.getPkgFromJson Test parsing of GitHub release JSON using 5 representative Mandrel releases (JDK 17/21/23/24/25). Verifies asset filtering, platform detection, archive types, JDK version extraction, prerelease skipping, and non-matching filename handling. Requires FOOJAY_API_ENVIRONMENT=test to avoid MQTT initialization. --- .../foojay/api/distribution/MandrelTest.java | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 src/test/java/io/foojay/api/distribution/MandrelTest.java diff --git a/src/test/java/io/foojay/api/distribution/MandrelTest.java b/src/test/java/io/foojay/api/distribution/MandrelTest.java new file mode 100644 index 0000000..034aeba --- /dev/null +++ b/src/test/java/io/foojay/api/distribution/MandrelTest.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2026. + * + * This file is part of DiscoAPI. + * + * DiscoAPI is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * DiscoAPI is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DiscoAPI. If not, see . + */ + +package io.foojay.api.distribution; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import eu.hansolo.jdktools.Architecture; +import eu.hansolo.jdktools.ArchiveType; +import eu.hansolo.jdktools.OperatingSystem; +import eu.hansolo.jdktools.PackageType; +import eu.hansolo.jdktools.ReleaseStatus; +import io.foojay.api.pkg.Distro; +import io.foojay.api.pkg.Pkg; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class MandrelTest { + + private static final Mandrel MANDREL = new Mandrel(); + + /** + * Builds a GitHub-release-style JsonObject for a Mandrel release. + */ + private JsonObject buildReleaseJson(String tagName, boolean prerelease, String[][] assets) { + JsonObject release = new JsonObject(); + release.addProperty("tag_name", tagName); + release.addProperty("prerelease", prerelease); + + JsonArray assetsArray = new JsonArray(); + for (String[] asset : assets) { + JsonObject assetObj = new JsonObject(); + assetObj.addProperty("name", asset[0]); + assetObj.addProperty("browser_download_url", asset[1]); + assetsArray.add(assetObj); + } + release.add("assets", assetsArray); + return release; + } + + /** + * Builds a standard set of assets for a Mandrel release, including + * the .sha1 and .sha256 files that should be filtered out. + */ + private String[][] buildStandardAssets(String tagName, int javaVersion) { + String version = tagName.replace("mandrel-", ""); + String base = "https://github.com/graalvm/mandrel/releases/download/" + tagName + "/"; + return new String[][] { + { "mandrel-java" + javaVersion + "-linux-aarch64-" + version + ".tar.gz", + base + "mandrel-java" + javaVersion + "-linux-aarch64-" + version + ".tar.gz" }, + { "mandrel-java" + javaVersion + "-linux-aarch64-" + version + ".tar.gz.sha1", + base + "mandrel-java" + javaVersion + "-linux-aarch64-" + version + ".tar.gz.sha1" }, + { "mandrel-java" + javaVersion + "-linux-aarch64-" + version + ".tar.gz.sha256", + base + "mandrel-java" + javaVersion + "-linux-aarch64-" + version + ".tar.gz.sha256" }, + { "mandrel-java" + javaVersion + "-linux-amd64-" + version + ".tar.gz", + base + "mandrel-java" + javaVersion + "-linux-amd64-" + version + ".tar.gz" }, + { "mandrel-java" + javaVersion + "-linux-amd64-" + version + ".tar.gz.sha1", + base + "mandrel-java" + javaVersion + "-linux-amd64-" + version + ".tar.gz.sha1" }, + { "mandrel-java" + javaVersion + "-linux-amd64-" + version + ".tar.gz.sha256", + base + "mandrel-java" + javaVersion + "-linux-amd64-" + version + ".tar.gz.sha256" }, + { "mandrel-java" + javaVersion + "-macos-aarch64-" + version + ".tar.gz", + base + "mandrel-java" + javaVersion + "-macos-aarch64-" + version + ".tar.gz" }, + { "mandrel-java" + javaVersion + "-macos-aarch64-" + version + ".tar.gz.sha1", + base + "mandrel-java" + javaVersion + "-macos-aarch64-" + version + ".tar.gz.sha1" }, + { "mandrel-java" + javaVersion + "-macos-aarch64-" + version + ".tar.gz.sha256", + base + "mandrel-java" + javaVersion + "-macos-aarch64-" + version + ".tar.gz.sha256" }, + { "mandrel-java" + javaVersion + "-windows-amd64-" + version + ".zip", + base + "mandrel-java" + javaVersion + "-windows-amd64-" + version + ".zip" }, + { "mandrel-java" + javaVersion + "-windows-amd64-" + version + ".zip.sha1", + base + "mandrel-java" + javaVersion + "-windows-amd64-" + version + ".zip.sha1" }, + { "mandrel-java" + javaVersion + "-windows-amd64-" + version + ".zip.sha256", + base + "mandrel-java" + javaVersion + "-windows-amd64-" + version + ".zip.sha256" }, + }; + } + + @Test + public void getPkgFromJsonParsesReleases() { + String[][] releases = { + { "mandrel-25.0.2.0-Final", "25" }, + { "mandrel-24.2.2.0-Final", "24" }, + { "mandrel-24.1.2.0-Final", "23" }, + { "mandrel-23.1.10.0-Final", "21" }, + { "mandrel-23.0.6.0-Final", "17" }, + }; + + for (String[] release : releases) { + String tagName = release[0]; + int javaVer = Integer.parseInt(release[1]); + + String[][] assets = buildStandardAssets(tagName, javaVer); + JsonObject releaseJson = buildReleaseJson(tagName, false, assets); + + List pkgs = MANDREL.getPkgFromJson( + releaseJson, null, false, null, null, null, null, null, false, null, null, false); + + // Each release has 4 actual binaries (sha1/sha256 filtered out) + assertEquals(4, pkgs.size(), "Expected 4 packages for " + tagName); + + for (Pkg pkg : pkgs) { + // Distribution + assertEquals(Distro.MANDREL.get(), pkg.getDistribution(), + "Distribution mismatch for " + pkg.getFilename()); + + // Package type is always JDK + assertEquals(PackageType.JDK, pkg.getPackageType(), + "PackageType mismatch for " + pkg.getFilename()); + + // Release status is always GA + assertEquals(ReleaseStatus.GA, pkg.getReleaseStatus(), + "ReleaseStatus mismatch for " + pkg.getFilename()); + + // Free use in production + assertTrue(pkg.getFreeUseInProduction(), + "FreeUseInProduction should be true for " + pkg.getFilename()); + + // JDK version matches the java version in the filename + assertEquals(javaVer, pkg.getJdkVersion().getAsInt(), + "JDK version mismatch for " + pkg.getFilename()); + + // Filename should start with mandrel-java + assertTrue(pkg.getFilename().startsWith("mandrel-java" + javaVer), + "Filename prefix mismatch: " + pkg.getFilename()); + + // Direct download URI should be set + assertFalse(pkg.getDirectDownloadUri().isEmpty(), + "Download URI should not be empty for " + pkg.getFilename()); + + // Architecture and OS should be resolved + assertTrue(pkg.getArchitecture() != Architecture.NONE, + "Architecture should be resolved for " + pkg.getFilename()); + assertTrue(pkg.getOperatingSystem() != OperatingSystem.NONE, + "OS should be resolved for " + pkg.getFilename()); + } + + // Verify specific platform combinations + long linuxAarch64 = pkgs.stream() + .filter(p -> p.getOperatingSystem() == OperatingSystem.LINUX + && p.getArchitecture() == Architecture.AARCH64) + .count(); + long linuxAmd64 = pkgs.stream() + .filter(p -> p.getOperatingSystem() == OperatingSystem.LINUX + && p.getArchitecture() == Architecture.AMD64) + .count(); + long macosAarch64 = pkgs.stream() + .filter(p -> p.getOperatingSystem() == OperatingSystem.MACOS + && p.getArchitecture() == Architecture.AARCH64) + .count(); + long windowsAmd64 = pkgs.stream() + .filter(p -> p.getOperatingSystem() == OperatingSystem.WINDOWS + && p.getArchitecture() == Architecture.AMD64) + .count(); + + assertEquals(1, linuxAarch64, "Expected 1 linux-aarch64 pkg for " + tagName); + assertEquals(1, linuxAmd64, "Expected 1 linux-amd64 pkg for " + tagName); + assertEquals(1, macosAarch64, "Expected 1 macos-aarch64 pkg for " + tagName); + assertEquals(1, windowsAmd64, "Expected 1 windows-amd64 pkg for " + tagName); + + // Verify archive types + long tarGzCount = pkgs.stream().filter(p -> p.getArchiveType() == ArchiveType.TAR_GZ).count(); + long zipCount = pkgs.stream().filter(p -> p.getArchiveType() == ArchiveType.ZIP).count(); + assertEquals(3, tarGzCount, "Expected 3 tar.gz packages for " + tagName); + assertEquals(1, zipCount, "Expected 1 zip package for " + tagName); + } + } + + @Test + public void getPkgFromJsonSkipsPrerelease() { + String[][] assets = buildStandardAssets("mandrel-25.0.2.0-Final", 25); + JsonObject releaseJson = buildReleaseJson("mandrel-25.0.2.0-Final", true, assets); + + List pkgs = MANDREL.getPkgFromJson( + releaseJson, null, false, null, null, null, null, null, false, null, null, false); + + assertTrue(pkgs.isEmpty(), "Prerelease should produce no packages"); + } + + @Test + public void getPkgFromJsonSkipsNonMatchingFilenames() { + String base = "https://github.com/graalvm/mandrel/releases/download/mandrel-25.0.2.0-Final/"; + String[][] assets = { + { "some-random-file.txt", base + "some-random-file.txt" }, + { "mandrel-sources-25.0.2.0.source.tar.gz", base + "mandrel-sources.source.tar.gz" }, + { "release-notes.jar", base + "release-notes.jar" }, + }; + JsonObject releaseJson = buildReleaseJson("mandrel-25.0.2.0-Final", false, assets); + + List pkgs = MANDREL.getPkgFromJson( + releaseJson, null, false, null, null, null, null, null, false, null, null, false); + + assertTrue(pkgs.isEmpty(), "Non-matching filenames should produce no packages"); + } +}