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
29 changes: 5 additions & 24 deletions .github/workflows/code-verify.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,14 @@ env:
jobs:
ci:
name: Code Verify
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
rust: [stable]
os: [ubuntu-latest]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install rust
uses: actions-rs/toolchain@v1
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ matrix.rust }}
profile: minimal
override: true
toolchain: stable
components: rustfmt, clippy
- name: Install gRPC
run: |
Expand All @@ -28,17 +21,5 @@ jobs:
run: cargo fmt --all -- --check
- name: Cargo clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Cargo build
run: cargo build --release
- name: Cargo test
run: cargo test --workspace --exclude flame-rs --exclude cri-rs
- name: Install cargo-tarpaulin
run: cargo install cargo-tarpaulin
- name: Generate coverage report
run: cargo tarpaulin --workspace --exclude flame-rs --exclude cri-rs --exclude candle-based-example --out xml --output-dir coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: coverage/cobertura.xml
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
4 changes: 2 additions & 2 deletions .github/workflows/e2e-bm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,13 @@ jobs:
echo "=== Verify object cache is accessible ==="
curl -s http://127.0.0.1:9090/ || echo "Note: Object cache gRPC endpoint (expected no HTTP response)"

- name: Run test_runner
- name: Run Python E2E tests
timeout-minutes: 20
run: |
export PYTHONPATH="$(pwd)/e2e/src:$PYTHONPATH"
export FLAME_LOG=DEBUG
cd e2e
pytest -vv --durations=0 tests/test_runner.py
pytest -vv --durations=0 tests/test_runner.py tests/test_flmexec.py

- name: Show service logs on failure
if: failure() || cancelled()
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.

6 changes: 5 additions & 1 deletion compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ services:
- ./ci/certs:/etc/flame/certs:ro
- ./examples:/opt/examples
- ./e2e:/opt/e2e
- flame-work:/usr/local/flame/work
- type: volume
source: flame-work
target: /usr/local/flame/work
volume:
nocopy: true
- ./logs:/usr/local/flame/logs
- ./work/cache:/usr/local/flame/data/cache
networks:
Expand Down
91 changes: 91 additions & 0 deletions e2e/tests/test_flmexec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""
Copyright 2025 The Flame Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

import json
import textwrap

import flamepy
import pytest

RESULT_PREFIX = "FLMEXEC_RUNNER_NUMPY_RESULT="


@pytest.fixture(scope="module")
def check_flmexec_runner_environment():
context = flamepy.FlameContext()
package_config = getattr(context, "package", None)
cache_config = getattr(context, "cache", None)
has_package_storage = package_config is not None and getattr(package_config, "storage", None) is not None
has_cache_endpoint = cache_config is not None
if not has_package_storage and not has_cache_endpoint:
pytest.skip("Runner package storage is not configured")

try:
if flamepy.get_application("flmexec") is None:
pytest.skip("flmexec application is not registered")
if flamepy.get_application("flmrun") is None:
pytest.skip("flmrun application is not registered")
except Exception as exc:
pytest.skip(f"Flame cluster is not available: {exc}")


@pytest.mark.timeout(600)
def test_flmexec_python_script_starts_runner_with_numpy_dependency(check_flmexec_runner_environment):
script = textwrap.dedent(
f"""
import json
import sys
import traceback
import uuid

try:
from flamepy.runner import Runner

def numpy_summary(limit):
import numpy as np

values = np.arange(1, limit + 1, dtype=np.int64)
return {{
"dtype": str(values.dtype),
"shape": list(values.shape),
"sum": int(values.sum()),
}}

app_name = f"test-flmexec-runner-numpy-{{uuid.uuid4().hex[:8]}}"

with Runner(app_name, dependencies=["numpy"]) as rr:
service = rr.service(numpy_summary)
result = service(5).get()

print("{RESULT_PREFIX}" + json.dumps(result, sort_keys=True))
except BaseException:
traceback.print_exc(file=sys.stdout)
sys.stdout.flush()
raise
"""
)

session = flamepy.create_session("flmexec")
try:
request = {"language": "python", "code": script, "input": None}
raw_response = session.invoke(json.dumps(request).encode("utf-8"))
finally:
session.close()

response = json.loads(raw_response.decode("utf-8"))
output = bytes(response["data"]).decode("utf-8")
result_line = next((line for line in output.splitlines() if line.startswith(RESULT_PREFIX)), None)
assert result_line is not None, f"missing result line in flmexec output:\n{output}"

result = json.loads(result_line.removeprefix(RESULT_PREFIX))
assert result == {"dtype": "int64", "shape": [5], "sum": 15}
3 changes: 3 additions & 0 deletions flmexec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ clap = { workspace = true }
indicatif = {version = "*", features = ["rayon"]}
rand = { workspace = true }

[dev-dependencies]
tempfile = { workspace = true }

[[bin]]
name = "flmexec"
path = "src/client.rs"
Expand Down
Loading
Loading