feat: add generated scene skill platform hardening
This commit is contained in:
@@ -12,7 +12,7 @@ use tungstenite::{accept, Message};
|
||||
const RUNTIME_DROP_PANIC_TEXT: &str =
|
||||
"Cannot drop a runtime in a context where blocking is not allowed";
|
||||
|
||||
const TEST_ZHIHU_SKILLS_DIR: &str = "D:/data/ideaSpace/rust/sgClaw/claw/claw/skills";
|
||||
const TEST_ZHIHU_SKILLS_DIR: &str = "D:/data/ideaSpace/rust/sgClaw/claw/claw/skills";
|
||||
|
||||
fn read_ws_text(stream: &mut tungstenite::WebSocket<std::net::TcpStream>) -> String {
|
||||
match stream.read().unwrap() {
|
||||
@@ -117,8 +117,12 @@ fn start_callback_host_hotlist_browser_server(
|
||||
|
||||
let handle = thread::spawn(move || {
|
||||
let (stream, _) = listener.accept().unwrap();
|
||||
stream.set_read_timeout(Some(Duration::from_secs(2))).unwrap();
|
||||
stream.set_write_timeout(Some(Duration::from_secs(2))).unwrap();
|
||||
stream
|
||||
.set_read_timeout(Some(Duration::from_secs(2)))
|
||||
.unwrap();
|
||||
stream
|
||||
.set_write_timeout(Some(Duration::from_secs(2)))
|
||||
.unwrap();
|
||||
let mut websocket = accept(stream).unwrap();
|
||||
|
||||
let register = match websocket.read().unwrap() {
|
||||
@@ -149,7 +153,9 @@ fn start_callback_host_hotlist_browser_server(
|
||||
other => panic!("expected second browser action frame, got {other:?}"),
|
||||
};
|
||||
event_tx
|
||||
.send(CallbackHostBrowserEvent::BrowserFrame(second_action.clone()))
|
||||
.send(CallbackHostBrowserEvent::BrowserFrame(
|
||||
second_action.clone(),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let Some(close_values) = first_action.as_array() else {
|
||||
@@ -328,7 +334,8 @@ fn start_callback_host_hotlist_browser_server(
|
||||
(format!("ws://{address}"), handle)
|
||||
}
|
||||
|
||||
fn start_direct_zhihu_browser_ws_server() -> (String, Arc<Mutex<Vec<String>>>, thread::JoinHandle<()>) {
|
||||
fn start_direct_zhihu_browser_ws_server(
|
||||
) -> (String, Arc<Mutex<Vec<String>>>, thread::JoinHandle<()>) {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let address = listener.local_addr().unwrap();
|
||||
let frames = Arc::new(Mutex::new(Vec::new()));
|
||||
@@ -336,8 +343,12 @@ fn start_direct_zhihu_browser_ws_server() -> (String, Arc<Mutex<Vec<String>>>, t
|
||||
|
||||
let handle = thread::spawn(move || {
|
||||
let (stream, _) = listener.accept().unwrap();
|
||||
stream.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
|
||||
stream.set_write_timeout(Some(Duration::from_secs(5))).unwrap();
|
||||
stream
|
||||
.set_read_timeout(Some(Duration::from_secs(5)))
|
||||
.unwrap();
|
||||
stream
|
||||
.set_write_timeout(Some(Duration::from_secs(5)))
|
||||
.unwrap();
|
||||
let mut socket = accept(stream).unwrap();
|
||||
let mut action_count = 0_u64;
|
||||
|
||||
@@ -364,7 +375,9 @@ fn start_direct_zhihu_browser_ws_server() -> (String, Arc<Mutex<Vec<String>>>, t
|
||||
continue;
|
||||
}
|
||||
|
||||
let values = parsed.as_array().expect("browser action frame should be an array");
|
||||
let values = parsed
|
||||
.as_array()
|
||||
.expect("browser action frame should be an array");
|
||||
let request_url = values[0].as_str().expect("request_url should be a string");
|
||||
let action = values[1].as_str().expect("action should be a string");
|
||||
action_count += 1;
|
||||
@@ -380,7 +393,9 @@ fn start_direct_zhihu_browser_ws_server() -> (String, Arc<Mutex<Vec<String>>>, t
|
||||
|
||||
let callback_frame = match action {
|
||||
"sgHideBrowserCallAfterLoaded" => {
|
||||
let target_url = values[2].as_str().expect("navigate target_url should be a string");
|
||||
let target_url = values[2]
|
||||
.as_str()
|
||||
.expect("navigate target_url should be a string");
|
||||
json!([
|
||||
request_url,
|
||||
"callBackJsToCpp",
|
||||
@@ -390,7 +405,9 @@ fn start_direct_zhihu_browser_ws_server() -> (String, Arc<Mutex<Vec<String>>>, t
|
||||
])
|
||||
}
|
||||
"sgBrowserExcuteJsCodeByArea" => {
|
||||
let target_url = values[2].as_str().expect("script target_url should be a string");
|
||||
let target_url = values[2]
|
||||
.as_str()
|
||||
.expect("script target_url should be a string");
|
||||
let response_text = if action_count == 2 {
|
||||
"知乎热榜\n1 问题一 344万热度\n2 问题二 266万热度".to_string()
|
||||
} else {
|
||||
@@ -534,7 +551,10 @@ fn client_sends_connect_request_and_exits_after_status() {
|
||||
assert!(output.status.success());
|
||||
assert_eq!(request, ClientMessage::Connect);
|
||||
let stdout = String::from_utf8(output.stdout).unwrap();
|
||||
assert_eq!(stdout.lines().collect::<Vec<_>>(), vec!["status: connected"]);
|
||||
assert_eq!(
|
||||
stdout.lines().collect::<Vec<_>>(),
|
||||
vec!["status: connected"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -603,7 +623,10 @@ fn client_prints_completion_only_once() {
|
||||
let mut websocket = accept(stream).unwrap();
|
||||
let payload = read_ws_text(&mut websocket);
|
||||
let request: ClientMessage = serde_json::from_str(&payload).unwrap();
|
||||
assert_eq!(request.into_submit_task_request().unwrap().instruction, "打开百度搜索天气");
|
||||
assert_eq!(
|
||||
request.into_submit_task_request().unwrap().instruction,
|
||||
"打开百度搜索天气"
|
||||
);
|
||||
|
||||
websocket
|
||||
.send(Message::Text(
|
||||
@@ -663,7 +686,10 @@ fn client_prints_log_entries_in_order_before_completion() {
|
||||
let mut websocket = accept(stream).unwrap();
|
||||
let payload = read_ws_text(&mut websocket);
|
||||
let request: ClientMessage = serde_json::from_str(&payload).unwrap();
|
||||
assert_eq!(request.into_submit_task_request().unwrap().instruction, "打开百度搜索天气");
|
||||
assert_eq!(
|
||||
request.into_submit_task_request().unwrap().instruction,
|
||||
"打开百度搜索天气"
|
||||
);
|
||||
|
||||
for message in [
|
||||
ServiceMessage::LogEntry {
|
||||
@@ -680,7 +706,9 @@ fn client_prints_log_entries_in_order_before_completion() {
|
||||
},
|
||||
] {
|
||||
websocket
|
||||
.send(Message::Text(serde_json::to_string(&message).unwrap().into()))
|
||||
.send(Message::Text(
|
||||
serde_json::to_string(&message).unwrap().into(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
websocket.close(None).unwrap();
|
||||
@@ -758,11 +786,15 @@ fn client_exits_with_failure_when_service_disconnects_before_completion() {
|
||||
assert!(!status.success());
|
||||
|
||||
let request = server.join().unwrap();
|
||||
assert_eq!(request.into_submit_task_request().unwrap().instruction, "打开百度搜索天气");
|
||||
assert_eq!(
|
||||
request.into_submit_task_request().unwrap().instruction,
|
||||
"打开百度搜索天气"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn client_to_service_regression_routes_zhihu_through_callback_host_without_invalid_hmac_seed_output() {
|
||||
fn client_to_service_regression_routes_zhihu_through_callback_host_without_invalid_hmac_seed_output(
|
||||
) {
|
||||
let service_listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let service_addr = service_listener.local_addr().unwrap();
|
||||
drop(service_listener);
|
||||
@@ -770,7 +802,8 @@ fn client_to_service_regression_routes_zhihu_through_callback_host_without_inval
|
||||
let (event_tx, event_rx) = mpsc::channel();
|
||||
let (browser_ws_url, browser_server) = start_callback_host_hotlist_browser_server(event_tx);
|
||||
|
||||
let root = std::env::temp_dir().join(format!("sgclaw-service-task-flow-{}", uuid::Uuid::new_v4()));
|
||||
let root =
|
||||
std::env::temp_dir().join(format!("sgclaw-service-task-flow-{}", uuid::Uuid::new_v4()));
|
||||
std::fs::create_dir_all(&root).unwrap();
|
||||
let config_path = root.join("sgclaw_config.json");
|
||||
std::fs::write(
|
||||
@@ -888,7 +921,8 @@ fn client_to_service_regression_routes_zhihu_through_callback_host_without_inval
|
||||
|
||||
let client_stdout = String::from_utf8_lossy(&client_output.stdout).into_owned();
|
||||
let client_stderr = String::from_utf8_lossy(&client_output.stderr).into_owned();
|
||||
let combined_output = format!("{client_stdout}\n{client_stderr}\n{service_stdout}\n{service_stderr}");
|
||||
let combined_output =
|
||||
format!("{client_stdout}\n{client_stderr}\n{service_stdout}\n{service_stderr}");
|
||||
|
||||
let register = match register {
|
||||
CallbackHostBrowserEvent::BrowserFrame(value) => value,
|
||||
@@ -927,13 +961,19 @@ fn client_to_service_regression_routes_zhihu_through_callback_host_without_inval
|
||||
other => panic!("expected open-page command envelope, got {other:?}"),
|
||||
};
|
||||
assert_eq!(open_page["command"]["action"], json!("sgBrowerserOpenPage"));
|
||||
assert_eq!(open_page["command"]["args"][0], json!("https://www.zhihu.com/hot"));
|
||||
assert_eq!(
|
||||
open_page["command"]["args"][0],
|
||||
json!("https://www.zhihu.com/hot")
|
||||
);
|
||||
|
||||
let get_text = match get_text {
|
||||
CallbackHostBrowserEvent::CommandEnvelope(value) => value,
|
||||
other => panic!("expected getText command envelope, got {other:?}"),
|
||||
};
|
||||
assert_eq!(get_text["command"]["action"], json!("sgBrowserExcuteJsCodeByDomain"));
|
||||
assert_eq!(
|
||||
get_text["command"]["action"],
|
||||
json!("sgBrowserExcuteJsCodeByDomain")
|
||||
);
|
||||
assert_eq!(get_text["command"]["args"][0], json!("www.zhihu.com"));
|
||||
assert!(get_text["command"]["args"][1]
|
||||
.as_str()
|
||||
@@ -943,15 +983,24 @@ fn client_to_service_regression_routes_zhihu_through_callback_host_without_inval
|
||||
CallbackHostBrowserEvent::CommandEnvelope(value) => value,
|
||||
other => panic!("expected eval command envelope, got {other:?}"),
|
||||
};
|
||||
assert_eq!(eval["command"]["action"], json!("sgBrowserExcuteJsCodeByDomain"));
|
||||
assert_eq!(
|
||||
eval["command"]["action"],
|
||||
json!("sgBrowserExcuteJsCodeByDomain")
|
||||
);
|
||||
assert_eq!(eval["command"]["args"][0], json!("www.zhihu.com"));
|
||||
assert!(eval["command"]["args"][1]
|
||||
.as_str()
|
||||
.is_some_and(|script| script.contains("sgclawOnEval")));
|
||||
|
||||
assert!(client_output.status.success());
|
||||
assert!(client_stdout.contains("已导出并打开知乎热榜 Excel"), "client stdout={client_stdout}");
|
||||
assert!(client_stdout.contains(".xlsx"), "client stdout={client_stdout}");
|
||||
assert!(
|
||||
client_stdout.contains("已导出并打开知乎热榜 Excel"),
|
||||
"client stdout={client_stdout}"
|
||||
);
|
||||
assert!(
|
||||
client_stdout.contains(".xlsx"),
|
||||
"client stdout={client_stdout}"
|
||||
);
|
||||
assert!(
|
||||
!combined_output.contains("invalid hmac seed: session key must not be empty"),
|
||||
"target behavior must avoid the invalid hmac seed failure; combined_output={combined_output}"
|
||||
|
||||
Reference in New Issue
Block a user