Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 88 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ jobs:
package:
needs: [build-native, test]
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -183,8 +185,93 @@ jobs:
name: nuget-package
path: artifacts/*.nupkg

# Smoke test the built NuGet package on every supported RID.
#
# This is NOT a rebuild of the solution - it consumes the .nupkg produced
# by the `package` job via a PackageReference, then runs a tiny console
# app that exercises the native FFI path. The purpose is to catch
# packaging-level regressions that project-reference tests miss:
# * missing runtimes/{rid}/native/* entries in the .nupkg
# * wrong architecture binaries shipped for a RID
# * DllImport resolver failing to find the native library
# when the package is consumed as a NuGet dependency
package-smoke-test:
needs: package
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
rid: win-x64
dotnet-arch: x64
- os: windows-11-arm
rid: win-arm64
dotnet-arch: arm64
- os: ubuntu-latest
rid: linux-x64
dotnet-arch: x64
- os: ubuntu-24.04-arm
rid: linux-arm64
dotnet-arch: arm64
# No Intel macOS runners remain; run the x64 SDK under Rosetta
# on an ARM64 runner instead.
- os: macos-latest
rid: osx-x64
dotnet-arch: x64
- os: macos-latest
rid: osx-arm64
dotnet-arch: arm64
runs-on: ${{ matrix.os }}
env:
# Force an isolated package cache so we always consume the freshly
# built .nupkg, never a cached earlier version.
NUGET_PACKAGES: ${{ github.workspace }}/.smoke-nuget-cache
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
steps:
- uses: actions/checkout@v4
# No submodules needed - the smoke test project has zero
# dependencies on the vendored rerun source tree.

- name: Setup .NET (${{ matrix.dotnet-arch }})
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
architecture: ${{ matrix.dotnet-arch }}

- name: Download built NuGet package
uses: actions/download-artifact@v4
with:
name: nuget-package
path: artifacts

- name: List downloaded package
shell: bash
run: ls -la artifacts

- name: Restore smoke test against local package
shell: bash
working-directory: tests/Rerun.Net.PackageSmokeTest
run: |
dotnet restore \
-p:RerunNetVersion=${{ needs.package.outputs.version }}

- name: Build smoke test
shell: bash
working-directory: tests/Rerun.Net.PackageSmokeTest
run: |
dotnet build --no-restore -c Release \
-p:RerunNetVersion=${{ needs.package.outputs.version }}

- name: Run smoke test (${{ matrix.rid }})
shell: bash
working-directory: tests/Rerun.Net.PackageSmokeTest
run: |
dotnet run --no-build -c Release \
-p:RerunNetVersion=${{ needs.package.outputs.version }}

deploy:
needs: [package, codegen-check]
needs: [package, package-smoke-test, codegen-check]
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
Expand Down
18 changes: 18 additions & 0 deletions tests/Rerun.Net.PackageSmokeTest/NuGet.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Scoped NuGet configuration for the package smoke test. Clears any inherited
sources so we only consume:
* nuget.org - for transitive dependencies (Apache.Arrow, etc.)
* local-artifacts - the artifacts/ folder at the repo root, where CI drops
the freshly built Rerun.Net.*.nupkg before running this project.

The local-artifacts path is relative to this NuGet.config file, so it
resolves to <repo>/artifacts regardless of the working directory.
-->
<configuration>
<packageSources>
<clear />
<add key="nuget-org" value="https://api.nuget.org/v3/index.json" />
<add key="local-artifacts" value="../../artifacts" />
</packageSources>
</configuration>
90 changes: 90 additions & 0 deletions tests/Rerun.Net.PackageSmokeTest/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Package smoke test for Rerun.Net.
//
// Consumes the published Rerun.Net NuGet package and exercises the full
// managed -> native code path on whatever RID this process happens to be
// running on. The goal is to prove, per platform, that:
//
// 1. The package restores cleanly from a PackageReference.
// 2. The runtimes/{rid}/native/{libname} binary shipped inside the .nupkg
// is discovered and loaded by the custom DllImportResolver / .NET host.
// 3. A round-trip RecordingStream -> Save -> disposed flow actually
// produces a non-empty .rrd file.
//
// Exits 0 on success, non-zero on failure. Any exception is printed to
// stderr so the CI log makes the failure obvious.

using System.Runtime.InteropServices;
using Rerun.Net;
using Rerun.Net.Archetypes;
using Rerun.Net.Components;
using Rerun.Net.Datatypes;

Console.WriteLine("=== Rerun.Net package smoke test ===");
Console.WriteLine($"RuntimeIdentifier : {RuntimeInformation.RuntimeIdentifier}");
Console.WriteLine($"OSDescription : {RuntimeInformation.OSDescription}");
Console.WriteLine($"OSArchitecture : {RuntimeInformation.OSArchitecture}");
Console.WriteLine($"ProcessArch : {RuntimeInformation.ProcessArchitecture}");
Console.WriteLine($"FrameworkDesc : {RuntimeInformation.FrameworkDescription}");

string? rrdPath = null;
try
{
// Step 1: touch the native library via the version entry point. This is
// the cheapest call that forces rerun_c to load; if the native binary
// for this RID is missing or the wrong architecture, we fail here with
// a DllNotFoundException or BadImageFormatException before touching
// anything else.
var version = RecordingStream.VersionString();
Console.WriteLine($"rerun_c version : {version}");
if (string.IsNullOrWhiteSpace(version))
throw new InvalidOperationException("rr_version_string returned an empty string.");

// Step 2: exercise the full RecordingStream -> Save -> Log -> Dispose
// path to prove Arrow FFI marshalling and sink wiring work in the
// packaged build, not just for version strings.
rrdPath = Path.Combine(
Path.GetTempPath(),
$"rerun_net_pkg_smoke_{Guid.NewGuid():N}.rrd");

using (var rec = new RecordingStream("rerun_net_package_smoke_test"))
{
rec.Save(rrdPath);
rec.SetTimeSequence("frame", 0);

var points = new Points3D(
new Position3D(new Vec3D([0f, 0f, 0f])),
new Position3D(new Vec3D([1f, 1f, 1f])),
new Position3D(new Vec3D([2f, 2f, 2f])))
.WithColors(
new Color(new Rgba32(0xFF0000FFu)),
new Color(new Rgba32(0x00FF00FFu)),
new Color(new Rgba32(0x0000FFFFu)))
.WithRadii(new Radius(0.5f));

rec.Log("smoke/points", points);
}

var info = new FileInfo(rrdPath);
if (!info.Exists)
throw new InvalidOperationException($"RRD file was not created at {rrdPath}.");
if (info.Length == 0)
throw new InvalidOperationException($"RRD file at {rrdPath} is empty.");

Console.WriteLine($"Wrote {info.Length} bytes to {rrdPath}");
Console.WriteLine("=== SMOKE TEST OK ===");
return 0;
}
catch (Exception ex)
{
Console.Error.WriteLine("=== SMOKE TEST FAILED ===");
Console.Error.WriteLine(ex);
return 1;
}
finally
{
if (rrdPath is not null && File.Exists(rrdPath))
{
try { File.Delete(rrdPath); }
catch { /* best-effort cleanup */ }
}
}
31 changes: 31 additions & 0 deletions tests/Rerun.Net.PackageSmokeTest/Rerun.Net.PackageSmokeTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<!--
Standalone smoke test that consumes the built Rerun.Net NuGet package via a
PackageReference (NOT a ProjectReference). Its purpose is to verify, on
every supported RID, that the published .nupkg works end-to-end:
1. restore succeeds from the produced package
2. the native rerun_c shared library is resolved from the package's
runtimes/{rid}/native/ folder
3. a minimal RecordingStream flow actually writes a non-empty .rrd file

This project is intentionally NOT listed in Rerun.Net.slnx, because the
Rerun.Net package it depends on only exists AFTER the `package` CI job has
built it. It is built and run standalone from the `package-smoke-test`
job in .github/workflows/ci.yml.
-->

<PropertyGroup>
<OutputType>Exe</OutputType>
<RootNamespace>Rerun.Net.PackageSmokeTest</RootNamespace>
<AssemblyName>Rerun.Net.PackageSmokeTest</AssemblyName>
<IsPackable>false</IsPackable>
<!-- Overridden from CI with the exact version the `package` job produced. -->
<RerunNetVersion Condition="'$(RerunNetVersion)' == ''">0.0.0-ci-local</RerunNetVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Rerun.Net" Version="$(RerunNetVersion)" />
</ItemGroup>

</Project>
Loading