mirror of
https://github.com/nimbold/Firelink.git
synced 2026-08-27 19:17:13 +00:00
fix(ci): use Windows-compatible Torrent RPC integration test
This commit is contained in:
@@ -71,10 +71,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cargo test --tests --target ${{ matrix.target }}
|
cargo test --tests --target ${{ matrix.target }}
|
||||||
cargo test --lib --no-run --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
|
- name: Provision locked engines
|
||||||
if: runner.os != 'macOS'
|
if: runner.os != 'macOS'
|
||||||
run: node scripts/provision-engines.js --target ${{ matrix.target }}
|
run: node scripts/provision-engines.js --target ${{ matrix.target }}
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@
|
|||||||
"check:updates": "node scripts/check-updates.js",
|
"check:updates": "node scripts/check-updates.js",
|
||||||
"smoke:torrent": "node scripts/smoke-torrent.js",
|
"smoke:torrent": "node scripts/smoke-torrent.js",
|
||||||
"smoke:torrent:failure-paths": "node scripts/smoke-torrent.js --failure-paths",
|
"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",
|
"verify:macos-signing": "node scripts/verify-macos-signing.js",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"tauri": "tauri",
|
"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,
|
port: u16,
|
||||||
secret: &str,
|
secret: &str,
|
||||||
method: &str,
|
method: &str,
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ npm run smoke:torrent
|
|||||||
Use `node scripts/smoke-torrent.js --binary /path/to/aria2c` when validating a
|
Use `node scripts/smoke-torrent.js --binary /path/to/aria2c` when validating a
|
||||||
packaged or target-specific Aria2 binary.
|
packaged or target-specific Aria2 binary.
|
||||||
|
|
||||||
Run the HTTP-boundary Torrent probe harness with a controllable local JSON-RPC
|
Run the HTTP-boundary Torrent RPC integration test. It drives the production
|
||||||
server. It drives the production Aria2 RPC client through scripted status,
|
Aria2 RPC client through a local JSON-RPC server and verifies successful
|
||||||
outage, race, cancellation, and daemon-termination cases:
|
requests plus HTTP gateway errors:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm run test:torrent:rpc
|
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
|
Native CI runs this failure-path smoke after staging the target-specific
|
||||||
bundled engines on macOS, Windows, and Linux. Windows also runs the filtered
|
bundled engines on macOS, Windows, and Linux. Windows runs this RPC
|
||||||
HTTP-boundary RPC harness explicitly because its general Rust job compiles the
|
integration test through its target-qualified `cargo test --tests` step;
|
||||||
library tests without executing them.
|
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