Skip to content
Open
135 changes: 83 additions & 52 deletions .github/workflows/check-bittensor-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ on:
env:
CARGO_TERM_COLOR: always
VERBOSE: ${{ github.event.inputs.verbose }}
# The in-repo SDK e2e harness reads LOCALNET_IMAGE from the environment.
LOCALNET_IMAGE: ghcr.io/raofoundation/subtensor-localnet:ci
# The in-repo Rust SDK e2e harness reads LOCALNET_IMAGE_NAME.
LOCALNET_IMAGE_NAME: ghcr.io/raofoundation/subtensor-localnet:ci

jobs:
trusted-pr:
Expand Down Expand Up @@ -88,44 +88,81 @@ jobs:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || github.ref_name }}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Verify the Rust e2e migration manifest
id: get-tests
shell: bash
run: |
set -euo pipefail
manifest=sdk/bittensor-core/tests/e2e-manifest.json
jq -e 'length == 113' "$manifest" >/dev/null
jq -e 'map(.label) | length == (unique | length)' "$manifest" >/dev/null
jq -e 'map(.test) | length == (unique | length)' "$manifest" >/dev/null
jq -e 'all(.[]; (.label | startswith("test_")) and ((.test | startswith("intent_")) or (.test | startswith("test_"))))' "$manifest" >/dev/null
test_matrix=$(jq -c . "$manifest")
echo "Found $(jq length "$manifest") migrated Rust e2e tests"
echo "test-files=$test_matrix" >> "$GITHUB_OUTPUT"

- name: Install uv
uses: astral-sh/setup-uv@v5
build-rust-e2e-test-binary:
needs: [check-label, find-e2e-tests]
if: needs.check-label.outputs.skip-bittensor-e2e-tests == 'false'
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
enable-cache: "false"
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || github.ref_name }}

- name: Collect in-repo SDK e2e tests
id: get-tests
working-directory: sdk/python
- name: Install Rust + build dependencies
run: |
chmod +x ./scripts/install_build_env.sh
./scripts/install_build_env.sh

- name: Compile once and prove manifest completeness
shell: bash
run: |
set -euo pipefail
uv sync --locked --all-extras --dev
test_matrix=$(
uv run pytest -q --collect-only -m e2e \
| sed -n '/^tests\/e2e\//p' \
| jq -R -s -c '
split("\n")
| map(select(. != ""))
| map({nodeid: ., label: (sub("^tests/e2e/"; "") | sub("\\.py$"; ""))})
'
source "$HOME/.cargo/env"
mkdir -p build/rust-e2e
# The workspace/localnet build also compiles the Python binding. Keep
# CoreError/API compatibility in this faster job so failures surface
# before the expensive node builds.
cargo check -p bittensor-core-py
cargo test -p bittensor-core --test e2e --no-run --message-format=json \
> build/rust-e2e/cargo-messages.json
executable=$(
jq -r '
select(.reason == "compiler-artifact")
| select(.target.name == "e2e")
| select(.target.kind | index("test"))
| .executable // empty
' build/rust-e2e/cargo-messages.json | tail -n 1
)
echo "Found tests: $test_matrix"
if [ "$test_matrix" = "[]" ] || [ -z "$test_matrix" ]; then
echo "No e2e tests found — failing."
exit 1
fi
echo "test-files=$test_matrix" >> "$GITHUB_OUTPUT"
shell: bash
test -n "$executable"
cp "$executable" build/rust-e2e/bittensor-core-e2e
chmod +x build/rust-e2e/bittensor-core-e2e

jq -r '.[].test' sdk/bittensor-core/tests/e2e-manifest.json \
| sort > build/rust-e2e/expected-tests.txt
build/rust-e2e/bittensor-core-e2e --list --format terse \
| sed -n 's/: test$//p' \
| sort > build/rust-e2e/compiled-tests.txt
diff -u build/rust-e2e/expected-tests.txt build/rust-e2e/compiled-tests.txt

- name: Upload compiled Rust e2e binary
uses: actions/upload-artifact@v4
with:
name: bittensor-core-e2e
path: build/rust-e2e/bittensor-core-e2e
if-no-files-found: error

artifacts:
name: Node • ${{ matrix.runtime }} • ${{ matrix.platform.arch }}
needs: [check-label, trusted-pr]
if: needs.check-label.outputs.skip-bittensor-e2e-tests == 'false'
strategy:
fail-fast: false
matrix:
platform:
- runner: [self-hosted, fireactions-heavy]
Expand Down Expand Up @@ -245,6 +282,7 @@ jobs:
needs:
- check-label
- find-e2e-tests
- build-rust-e2e-test-binary
- build-image-with-current-branch
if: needs.check-label.outputs.skip-bittensor-e2e-tests == 'false'
runs-on: ubuntu-latest
Expand All @@ -255,23 +293,13 @@ jobs:
include: ${{ fromJson(needs.find-e2e-tests.outputs.test-files) }}
Comment thread
UnArbosSix marked this conversation as resolved.

timeout-minutes: 60
name: "sdk: ${{ matrix.label }}"
name: "sdk-rust: ${{ matrix.label }}"
steps:
- name: Check-out repository
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
ref: ${{ github.event.pull_request.head.ref || github.ref_name }}

- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Download compiled Rust e2e binary
uses: actions/download-artifact@v4
with:
enable-cache: "false"

- name: Install in-repo SDK
working-directory: sdk/python
run: |
uv sync --locked --all-extras --dev
name: bittensor-core-e2e
path: rust-e2e

- name: Download Cached Docker Image
uses: actions/download-artifact@v4
Expand All @@ -282,27 +310,30 @@ jobs:
run: docker load -i subtensor-localnet.tar

- name: Retag Docker Image
run: docker tag localnet "$LOCALNET_IMAGE"
run: docker tag localnet "$LOCALNET_IMAGE_NAME"

- name: Run with retry
working-directory: sdk/python
env:
SKIP_PULL: 1
RUST_BACKTRACE: 1
run: |
set +e
chmod +x rust-e2e/bittensor-core-e2e
for i in 1 2; do
echo "Attempt $i: Running tests"
# -m e2e overrides the default addopts (-m 'not e2e') which would
# otherwise deselect the collected test and fail with "no tests ran".
uv run pytest "${{ matrix.nodeid }}" -s -m e2e
echo "Attempt $i: Running ${{ matrix.test }}"
rust-e2e/bittensor-core-e2e \
"${{ matrix.test }}" \
Comment thread
UnArbosSix marked this conversation as resolved.
Outdated
--exact \
--nocapture \
--test-threads=1
status=$?
if [ $status -eq 0 ]; then
echo "Tests passed on attempt $i"
echo "Test passed on attempt $i"
break
else
echo "Tests failed on attempt $i"
echo "Test failed on attempt $i"
if [ $i -eq 2 ]; then
echo "Tests failed after 2 attempts"
echo "Test failed after 2 attempts"
exit 1
fi
echo "Retrying..."
Expand Down
4 changes: 3 additions & 1 deletion sdk/bittensor-core-py/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! The one place `CoreError` becomes a Python exception.

use bittensor_core::CoreError;
use pyo3::exceptions::{PyKeyError, PyValueError};
use pyo3::exceptions::{PyConnectionError, PyKeyError, PyPermissionError, PyValueError};
use pyo3::prelude::*;

pyo3::create_exception!(
Expand Down Expand Up @@ -33,5 +33,7 @@ pub fn to_py_err(error: CoreError) -> PyErr {
CoreError::NotInRuntime(what) => PyKeyError::new_err(what),
CoreError::Codec(msg) | CoreError::Crypto(msg) => PyValueError::new_err(msg),
CoreError::Device(msg) => LedgerError::new_err(msg),
CoreError::Rpc(msg) => PyConnectionError::new_err(msg),
CoreError::Policy(msg) => PyPermissionError::new_err(msg),
}
}
Loading
Loading