From 50f228593736694b2db3354da63bb68ed195cc6d Mon Sep 17 00:00:00 2001 From: Sam Freund Date: Wed, 17 Dec 2025 10:16:21 -0600 Subject: [PATCH] Integrate smoketests into image build (#2248) Runs the smoketest on each image after we build it in CI. This helps ensure that we check every image that we build has the requisite JNI libraries, and that they can be loaded. This is needed cause we've been breaking that, and our current smoketests don't actually test all our libraries since some are gated behind platform checks. --- .github/workflows/build.yml | 57 ++++++-------- .../src/main/java/org/photonvision/Main.java | 76 ++++++++++--------- 2 files changed, 64 insertions(+), 69 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 23093b203..56e0ffcab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -409,44 +409,9 @@ jobs: - run: ls *.jar | %{ Write-Host "Running $($_.Name)"; Start-Process "java" -ArgumentList "-jar `"$($_.FullName)`" --smoketest" -NoNewWindow -Wait; break } if: ${{ (matrix.os) == 'windows-latest' }} - run-smoketest-chroot: - needs: [build-package] - - strategy: - fail-fast: false - matrix: - include: - - image_suffix: RaspberryPi - image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_raspi.img.xz - - image_suffix: rubikpi3 - image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_rubikpi3.tar.xz - root_location: 'offset=569376768' - - image_suffix: orangepi5 - image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5.img.xz - - runs-on: ubuntu-24.04-arm - name: smoketest-${{ matrix.image_suffix }} - - steps: - - uses: actions/download-artifact@v4 - with: - name: jar-LinuxArm64 - - - uses: photonvision/photon-image-runner@HEAD - name: Run photon smoketest - id: generate_image - with: - image_url: ${{ matrix.image_url }} - root_location: ${{ matrix.root_location || 'partition=2' }} - # our image better have java installed already - commands: | - java -jar *.jar --smoketest - build-image: needs: [build-package] - if: ${{ github.event_name != 'pull_request' }} - strategy: fail-fast: false matrix: @@ -454,66 +419,79 @@ jobs: - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: RaspberryPi + plat_override: LINUX_RASPBIAN64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_raspi.img.xz minimum_free_mb: 100 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: limelight2 + plat_override: LINUX_RASPBIAN64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight.img.xz minimum_free_mb: 100 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: limelight3 + plat_override: LINUX_RASPBIAN64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight3.img.xz minimum_free_mb: 100 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: limelight3G + plat_override: LINUX_RASPBIAN64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight3g.img.xz minimum_free_mb: 100 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: limelight4 + plat_override: LINUX_RASPBIAN64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_limelight4.img.xz minimum_free_mb: 100 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: luma_p1 + plat_override: LINUX_RASPBIAN64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_luma_p1.img.xz minimum_free_mb: 100 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: orangepi5 + plat_override: LINUX_RK3588_64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5.img.xz minimum_free_mb: 1024 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: orangepi5b + plat_override: LINUX_RK3588_64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5b.img.xz minimum_free_mb: 1024 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: orangepi5plus + plat_override: LINUX_RK3588_64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5plus.img.xz minimum_free_mb: 1024 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: orangepi5pro + plat_override: LINUX_RK3588_64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5pro.img.xz minimum_free_mb: 1024 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: orangepi5max + plat_override: LINUX_RK3588_64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_opi5max.img.xz minimum_free_mb: 1024 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: rock5c + plat_override: LINUX_RK3588_64 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_rock5c.img.xz minimum_free_mb: 1024 - os: ubuntu-24.04-arm artifact-name: LinuxArm64 image_suffix: rubikpi3 + plat_override: LINUX_QCS6490 image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/$IMAGE_VERSION/photonvision_rubikpi3.tar.xz minimum_free_mb: 1024 root_location: 'offset=569376768' @@ -541,6 +519,7 @@ jobs: commands: | chmod +x scripts/armrunner.sh ./scripts/armrunner.sh + java -jar *.jar --smoketest --platform=${{ matrix.plat_override }} - name: Compress image # Compress the standard images @@ -570,8 +549,16 @@ jobs: name: image-${{ matrix.image_suffix }} path: photonvision*.xz + matrix-checker: + runs-on: ubuntu-latest + needs: [build-image] + if: always() + steps: + - run: ${{!contains(needs.*.result, 'failure')}} + release: needs: [build-photonlib-vendorjson, build-package, build-image, combine] + if: github.ref == ('refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) && github.repository == 'PhotonVision/photonvision' runs-on: ubuntu-22.04 steps: # Download all fat JARs diff --git a/photon-server/src/main/java/org/photonvision/Main.java b/photon-server/src/main/java/org/photonvision/Main.java index 5dfe38cde..c11bc0203 100644 --- a/photon-server/src/main/java/org/photonvision/Main.java +++ b/photon-server/src/main/java/org/photonvision/Main.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; import org.apache.commons.cli.*; import org.photonvision.common.LoadJNI; +import org.photonvision.common.LoadJNI.JNITypes; import org.photonvision.common.configuration.CameraConfiguration; import org.photonvision.common.configuration.ConfigManager; import org.photonvision.common.configuration.NeuralNetworkModelManager; @@ -53,7 +54,6 @@ public class Main { public static final int DEFAULT_WEBPORT = 5800; private static final Logger logger = new Logger(Main.class, LogGroup.General); - private static final boolean isRelease = PhotonVersion.isRelease; private static boolean isTestMode = false; private static boolean isSmoketest = false; @@ -70,7 +70,7 @@ public class Main { false, "Run in test mode with 2019 and 2020 WPI field images in place of cameras"); - options.addOption("p", "path", true, "Point test mode to a specific folder"); + options.addOption("f", "folder", true, "Point test mode to a specific folder"); options.addOption("n", "disable-networking", false, "Disables control device network settings"); options.addOption( "c", @@ -82,6 +82,7 @@ public class Main { "smoketest", false, "Exit Photon after loading native libraries and camera configs, but before starting up camera runners"); + options.addOption("p", "platform", true, "Specify platform override, based on Platform enum"); CommandLineParser parser = new DefaultParser(); CommandLine cmd = parser.parse(options, args); @@ -118,6 +119,18 @@ public class Main { if (cmd.hasOption("smoketest")) { isSmoketest = true; } + + if (cmd.hasOption("platform")) { + String platStr = cmd.getOptionValue("platform"); + try { + Platform plat = Platform.valueOf(platStr); + Platform.overridePlatform(plat); + logger.info("Overrode platform to: " + plat); + } catch (IllegalArgumentException e) { + logger.error("Invalid platform override: " + platStr); + return false; + } + } } return true; } @@ -161,6 +174,18 @@ public class Main { VisionSourceManager.getInstance().registerLoadedConfigs(cameraConfigs); } + private static void tryLoadJNI(JNITypes type) { + try { + LoadJNI.forceLoad(type); + logger.info("Loaded " + type.name() + "-JNI"); + } catch (IOException e) { + logger.error("Failed to load " + type.name() + "-JNI!", e); + if (isSmoketest) { + System.exit(1); + } + } + } + public static void main(String[] args) { logger.info( "Starting PhotonVision version " @@ -209,41 +234,24 @@ public class Main { System.exit(1); } - try { - if (Platform.isRaspberryPi()) { - LoadJNI.forceLoad(LoadJNI.JNITypes.LIBCAMERA); - logger.info("Loaded libcamera-JNI"); - } - } catch (IOException e) { - logger.error("Failed to load libcamera-JNI!", e); + if (Platform.isRaspberryPi()) { + tryLoadJNI(JNITypes.LIBCAMERA); } - try { - if (Platform.isRK3588()) { - LoadJNI.forceLoad(LoadJNI.JNITypes.RKNN_DETECTOR); - logger.info("Loaded RKNN-JNI"); - } else { - logger.error("Platform does not support RKNN based machine learning!"); - } - } catch (IOException e) { - logger.error("Failed to load RKNN-JNI!", e); + + if (Platform.isRK3588()) { + tryLoadJNI(JNITypes.RKNN_DETECTOR); + } else { + logger.error("Platform does not support RKNN based machine learning!"); } - try { - if (Platform.isQCS6490()) { - LoadJNI.forceLoad(LoadJNI.JNITypes.RUBIK_DETECTOR); - logger.info("Loaded Rubik-JNI"); - } else { - logger.error("Platform does not support Rubik based machine learning!"); - } - } catch (IOException e) { - logger.error("Failed to load Rubik-JNI!", e); + + if (Platform.isQCS6490()) { + tryLoadJNI(JNITypes.RUBIK_DETECTOR); + } else { + logger.error("Platform does not support Rubik based machine learning!"); } - try { - LoadJNI.forceLoad(LoadJNI.JNITypes.MRCAL); - logger.info("mrcal-JNI loaded successfully."); - } catch (Exception e) { - logger.warn( - "Failed to load mrcal-JNI! Camera calibration will fall back to opencv\n" - + e.getMessage()); + + if (Platform.isWindows() || Platform.isLinux()) { + tryLoadJNI(JNITypes.MRCAL); } CVMat.enablePrint(false);