mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-02 15:39:37 +00:00
fix(ci): use Windows-compatible Torrent RPC integration test
This commit is contained in:
@@ -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
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user