Skip to content

Commit 0503a45

Browse files
authored
Merge pull request #7 from managedcode/codex/fix-skip-not-found-errors-in-tests
Assert integration test assets are configured
2 parents d7ae5fb + 292d363 commit 0503a45

File tree

5 files changed

+96
-56
lines changed

5 files changed

+96
-56
lines changed

.github/workflows/ci.yml

Lines changed: 75 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,71 +25,103 @@ jobs:
2525
- name: Build managed projects
2626
run: dotnet build --configuration Release --no-restore
2727

28-
native-linux:
28+
native-assets:
2929
needs: dotnet-build
3030
runs-on: ubuntu-latest
31+
env:
32+
NATIVE_RELEASE_REPO: ${{ vars.MLXSHARP_NATIVE_REPO || 'ManagedCode/MLXSharp' }}
33+
NATIVE_RELEASE_TAG: ${{ vars.MLXSHARP_NATIVE_TAG || '' }}
3134
steps:
32-
- name: Checkout repository
33-
uses: actions/checkout@v4
34-
with:
35-
submodules: recursive
36-
37-
- name: Install build dependencies
35+
- name: Install tooling
3836
run: |
3937
sudo apt-get update
40-
sudo apt-get install -y build-essential cmake libopenblas-dev liblapack-dev liblapacke-dev
38+
sudo apt-get install -y jq unzip
4139
42-
- name: Configure native build
43-
run: cmake -S native -B native/build/linux -DCMAKE_BUILD_TYPE=Release
40+
- name: Download official native binaries
41+
env:
42+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43+
run: |
44+
set -euo pipefail
4445
45-
- name: Build native library
46-
run: cmake --build native/build/linux --target mlxsharp --config Release
46+
repo="${NATIVE_RELEASE_REPO}"
47+
if [ -z "$repo" ]; then
48+
echo "::error::NATIVE_RELEASE_REPO must be provided" >&2
49+
exit 1
50+
fi
4751
48-
- name: Package native artifact
49-
run: |
50-
mkdir -p artifacts/native/linux-x64
51-
cp native/build/linux/libmlxsharp.so artifacts/native/linux-x64/
52+
if [ -n "${NATIVE_RELEASE_TAG}" ]; then
53+
release_api="https://api.github.com/repos/${repo}/releases/tags/${NATIVE_RELEASE_TAG}"
54+
else
55+
release_api="https://api.github.com/repos/${repo}/releases/latest"
56+
fi
5257
53-
- name: Upload native artifact
54-
uses: actions/upload-artifact@v4
55-
with:
56-
name: native-linux-x64
57-
path: artifacts/native/linux-x64/libmlxsharp.so
58+
echo "Fetching release metadata from ${release_api}"
59+
response=$(curl -fsSL -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${GITHUB_TOKEN}" "$release_api")
60+
tag=$(echo "$response" | jq -r '.tag_name // ""')
5861
59-
native-macos:
60-
needs: dotnet-build
61-
runs-on: macos-latest
62-
steps:
63-
- name: Checkout repository
64-
uses: actions/checkout@v4
65-
with:
66-
submodules: recursive
62+
if [ -z "$tag" ]; then
63+
echo "::error::Unable to resolve release tag from ${release_api}" >&2
64+
exit 1
65+
fi
6766
68-
- name: Install CMake
69-
run: brew install cmake
67+
echo "Using native release ${repo}@${tag}"
7068
71-
- name: Configure native build
72-
run: cmake -S native -B native/build/macos -DCMAKE_BUILD_TYPE=Release
69+
nupkg_asset=$(echo "$response" | jq -r '.assets[] | select(.name | startswith("ManagedCode.MLXSharp.")) | select(.name | endswith(".nupkg")) | .name' | head -n1)
70+
if [ -z "$nupkg_asset" ] || [ "$nupkg_asset" = "null" ]; then
71+
echo "::error::No ManagedCode.MLXSharp.*.nupkg asset found in release ${tag}" >&2
72+
exit 1
73+
fi
7374
74-
- name: Build native library
75-
run: cmake --build native/build/macos --target mlxsharp --config Release
75+
asset_url=$(echo "$response" | jq -r --arg name "$nupkg_asset" '.assets[] | select(.name == $name) | .url')
76+
if [ -z "$asset_url" ] || [ "$asset_url" = "null" ]; then
77+
echo "::error::Failed to resolve download URL for ${nupkg_asset}" >&2
78+
exit 1
79+
fi
7680
77-
- name: Package native artifact
78-
run: |
79-
mkdir -p artifacts/native/osx-arm64
80-
cp native/build/macos/libmlxsharp.dylib artifacts/native/osx-arm64/
81-
cp native/build/macos/extern/mlx/mlx/backend/metal/kernels/mlx.metallib artifacts/native/osx-arm64/
81+
mkdir -p work artifacts/native/osx-arm64 artifacts/native/linux-x64
8282
83-
- name: Upload native artifact
83+
echo "Downloading ${nupkg_asset}"
84+
curl -fsSL -H "Accept: application/octet-stream" -H "Authorization: Bearer ${GITHUB_TOKEN}" "$asset_url" -o work/native.nupkg
85+
86+
echo "Extracting native runtimes"
87+
unzip -q work/native.nupkg 'runtimes/osx-arm64/native/*' -d work/extract
88+
unzip -q work/native.nupkg 'runtimes/linux-x64/native/*' -d work/extract
89+
90+
shopt -s nullglob
91+
mac_files=(work/extract/runtimes/osx-arm64/native/*)
92+
linux_files=(work/extract/runtimes/linux-x64/native/*)
93+
94+
if [ ${#mac_files[@]} -eq 0 ]; then
95+
echo "::error::macOS native assets are missing from ${nupkg_asset}" >&2
96+
exit 1
97+
fi
98+
99+
if [ ${#linux_files[@]} -eq 0 ]; then
100+
echo "::error::Linux native assets are missing from ${nupkg_asset}" >&2
101+
exit 1
102+
fi
103+
104+
cp work/extract/runtimes/osx-arm64/native/* artifacts/native/osx-arm64/
105+
cp work/extract/runtimes/linux-x64/native/* artifacts/native/linux-x64/
106+
107+
echo "Staged native artifacts:"
108+
ls -R artifacts/native
109+
110+
- name: Upload macOS native artifact
84111
uses: actions/upload-artifact@v4
85112
with:
86113
name: native-osx-arm64
87114
path: artifacts/native/osx-arm64
88115

116+
- name: Upload Linux native artifact
117+
uses: actions/upload-artifact@v4
118+
with:
119+
name: native-linux-x64
120+
path: artifacts/native/linux-x64
121+
89122
package-test:
90123
needs:
91-
- native-linux
92-
- native-macos
124+
- native-assets
93125
runs-on: macos-latest
94126
steps:
95127
- name: Checkout repository

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,4 +872,8 @@ FodyWeavers.xsd
872872

873873
# Local model files for testing
874874
Tests/**/LocalModels/
875-
Apps/**/LocalModels/
875+
Apps/**/LocalModels/
876+
# Downloaded native artifacts
877+
libs/native-libs/
878+
ManagedCode.MLXSharp.nupkg
879+

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ The CMake project vendored from MLX builds MLX and the shim in one go. macOS bui
101101

102102
## CI overview
103103
1. `dotnet-build` (Ubuntu): restores the solution and compiles managed projects.
104-
2. `native-linux` / `native-macos`: compile `libmlxsharp.so` and `libmlxsharp.dylib` in parallel.
105-
3. `package-test` (macOS): downloads both native artifacts, stages them into `src/MLXSharp/runtimes/{rid}/native`, rebuilds, runs the integration tests, and produces NuGet packages.
104+
2. `native-assets` (Ubuntu): downloads the signed native binaries published with the latest MLXSharp release and uploads them as workflow artifacts.
105+
3. `package-test` (macOS): pulls down the staged native artifacts, copies them into `src/MLXSharp/runtimes/{rid}/native`, rebuilds, runs the integration tests, and produces NuGet packages.
106106

107107
## Testing
108108
The managed integration tests still piggy-back on `mlx_lm` until the native runner is feature-complete. Bring your own HuggingFace bundle (any MLX-compatible repo) and point `MLXSHARP_MODEL_PATH` to it before running:

src/MLXSharp.Tests/ModelIntegrationTests.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public sealed class ModelIntegrationTests
1414
public async Task NativeBackendAnswersSimpleMathAsync()
1515
{
1616
TestEnvironment.EnsureInitialized();
17-
EnsureAssetsOrSkip();
17+
EnsureAssets();
1818

1919
var options = CreateOptions();
2020
using var backend = MlxNativeBackend.Create(options);
@@ -59,18 +59,14 @@ private static MlxClientOptions CreateOptions()
5959
return options;
6060
}
6161

62-
private static void EnsureAssetsOrSkip()
62+
private static void EnsureAssets()
6363
{
6464
var modelPath = Environment.GetEnvironmentVariable("MLXSHARP_MODEL_PATH");
65-
if (string.IsNullOrWhiteSpace(modelPath) || !System.IO.Directory.Exists(modelPath))
66-
{
67-
Skip.If(true, "Native model bundle not found.");
68-
}
65+
Assert.False(string.IsNullOrWhiteSpace(modelPath), "Native model bundle path is not configured. Set MLXSHARP_MODEL_PATH to a valid directory.");
66+
Assert.True(System.IO.Directory.Exists(modelPath), $"Native model bundle not found at '{modelPath}'.");
6967

7068
var library = Environment.GetEnvironmentVariable("MLXSHARP_LIBRARY");
71-
if (string.IsNullOrWhiteSpace(library) || !System.IO.File.Exists(library))
72-
{
73-
Skip.If(true, "Native libmlxsharp library not configured.");
74-
}
69+
Assert.False(string.IsNullOrWhiteSpace(library), "Native libmlxsharp library is not configured. Set MLXSHARP_LIBRARY to the staged native library that ships with the official MLXSharp release.");
70+
Assert.True(System.IO.File.Exists(library), $"Native libmlxsharp library not found at '{library}'.");
7571
}
7672
}

src/MLXSharp/MLXSharp.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,21 @@
1616
</ItemGroup>
1717

1818
<PropertyGroup>
19+
<_RepoRoot>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)/../..'))</_RepoRoot>
20+
<MLXSharpNativeLibsDir Condition="'$(MLXSharpNativeLibsDir)' == ''">$([System.IO.Path]::Combine('$(_RepoRoot)','libs','native-libs'))</MLXSharpNativeLibsDir>
21+
<_MLXSharpMacNativeFromLibs>$([System.IO.Path]::Combine($(MLXSharpNativeLibsDir), 'osx-arm64', 'libmlxsharp.dylib'))</_MLXSharpMacNativeFromLibs>
22+
<_MLXSharpMacMetallibFromLibs>$([System.IO.Path]::Combine($(MLXSharpNativeLibsDir), 'osx-arm64', 'mlx.metallib'))</_MLXSharpMacMetallibFromLibs>
23+
<_MLXSharpLinuxNativeFromLibs>$([System.IO.Path]::Combine($(MLXSharpNativeLibsDir), 'linux-x64', 'libmlxsharp.so'))</_MLXSharpLinuxNativeFromLibs>
24+
<MLXSharpMacNativeBinary Condition="'$(MLXSharpMacNativeBinary)' == '' and Exists('$(_MLXSharpMacNativeFromLibs)')">$(_MLXSharpMacNativeFromLibs)</MLXSharpMacNativeBinary>
1925
<MLXSharpMacNativeBinary Condition="'$(MLXSharpMacNativeBinary)' == ''">$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)','..','..','native','build','libmlxsharp.dylib'))</MLXSharpMacNativeBinary>
2026
<MLXSharpMacNativeDestination>$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)','runtimes','osx-arm64','native','libmlxsharp.dylib'))</MLXSharpMacNativeDestination>
2127
<MLXSharpSkipMacNativeValidation Condition="'$(MLXSharpSkipMacNativeValidation)' == ''">false</MLXSharpSkipMacNativeValidation>
2228
<MLXSharpMacNativeDestinationDir>$([System.IO.Path]::GetDirectoryName('$(MLXSharpMacNativeDestination)'))</MLXSharpMacNativeDestinationDir>
29+
<MLXSharpMacMetallibBinary Condition="'$(MLXSharpMacMetallibBinary)' == '' and Exists('$(_MLXSharpMacMetallibFromLibs)')">$(_MLXSharpMacMetallibFromLibs)</MLXSharpMacMetallibBinary>
2330
<MLXSharpMacMetallibBinary Condition="'$(MLXSharpMacMetallibBinary)' == ''">$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)','..','..','native','build','macos','extern','mlx','mlx','backend','metal','kernels','mlx.metallib'))</MLXSharpMacMetallibBinary>
2431
<MLXSharpMacMetallibDestination Condition="'$(MLXSharpMacMetallibDestination)' == ''">$([System.IO.Path]::Combine('$(MLXSharpMacNativeDestinationDir)','mlx.metallib'))</MLXSharpMacMetallibDestination>
2532

33+
<MLXSharpLinuxNativeBinary Condition="'$(MLXSharpLinuxNativeBinary)' == '' and Exists('$(_MLXSharpLinuxNativeFromLibs)')">$(_MLXSharpLinuxNativeFromLibs)</MLXSharpLinuxNativeBinary>
2634
<MLXSharpLinuxNativeBinary Condition="'$(MLXSharpLinuxNativeBinary)' == ''">$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)','..','..','native','build','linux','libmlxsharp.so'))</MLXSharpLinuxNativeBinary>
2735
<MLXSharpLinuxNativeDestination>$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)','runtimes','linux-x64','native','libmlxsharp.so'))</MLXSharpLinuxNativeDestination>
2836
<MLXSharpSkipLinuxNativeValidation Condition="'$(MLXSharpSkipLinuxNativeValidation)' == ''">false</MLXSharpSkipLinuxNativeValidation>

0 commit comments

Comments
 (0)