fix(ci): use Windows-compatible Torrent RPC integration test

This commit is contained in:
NimBold
2026-08-01 20:09:57 +03:30
parent 92092e9844
commit bb64c4cd52
5 changed files with 106 additions and 12 deletions
-4
View File
@@ -71,10 +71,6 @@ jobs:
run: |
cargo test --tests --target ${{ matrix.target }}
cargo test --lib --no-run --target ${{ matrix.target }}
- name: Test Torrent RPC harness on Windows
if: runner.os == 'Windows'
working-directory: src-tauri
run: cargo test torrent_probe::tests::http_rpc_harness --target ${{ matrix.target }} -- --nocapture
- name: Provision locked engines
if: runner.os != 'macOS'
run: node scripts/provision-engines.js --target ${{ matrix.target }}
+1 -1
View File
@@ -35,7 +35,7 @@
"check:updates": "node scripts/check-updates.js",
"smoke:torrent": "node scripts/smoke-torrent.js",
"smoke:torrent:failure-paths": "node scripts/smoke-torrent.js --failure-paths",
"test:torrent:rpc": "cd src-tauri && cargo test torrent_probe::tests::http_rpc_harness -- --nocapture",
"test:torrent:rpc": "cd src-tauri && cargo test --test torrent_rpc -- --nocapture",
"verify:macos-signing": "node scripts/verify-macos-signing.js",
"preview": "vite preview",
"tauri": "tauri",
+2 -1
View File
@@ -3235,7 +3235,8 @@ fn dispatch_deep_links(app_handle: tauri::AppHandle, deep_links: Vec<url::Url>)
});
}
pub(crate) async fn rpc_call(
#[doc(hidden)]
pub async fn rpc_call(
port: u16,
secret: &str,
method: &str,
+7 -6
View File
@@ -36,9 +36,9 @@ npm run smoke:torrent
Use `node scripts/smoke-torrent.js --binary /path/to/aria2c` when validating a
packaged or target-specific Aria2 binary.
Run the HTTP-boundary Torrent probe harness with a controllable local JSON-RPC
server. It drives the production Aria2 RPC client through scripted status,
outage, race, cancellation, and daemon-termination cases:
Run the HTTP-boundary Torrent RPC integration test. It drives the production
Aria2 RPC client through a local JSON-RPC server and verifies successful
requests plus HTTP gateway errors:
```sh
npm run test:torrent:rpc
@@ -51,6 +51,7 @@ npm run smoke:torrent:failure-paths
```
Native CI runs this failure-path smoke after staging the target-specific
bundled engines on macOS, Windows, and Linux. Windows also runs the filtered
HTTP-boundary RPC harness explicitly because its general Rust job compiles the
library tests without executing them.
bundled engines on macOS, Windows, and Linux. Windows runs this RPC
integration test through its target-qualified `cargo test --tests` step;
the general Rust job compiles the library tests without executing the
known-broken Tauri library harness.
+96
View File
@@ -0,0 +1,96 @@
use axum::{extract::Json, http::StatusCode, response::IntoResponse, routing::post, Router};
use firelink_lib::rpc_call;
use serde_json::{json, Value};
use std::net::SocketAddr;
use tokio::sync::oneshot;
async fn start_server(
app: Router,
) -> (SocketAddr, oneshot::Sender<()>, tokio::task::JoinHandle<()>) {
let listener = tokio::net::TcpListener::bind(("127.0.0.1", 0))
.await
.expect("RPC test server should bind");
let address = listener
.local_addr()
.expect("RPC test server should have an address");
let (shutdown, shutdown_signal) = oneshot::channel();
let task = tokio::spawn(async move {
axum::serve(listener, app)
.with_graceful_shutdown(async {
let _ = shutdown_signal.await;
})
.await
.expect("RPC test server should stop cleanly");
});
(address, shutdown, task)
}
struct TestResponse(StatusCode, Value);
impl IntoResponse for TestResponse {
fn into_response(self) -> axum::response::Response {
(self.0, Json(self.1)).into_response()
}
}
async fn successful_rpc(Json(request): Json<Value>) -> TestResponse {
assert_eq!(request.get("jsonrpc"), Some(&json!("2.0")));
assert_eq!(request.get("id"), Some(&json!("1")));
assert_eq!(request.get("method"), Some(&json!("aria2.getVersion")));
assert_eq!(
request.get("params"),
Some(&json!(["token:test-secret", {"include": "version"}]))
);
TestResponse(
StatusCode::OK,
json!({"jsonrpc": "2.0", "id": "1", "result": {"version": "test"}}),
)
}
async fn gateway_error(Json(_request): Json<Value>) -> TestResponse {
TestResponse(
StatusCode::BAD_GATEWAY,
json!({"jsonrpc": "2.0", "id": "1", "error": {"code": 1, "message": "backend unavailable"}}),
)
}
async fn stop_server(shutdown: oneshot::Sender<()>, task: tokio::task::JoinHandle<()>) {
let _ = shutdown.send(());
task.await.expect("RPC test server task should join");
}
#[tokio::test]
async fn production_rpc_client_sends_authenticated_json_rpc() {
let app = Router::new().route("/jsonrpc", post(successful_rpc));
let (address, shutdown, task) = start_server(app).await;
let result = rpc_call(
address.port(),
"test-secret",
"aria2.getVersion",
json!([{"include": "version"}]),
)
.await
.expect("successful RPC response should decode");
assert_eq!(result, json!({"version": "test"}));
stop_server(shutdown, task).await;
}
#[tokio::test]
async fn production_rpc_client_preserves_http_gateway_context() {
let app = Router::new().route("/jsonrpc", post(gateway_error));
let (address, shutdown, task) = start_server(app).await;
let error = rpc_call(address.port(), "test-secret", "aria2.getVersion", json!([]))
.await
.expect_err("gateway response should fail");
assert!(
error.contains("HTTP 502 Bad Gateway"),
"unexpected error: {error}"
);
assert!(
error.contains("backend unavailable"),
"unexpected error: {error}"
);
stop_server(shutdown, task).await;
}