154 lines
4.3 KiB
Rust
154 lines
4.3 KiB
Rust
use std::collections::VecDeque;
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use serde_json::json;
|
|
use sgclaw::browser::bridge_contract::{
|
|
BridgeBrowserActionError, BridgeBrowserActionReply, BridgeBrowserActionRequest,
|
|
BridgeBrowserActionSuccess,
|
|
};
|
|
use sgclaw::browser::bridge_transport::BridgeActionTransport;
|
|
use sgclaw::browser::{BridgeBrowserBackend, BrowserBackend};
|
|
use sgclaw::pipe::{Action, PipeError, Timing};
|
|
use sgclaw::security::MacPolicy;
|
|
|
|
fn test_policy() -> MacPolicy {
|
|
MacPolicy::from_json_str(
|
|
r#"{
|
|
"version": "1.0",
|
|
"domains": { "allowed": ["www.baidu.com"] },
|
|
"pipe_actions": {
|
|
"allowed": ["click", "type", "navigate", "getText", "eval"],
|
|
"blocked": []
|
|
}
|
|
}"#,
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
struct FakeBridgeTransport {
|
|
requests: Mutex<Vec<BridgeBrowserActionRequest>>,
|
|
replies: Mutex<VecDeque<Result<BridgeBrowserActionReply, PipeError>>>,
|
|
}
|
|
|
|
impl FakeBridgeTransport {
|
|
fn new(replies: Vec<Result<BridgeBrowserActionReply, PipeError>>) -> Self {
|
|
Self {
|
|
requests: Mutex::new(Vec::new()),
|
|
replies: Mutex::new(replies.into()),
|
|
}
|
|
}
|
|
|
|
fn recorded_requests(&self) -> Vec<BridgeBrowserActionRequest> {
|
|
self.requests.lock().unwrap().clone()
|
|
}
|
|
}
|
|
|
|
impl BridgeActionTransport for FakeBridgeTransport {
|
|
fn execute(
|
|
&self,
|
|
request: BridgeBrowserActionRequest,
|
|
) -> Result<BridgeBrowserActionReply, PipeError> {
|
|
self.requests.lock().unwrap().push(request);
|
|
self.replies
|
|
.lock()
|
|
.unwrap()
|
|
.pop_front()
|
|
.unwrap_or(Err(PipeError::Timeout))
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn bridge_backend_maps_navigate_to_bridge_action_request() {
|
|
let transport = Arc::new(FakeBridgeTransport::new(vec![Ok(
|
|
BridgeBrowserActionReply::Success(BridgeBrowserActionSuccess {
|
|
data: json!({ "navigated": true }),
|
|
aom_snapshot: vec![],
|
|
timing: Timing {
|
|
queue_ms: 1,
|
|
exec_ms: 11,
|
|
},
|
|
}),
|
|
)]));
|
|
let backend = BridgeBrowserBackend::new(transport.clone(), test_policy());
|
|
|
|
let output = backend
|
|
.invoke(
|
|
Action::Navigate,
|
|
json!({ "url": "https://www.baidu.com" }),
|
|
"www.baidu.com",
|
|
)
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
transport.recorded_requests(),
|
|
vec![BridgeBrowserActionRequest::new(
|
|
"navigate",
|
|
json!({ "url": "https://www.baidu.com" }),
|
|
"www.baidu.com",
|
|
)]
|
|
);
|
|
assert_eq!(output.seq, 1);
|
|
assert!(output.success);
|
|
}
|
|
|
|
#[test]
|
|
fn bridge_backend_normalizes_successful_bridge_reply() {
|
|
let transport = Arc::new(FakeBridgeTransport::new(vec![Ok(
|
|
BridgeBrowserActionReply::Success(BridgeBrowserActionSuccess {
|
|
data: json!({ "text": "天气" }),
|
|
aom_snapshot: vec![json!({ "role": "textbox", "name": "百度一下" })],
|
|
timing: Timing {
|
|
queue_ms: 4,
|
|
exec_ms: 14,
|
|
},
|
|
}),
|
|
)]));
|
|
let backend = BridgeBrowserBackend::new(transport, test_policy());
|
|
|
|
let output = backend
|
|
.invoke(
|
|
Action::GetText,
|
|
json!({ "selector": "#content_left" }),
|
|
"www.baidu.com",
|
|
)
|
|
.unwrap();
|
|
|
|
assert_eq!(output.seq, 1);
|
|
assert!(output.success);
|
|
assert_eq!(output.data, json!({ "text": "天气" }));
|
|
assert_eq!(
|
|
output.aom_snapshot,
|
|
vec![json!({ "role": "textbox", "name": "百度一下" })]
|
|
);
|
|
assert_eq!(
|
|
output.timing,
|
|
Timing {
|
|
queue_ms: 4,
|
|
exec_ms: 14,
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn bridge_backend_maps_bridge_failure_to_pipe_error() {
|
|
let transport = Arc::new(FakeBridgeTransport::new(vec![Ok(
|
|
BridgeBrowserActionReply::Error(BridgeBrowserActionError {
|
|
message: "selector not found".to_string(),
|
|
details: json!({ "selector": "#missing" }),
|
|
}),
|
|
)]));
|
|
let backend = BridgeBrowserBackend::new(transport, test_policy());
|
|
|
|
let error = backend
|
|
.invoke(
|
|
Action::Click,
|
|
json!({ "selector": "#missing" }),
|
|
"www.baidu.com",
|
|
)
|
|
.unwrap_err();
|
|
|
|
assert!(
|
|
matches!(error, PipeError::Protocol(message) if message == "bridge action failed: selector not found")
|
|
);
|
|
}
|