Skip to content
Open
Show file tree
Hide file tree
Changes from 10 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
153 changes: 91 additions & 62 deletions .github/workflows/check-bittensor-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,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 @@ -112,50 +112,86 @@ 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 }}
name: Node • fast-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]
triple: x86_64-unknown-linux-gnu
arch: amd64
runtime: ["fast-runtime", "non-fast-runtime"]

runs-on: ${{ matrix.platform.runner }}

Expand Down Expand Up @@ -186,15 +222,13 @@ jobs:
export PATH="$HOME/.cargo/bin:$PATH"
export CARGO_BUILD_TARGET="${{ matrix.platform.triple }}"

if [ "${{ matrix.runtime }}" = "fast-runtime" ]; then
./scripts/localnet.sh --build-only
else
./scripts/localnet.sh False --build-only
fi
# Historical Python E2Es used Docker's default `True`, so this
# migration intentionally validates the same fast-runtime localnet.
./scripts/localnet.sh --build-only
Comment thread
UnArbosSix marked this conversation as resolved.
Outdated

- name: Prepare artifacts for upload
run: |
RUNTIME="${{ matrix.runtime }}"
RUNTIME="fast-runtime"
TRIPLE="${{ matrix.platform.triple }}"

BINARY_PATH="target/${RUNTIME}/${TRIPLE}/release/node-subtensor"
Expand All @@ -221,7 +255,7 @@ jobs:
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: binaries-${{ matrix.platform.triple }}-${{ matrix.runtime }}
name: binaries-${{ matrix.platform.triple }}-fast-runtime
path: build/
if-no-files-found: error

Expand Down Expand Up @@ -254,7 +288,7 @@ jobs:
docker info | grep "Docker Root Dir"

- name: Build Docker Image
run: docker build -f Dockerfile-localnet --build-arg BUILT_IN_CI="Boom shakalaka" -t localnet .
run: docker build -f sdk/bittensor-core/tests/Dockerfile.localnet-fast -t localnet .

- name: Save Docker Image as Tar
run: docker save -o /mnt/data/subtensor-localnet.tar localnet
Expand All @@ -269,6 +303,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 @@ -279,23 +314,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 @@ -306,27 +331,31 @@ 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
TEST_NAME: ${{ matrix.test }}
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 $TEST_NAME"
rust-e2e/bittensor-core-e2e \
"$TEST_NAME" \
--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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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),
}
}
8 changes: 8 additions & 0 deletions sdk/bittensor-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ license = "Apache-2.0"
name = "bittensor_core"
crate-type = ["rlib"]

# External localnet suite. It is selected explicitly by the dedicated E2E
# workflow; `test = false` keeps ordinary workspace/nextest runs unit-only.
[[test]]
name = "e2e"
path = "tests/e2e.rs"
test = false

[dependencies]
# keys / keyfiles (absorbed from py-sp-core)
ansible-vault = "0.2.1"
Expand Down Expand Up @@ -63,6 +70,7 @@ merkleized-metadata = "0.5.1"
# workers (codec/batch.rs).
rayon = "1.10"
scale-info = { workspace = true, features = ["std", "serde"] }
subtensor-macros = { workspace = true }

# signers (feature "ledger"): APDU types for the Polkadot generic app; the
# HID transport itself lives in signers/ledger.rs on top of hidapi (below).
Expand Down
Loading
Loading