Files
dev/code-rs/app-server/tests/binary_smoke.rs
T
zeekayandHanzo Dev 6cbbea2d03 merge: just-every/code v0.6.169 (e4fe007150) — keep Hanzo identity
Our history is just-every's with author emails rewritten, so the graphs are
disjoint and git finds no merge base. Supplied one by hand: d1f1f51a41, the
just-every commit matching our Oct-2025 fork point (22 files apart). 9618
upstream commits, 7004 files, +1.81M/-159k, 37 conflicts.

Resolution:
- Upstream code where our side was the Oct-2025 prototype of a feature they
  have since reimplemented 3-5x larger (agent_runs, browser_sessions,
  history_cell/{agent,browser}, the vt100 harness and its snapshots).
- Upstream's config.rs module split (builder/defaults/sources/validation)
  kept; zen5-coder and the provider-follows-model rule re-applied on top.
- Ours where the file IS the identity: README, package.json, postinstall,
  release notes pipeline, integration-zed.
- Hybrid where upstream improved a file we had branded: updates.rs (their
  release-repo migration, our hanzoai/dev), release.yml (their fail-fast npm
  auth check, our package name), chatwidget.rs (their turn handling, our
  HANZO_USER_KEY hint), exec human output (their 237 lines, our banner).

Superseded and dropped deliberately: our resume_command_name() coder-alias
hack — upstream's derive_resume_command_name() reads the invocation basename
generically, which yields "dev" for us.

LLM.md now records the real topology and the sync point; AGENTS.md and
CLAUDE.md are symlinks to it again. Single parent on purpose: adopting
jecode/main as a second parent would re-import 13,742 commits carrying the
upstream author emails a prior rewrite deliberately removed.

Version 0.2.188 -> 0.2.189.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-05 23:09:12 -07:00

125 lines
3.9 KiB
Rust

use std::collections::BTreeMap;
use std::path::PathBuf;
use std::process::Command;
use std::process::Stdio;
use serde_json::Value;
use serde_json::json;
fn app_server_bin() -> PathBuf {
PathBuf::from(assert_cmd::cargo::cargo_bin!("code-app-server"))
}
fn run_jsonrpc_script(requests: &[Value]) -> BTreeMap<i64, Value> {
let mut child = Command::new(app_server_bin())
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("failed to spawn code-app-server");
let mut stdin = child.stdin.take().expect("child stdin is not piped");
for request in requests {
let line = serde_json::to_string(request).expect("request must be valid JSON");
use std::io::Write as _;
writeln!(stdin, "{line}").expect("failed to write JSON-RPC request line");
}
drop(stdin);
let output = child
.wait_with_output()
.expect("failed waiting for code-app-server output");
assert!(
output.status.success(),
"code-app-server exited with {status}; stderr:\n{stderr}",
status = output.status,
stderr = String::from_utf8_lossy(&output.stderr)
);
String::from_utf8_lossy(&output.stdout)
.lines()
.map(|line| {
let message: Value = serde_json::from_str(line)
.unwrap_or_else(|e| panic!("invalid JSON-RPC line `{line}`: {e}"));
let id = message
.get("id")
.and_then(Value::as_i64)
.unwrap_or_else(|| panic!("JSON-RPC message missing numeric id: {message}"));
(id, message)
})
.collect()
}
#[test]
fn binary_smoke_requires_init_and_executes_command() {
let marker = "hello-from-app-server-binary-smoke";
let requests = vec![
json!({"jsonrpc":"2.0","id":1,"method":"getUserAgent"}),
json!({
"jsonrpc":"2.0",
"id":2,
"method":"initialize",
"params":{
"clientInfo":{
"name":"app-server-binary-smoke",
"version":"0.1.0"
}
}
}),
json!({"jsonrpc":"2.0","id":3,"method":"getUserAgent"}),
json!({
"jsonrpc":"2.0",
"id":4,
"method":"execOneOffCommand",
"params":{
"command":["bash","-lc", format!("echo {marker}")],
"timeoutMs":5000
}
}),
];
let responses = run_jsonrpc_script(&requests);
let pre_init_error = responses
.get(&1)
.and_then(|v| v.get("error"))
.and_then(|v| v.get("message"))
.and_then(Value::as_str)
.expect("expected error response for pre-initialize getUserAgent");
assert!(
pre_init_error.contains("Not initialized"),
"unexpected pre-init error message: {pre_init_error}"
);
let user_agent = responses
.get(&3)
.and_then(|v| v.get("result"))
.and_then(|v| v.get("userAgent"))
.and_then(Value::as_str)
.expect("expected getUserAgent response after initialize");
assert!(
user_agent.contains("(app-server-binary-smoke; 0.1.0)"),
"user agent did not include initialize client info: {user_agent}"
);
let exec_result = responses
.get(&4)
.and_then(|v| v.get("result"))
.expect("expected execOneOffCommand response");
let exit_code = exec_result
.get("exitCode")
.and_then(Value::as_i64)
.expect("execOneOffCommand result missing exitCode");
let stdout = exec_result
.get("stdout")
.and_then(Value::as_str)
.expect("execOneOffCommand result missing stdout");
assert_eq!(exit_code, 0, "execOneOffCommand returned non-zero exit");
assert!(
stdout.contains(marker),
"execOneOffCommand stdout missing marker. stdout was: {stdout}"
);
}