test: cover all protocol roundtrips
This commit is contained in:
parent
e49b945259
commit
0d588fb3d9
2 changed files with 674 additions and 4 deletions
|
|
@ -1809,6 +1809,676 @@ pub fn decode_overlay_wire_response(line: &str) -> Result<OverlayWireResponse, C
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::{Map, Value, json};
|
||||
|
||||
const CONTROL_REQUEST_VARIANTS: usize = 122;
|
||||
const CONTROL_RESPONSE_VARIANTS: usize = 114;
|
||||
const PEER_CONTROL_REQUEST_VARIANTS: usize = 19;
|
||||
const PEER_CONTROL_RESPONSE_VARIANTS: usize = 20;
|
||||
const PIPE_WIRE_REQUEST_VARIANTS: usize = 3;
|
||||
const PIPE_WIRE_RESPONSE_VARIANTS: usize = 3;
|
||||
const OVERLAY_WIRE_REQUEST_VARIANTS: usize = 1;
|
||||
const OVERLAY_WIRE_RESPONSE_VARIANTS: usize = 2;
|
||||
|
||||
#[test]
|
||||
fn all_protocol_variants_have_roundtrip_samples() {
|
||||
roundtrip_declared_variants::<ControlRequest>(
|
||||
"ControlRequest",
|
||||
CONTROL_REQUEST_VARIANTS,
|
||||
decode_request,
|
||||
encode_request,
|
||||
);
|
||||
roundtrip_declared_variants::<ControlResponse>(
|
||||
"ControlResponse",
|
||||
CONTROL_RESPONSE_VARIANTS,
|
||||
decode_response,
|
||||
encode_response,
|
||||
);
|
||||
roundtrip_declared_variants::<PeerControlRequest>(
|
||||
"PeerControlRequest",
|
||||
PEER_CONTROL_REQUEST_VARIANTS,
|
||||
decode_peer_request,
|
||||
encode_peer_request,
|
||||
);
|
||||
roundtrip_declared_variants::<PeerControlResponse>(
|
||||
"PeerControlResponse",
|
||||
PEER_CONTROL_RESPONSE_VARIANTS,
|
||||
decode_peer_response,
|
||||
encode_peer_response,
|
||||
);
|
||||
roundtrip_declared_variants::<PipeWireRequest>(
|
||||
"PipeWireRequest",
|
||||
PIPE_WIRE_REQUEST_VARIANTS,
|
||||
decode_pipe_wire_request,
|
||||
encode_pipe_wire_request,
|
||||
);
|
||||
roundtrip_declared_variants::<PipeWireResponse>(
|
||||
"PipeWireResponse",
|
||||
PIPE_WIRE_RESPONSE_VARIANTS,
|
||||
decode_pipe_wire_response,
|
||||
encode_pipe_wire_response,
|
||||
);
|
||||
roundtrip_declared_variants::<OverlayWireRequest>(
|
||||
"OverlayWireRequest",
|
||||
OVERLAY_WIRE_REQUEST_VARIANTS,
|
||||
decode_overlay_wire_request,
|
||||
encode_overlay_wire_request,
|
||||
);
|
||||
roundtrip_declared_variants::<OverlayWireResponse>(
|
||||
"OverlayWireResponse",
|
||||
OVERLAY_WIRE_RESPONSE_VARIANTS,
|
||||
decode_overlay_wire_response,
|
||||
encode_overlay_wire_response,
|
||||
);
|
||||
}
|
||||
|
||||
fn roundtrip_declared_variants<T>(
|
||||
enum_name: &str,
|
||||
expected_count: usize,
|
||||
decode: fn(&str) -> Result<T, ControlError>,
|
||||
encode: fn(&T) -> Result<String, ControlError>,
|
||||
) where
|
||||
T: std::fmt::Debug + PartialEq,
|
||||
{
|
||||
let variants = declared_enum_variants(enum_name);
|
||||
assert_eq!(variants.len(), expected_count, "{enum_name} variant count");
|
||||
|
||||
for variant in variants {
|
||||
let sample = protocol_sample(&variant);
|
||||
let encoded_sample = serde_json::to_string(&sample).expect("sample json");
|
||||
let decoded = decode(&encoded_sample).unwrap_or_else(|err| {
|
||||
panic!("{enum_name}::{} sample decodes: {err}", variant.name)
|
||||
});
|
||||
let encoded = encode(&decoded).unwrap_or_else(|err| {
|
||||
panic!("{enum_name}::{} sample encodes: {err}", variant.name)
|
||||
});
|
||||
let decoded_again = decode(&encoded).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"{enum_name}::{} encoded sample decodes: {err}",
|
||||
variant.name
|
||||
)
|
||||
});
|
||||
assert_eq!(
|
||||
decoded_again, decoded,
|
||||
"{enum_name}::{} roundtrips through line codec",
|
||||
variant.name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EnumVariant {
|
||||
name: String,
|
||||
body: VariantBody,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum VariantBody {
|
||||
Unit,
|
||||
Tuple(String),
|
||||
Struct(Vec<(String, String)>),
|
||||
}
|
||||
|
||||
fn declared_enum_variants(enum_name: &str) -> Vec<EnumVariant> {
|
||||
let source = include_str!("lib.rs");
|
||||
let needle = format!("pub enum {enum_name}");
|
||||
let start = source.find(&needle).expect("enum exists");
|
||||
let after_name = &source[start + needle.len()..];
|
||||
let open = after_name.find('{').expect("enum opens");
|
||||
let block = enum_block(&after_name[open..]);
|
||||
split_top_level(block)
|
||||
.into_iter()
|
||||
.filter_map(|decl| parse_variant_decl(decl.trim()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn enum_block(input: &str) -> &str {
|
||||
let mut depth = 0_i32;
|
||||
let mut start = None;
|
||||
for (idx, ch) in input.char_indices() {
|
||||
match ch {
|
||||
'{' => {
|
||||
depth += 1;
|
||||
if start.is_none() {
|
||||
start = Some(idx + 1);
|
||||
}
|
||||
}
|
||||
'}' => {
|
||||
depth -= 1;
|
||||
if depth == 0 {
|
||||
return &input[start.expect("block start")..idx];
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
panic!("unterminated enum block");
|
||||
}
|
||||
|
||||
fn split_top_level(input: &str) -> Vec<&str> {
|
||||
let mut parts = Vec::new();
|
||||
let mut start = 0;
|
||||
let mut brace_depth = 0_i32;
|
||||
let mut paren_depth = 0_i32;
|
||||
let mut angle_depth = 0_i32;
|
||||
for (idx, ch) in input.char_indices() {
|
||||
match ch {
|
||||
'{' => brace_depth += 1,
|
||||
'}' => brace_depth -= 1,
|
||||
'(' => paren_depth += 1,
|
||||
')' => paren_depth -= 1,
|
||||
'<' => angle_depth += 1,
|
||||
'>' => angle_depth -= 1,
|
||||
',' if brace_depth == 0 && paren_depth == 0 && angle_depth == 0 => {
|
||||
parts.push(&input[start..idx]);
|
||||
start = idx + 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if start < input.len() {
|
||||
parts.push(&input[start..]);
|
||||
}
|
||||
parts
|
||||
}
|
||||
|
||||
fn parse_variant_decl(decl: &str) -> Option<EnumVariant> {
|
||||
let decl = decl.trim();
|
||||
if decl.is_empty() || decl.starts_with("#[") {
|
||||
return None;
|
||||
}
|
||||
let name_len = decl
|
||||
.find(|ch: char| !(ch.is_ascii_alphanumeric() || ch == '_'))
|
||||
.unwrap_or(decl.len());
|
||||
let name = decl[..name_len].to_owned();
|
||||
let rest = decl[name_len..].trim();
|
||||
let body = if rest.starts_with('{') {
|
||||
let fields = split_top_level(enum_block(rest))
|
||||
.into_iter()
|
||||
.filter_map(|field| {
|
||||
let (name, ty) = field.trim().split_once(':')?;
|
||||
Some((name.trim().to_owned(), ty.trim().to_owned()))
|
||||
})
|
||||
.collect();
|
||||
VariantBody::Struct(fields)
|
||||
} else if let Some(tuple) = rest
|
||||
.strip_prefix('(')
|
||||
.and_then(|rest| rest.split(')').next())
|
||||
{
|
||||
VariantBody::Tuple(tuple.trim().to_owned())
|
||||
} else {
|
||||
VariantBody::Unit
|
||||
};
|
||||
Some(EnumVariant { name, body })
|
||||
}
|
||||
|
||||
fn protocol_sample(variant: &EnumVariant) -> Value {
|
||||
let mut object = Map::new();
|
||||
object.insert("type".to_owned(), Value::String(kebab_case(&variant.name)));
|
||||
match &variant.body {
|
||||
VariantBody::Unit => {}
|
||||
VariantBody::Tuple(ty) => {
|
||||
let Value::Object(fields) = sample_for_type(ty) else {
|
||||
panic!("tuple variant {} must use object sample", variant.name);
|
||||
};
|
||||
object.extend(fields);
|
||||
}
|
||||
VariantBody::Struct(fields) => {
|
||||
for (name, ty) in fields {
|
||||
object.insert(name.clone(), sample_for_type(ty));
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Object(object)
|
||||
}
|
||||
|
||||
fn kebab_case(name: &str) -> String {
|
||||
let mut out = String::new();
|
||||
for (idx, ch) in name.chars().enumerate() {
|
||||
if ch.is_ascii_uppercase() {
|
||||
if idx > 0 {
|
||||
out.push('-');
|
||||
}
|
||||
out.push(ch.to_ascii_lowercase());
|
||||
} else {
|
||||
out.push(ch);
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn sample_for_type(ty: &str) -> Value {
|
||||
let ty = compact_type(ty);
|
||||
if let Some(inner) = ty
|
||||
.strip_prefix("Option<")
|
||||
.and_then(|ty| ty.strip_suffix('>'))
|
||||
{
|
||||
let _ = inner;
|
||||
return Value::Null;
|
||||
}
|
||||
if ty.starts_with("Vec<") {
|
||||
return json!([]);
|
||||
}
|
||||
if let Some(inner) = ty.strip_prefix("Box<").and_then(|ty| ty.strip_suffix('>')) {
|
||||
return sample_for_type(inner);
|
||||
}
|
||||
|
||||
match ty.as_str() {
|
||||
"String" | "PathBuf" => json!("sample"),
|
||||
"bool" => json!(true),
|
||||
"usize" | "u64" | "u32" | "u16" | "i64" => json!(1),
|
||||
"BlobHash" => json!("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"),
|
||||
"StatusResponse" => json!({
|
||||
"home": "/tmp/geth-home",
|
||||
"socket": "/tmp/geth.sock",
|
||||
"agent_id": "agent:local",
|
||||
"node_id": "node:local",
|
||||
"daemon_started_at_ms": 1,
|
||||
"daemon_uptime_seconds": 1,
|
||||
"store_schema_version": 1,
|
||||
"store_current_schema_version": 1,
|
||||
"store_journal_mode": "wal",
|
||||
"store_synchronous": "normal",
|
||||
"store_status": "ok",
|
||||
"store_note": "sample",
|
||||
"iroh_enabled": true,
|
||||
"endpoint_id": "endpoint:local",
|
||||
"iroh_relay_mode": "default",
|
||||
"iroh_local_discovery": true,
|
||||
"iroh": "enabled",
|
||||
"native_backends": []
|
||||
}),
|
||||
"NodeIdResponse" => json!({
|
||||
"agent_id": "agent:local",
|
||||
"node_id": "node:local",
|
||||
"endpoint_id": "endpoint:local"
|
||||
}),
|
||||
"KeychainStatusResponse" => json!({
|
||||
"initialized": true,
|
||||
"admin_keys": 1,
|
||||
"signatures": 1,
|
||||
"verified_signatures": 1,
|
||||
"failed_signatures": 0,
|
||||
"users": 1,
|
||||
"devices": 1,
|
||||
"nodes": 1
|
||||
}),
|
||||
"KeychainFetchImportReport" => json!({
|
||||
"ops_imported": 1,
|
||||
"signatures_imported": 1,
|
||||
"invalid_ops_rejected": 0
|
||||
}),
|
||||
"ResourceDescriptor" => json!({
|
||||
"id": "resource:sample",
|
||||
"kind": "kv",
|
||||
"name": "sample",
|
||||
"authority": {"kind": "local"},
|
||||
"local_role": "owner",
|
||||
"replication": "local-only",
|
||||
"retention": "keep",
|
||||
"status": "active"
|
||||
}),
|
||||
"PeerCard" => peer_card_json(),
|
||||
"DiscoveredPeer" => json!({
|
||||
"card": peer_card_json(),
|
||||
"discovered_at": 1,
|
||||
"source": "manual",
|
||||
"trust_state": "candidate-only"
|
||||
}),
|
||||
"OverlayPlan" => json!({
|
||||
"name": "home",
|
||||
"resource": "resource:overlay:home",
|
||||
"cidr": "172.22.0.0/24",
|
||||
"alpn": "/geth/overlay/1",
|
||||
"capabilities": [],
|
||||
"discovery": "manual",
|
||||
"runtime": "planned",
|
||||
"security": [],
|
||||
"implementation_notes": []
|
||||
}),
|
||||
"OverlayJoinPlan" => json!({
|
||||
"plan": sample_for_type("OverlayPlan"),
|
||||
"network": sample_for_type("OverlayNetworkStatus"),
|
||||
"enabled": true,
|
||||
"note": "sample"
|
||||
}),
|
||||
"OverlayNetworkStatus" => json!({
|
||||
"name": "home",
|
||||
"resource": "resource:overlay:home",
|
||||
"cidr": "172.22.0.0/24",
|
||||
"state": "joined",
|
||||
"virtual_ip": "172.22.0.2",
|
||||
"peers": [],
|
||||
"note": "sample"
|
||||
}),
|
||||
"OverlayInterfacePlan" => json!({
|
||||
"name": "home",
|
||||
"platform": "linux",
|
||||
"interface_name": "geth-home",
|
||||
"cidr": "172.22.0.0/24",
|
||||
"virtual_ip": "172.22.0.2",
|
||||
"requires_privileges": true,
|
||||
"commands": [],
|
||||
"notes": []
|
||||
}),
|
||||
"OverlayRuntimeStatus" => json!({
|
||||
"name": "home",
|
||||
"interface_name": "geth-home",
|
||||
"virtual_ip": "172.22.0.2",
|
||||
"cidr": "172.22.0.0/24",
|
||||
"mtu": 1280,
|
||||
"started_at_ms": 1,
|
||||
"packets_from_tun": 0,
|
||||
"packets_to_tun": 0,
|
||||
"packets_to_peers": 0,
|
||||
"last_error": null,
|
||||
"note": "sample"
|
||||
}),
|
||||
"OverlayPacket" => json!({
|
||||
"id": "overlay-packet:sample",
|
||||
"network": "home",
|
||||
"source_node": "node:local",
|
||||
"destination_node": "node:peer",
|
||||
"packet_base64": "AA==",
|
||||
"size_bytes": 1,
|
||||
"received_at_ms": 1,
|
||||
"note": "sample"
|
||||
}),
|
||||
"FileRoot" => json!({
|
||||
"id": "file-root:sample",
|
||||
"resource": "resource:cas-root:sample",
|
||||
"name": "sample",
|
||||
"path": "/tmp/sample",
|
||||
"latest_tree": null,
|
||||
"updated_at_ms": 1
|
||||
}),
|
||||
"FileRootScan" => json!({
|
||||
"root": sample_for_type("FileRoot"),
|
||||
"tree": {
|
||||
"hash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||
"size_bytes": 1
|
||||
},
|
||||
"changes": [],
|
||||
"note": "sample"
|
||||
}),
|
||||
"FileConflict" => json!({
|
||||
"id": "file-conflict:sample",
|
||||
"root": "sample",
|
||||
"resource": "resource:cas-root:sample",
|
||||
"path": "file.txt",
|
||||
"kind": "concurrent-edit",
|
||||
"status": "open",
|
||||
"base_tree": null,
|
||||
"local_tree": null,
|
||||
"remote_tree": null,
|
||||
"detail": "sample",
|
||||
"resolution": null,
|
||||
"resolution_note": null,
|
||||
"created_at_ms": 1,
|
||||
"resolved_at_ms": null
|
||||
}),
|
||||
"KeychainOp" => json!({
|
||||
"id": "auth-op:sample",
|
||||
"created_at": 1,
|
||||
"kind": {"kind": "keychain-init"}
|
||||
}),
|
||||
"KeychainOpSignature" => json!({
|
||||
"op_id": "auth-op:sample",
|
||||
"signer": "key:sample",
|
||||
"signer_public_key": "public",
|
||||
"namespace": "geth.keychain.v1@geth.local",
|
||||
"signature": [1],
|
||||
"created_at": 1
|
||||
}),
|
||||
"KeychainAllowedSigner" => json!({
|
||||
"key": "key:sample",
|
||||
"principal": "admin",
|
||||
"public_key": "public",
|
||||
"valid_after_ms": null,
|
||||
"valid_before_ms": null
|
||||
}),
|
||||
"KeychainSigchainReport" => json!({
|
||||
"ops": 1,
|
||||
"signatures": 1,
|
||||
"accepted_ops": 1,
|
||||
"rejected_ops": 0,
|
||||
"active_admin_keys": 1,
|
||||
"accepted_head": null,
|
||||
"note": "sample"
|
||||
}),
|
||||
"KeychainSigchainEntry" => json!({
|
||||
"op": sample_for_type("KeychainOp"),
|
||||
"signatures": []
|
||||
}),
|
||||
"KeychainCheckpoint" => json!({
|
||||
"version": 1,
|
||||
"profile": {
|
||||
"keychain_signature_namespace": "geth.keychain.v1@geth.local",
|
||||
"node_enrollment_request_namespace": "geth.node-enrollment-request.v1@geth.local",
|
||||
"default_admin_principal": "geth-admin"
|
||||
},
|
||||
"base_url": "https://example.invalid",
|
||||
"head": null,
|
||||
"ops": 1,
|
||||
"signatures": 1,
|
||||
"sigchain_bytes": 1,
|
||||
"sigchain_hash": "hash",
|
||||
"allowed_signers_hash": "hash",
|
||||
"reduced_view_hash": "hash",
|
||||
"generated_at": 1
|
||||
}),
|
||||
"AuthExplanation" => json!({
|
||||
"subject": "node:peer",
|
||||
"resource": "resource:sample",
|
||||
"capability": "sample.read",
|
||||
"allowed": true,
|
||||
"reason": "sample",
|
||||
"evaluated_ops": 1,
|
||||
"diagnostics": []
|
||||
}),
|
||||
"AuthOp" => json!({
|
||||
"id": "auth-op:sample",
|
||||
"resource": "resource:sample",
|
||||
"created_at": 1,
|
||||
"kind": {"kind": "resource-create"}
|
||||
}),
|
||||
"AuthOpSignature" => json!({
|
||||
"op_id": "auth-op:sample",
|
||||
"signer": "key:sample",
|
||||
"signer_public_key": "public",
|
||||
"namespace": "geth.auth.v1@geth.local",
|
||||
"signature": [1],
|
||||
"created_at": 1
|
||||
}),
|
||||
"NodeRecord" => json!({
|
||||
"id": "node:peer",
|
||||
"device": "device:peer",
|
||||
"name": "peer",
|
||||
"endpoints": []
|
||||
}),
|
||||
"NodeEnrollmentRequest" => json!({
|
||||
"id": "auth-op:enroll",
|
||||
"requester_node": "node:peer",
|
||||
"requester_agent": "agent:peer",
|
||||
"requester_agent_public_key": "public",
|
||||
"requested_node_name": "peer",
|
||||
"requested_capabilities": [],
|
||||
"endpoint_id": null,
|
||||
"reason": null,
|
||||
"status": "pending",
|
||||
"created_at": 1,
|
||||
"provenance": null
|
||||
}),
|
||||
"ResourceMasterSecret" => json!({
|
||||
"id": "secret:sample",
|
||||
"resource": "resource:sample",
|
||||
"epoch": 1,
|
||||
"created_at": 1
|
||||
}),
|
||||
"BearerAccess" => json!({
|
||||
"secret": "bearer:sample",
|
||||
"token": null,
|
||||
"token_hash": "hash",
|
||||
"resource": "resource:sample",
|
||||
"capabilities": ["sample.read"],
|
||||
"expires_at": null,
|
||||
"may_delegate": false
|
||||
}),
|
||||
"BearerChallenge" => json!({
|
||||
"resource": "resource:sample",
|
||||
"capabilities": ["sample.read"],
|
||||
"nonce": "nonce",
|
||||
"issued_at": 1
|
||||
}),
|
||||
"BearerProof" => json!({
|
||||
"secret": "bearer:sample",
|
||||
"resource": "resource:sample",
|
||||
"capabilities": ["sample.read"],
|
||||
"nonce": "nonce",
|
||||
"response": "response"
|
||||
}),
|
||||
"SshCertRequest" => json!({
|
||||
"id": "ssh-cert-request:sample",
|
||||
"requester_node": "node:peer",
|
||||
"public_key": "ssh-ed25519 AAAA sample",
|
||||
"public_key_fingerprint": "SHA256:sample",
|
||||
"cert_kind": "user",
|
||||
"principals": [],
|
||||
"requested_validity": null,
|
||||
"renewal_of": null,
|
||||
"reason": null,
|
||||
"status": "pending",
|
||||
"created_at": 1,
|
||||
"provenance": null
|
||||
}),
|
||||
"SshCertApproval" => json!({
|
||||
"request_id": "ssh-cert-request:sample",
|
||||
"approved_by_node": "node:local",
|
||||
"ca_key_path": "/tmp/ca",
|
||||
"key_id": "geth",
|
||||
"valid_for": "+1h",
|
||||
"serial": null,
|
||||
"output_path": null,
|
||||
"signing_command": [],
|
||||
"signed": false,
|
||||
"certificate_id": null,
|
||||
"note": "sample"
|
||||
}),
|
||||
"SshCertificateRecord" => json!({
|
||||
"id": "ssh-cert:sample",
|
||||
"request_id": "ssh-cert-request:sample",
|
||||
"certificate": "cert",
|
||||
"certificate_fingerprint": "SHA256:sample",
|
||||
"imported_at": 1,
|
||||
"provenance": null
|
||||
}),
|
||||
"SshRevocationEntry" => json!({
|
||||
"id": "ssh-revocation:sample",
|
||||
"kind": "public-key",
|
||||
"target": "ssh-ed25519 AAAA sample",
|
||||
"reason": null,
|
||||
"created_at": 1,
|
||||
"published": false,
|
||||
"provenance": null
|
||||
}),
|
||||
"DbResource" => json!({
|
||||
"id": "db:sample",
|
||||
"resource": "resource:db:sample",
|
||||
"name": "sample",
|
||||
"path": "/tmp/sample.sqlite",
|
||||
"path_exists": true,
|
||||
"size_bytes": 1,
|
||||
"schema_metadata": "schema",
|
||||
"crsqlite_changes": {
|
||||
"available": false,
|
||||
"change_count": null,
|
||||
"max_db_version": null,
|
||||
"columns": [],
|
||||
"error": null
|
||||
},
|
||||
"sync_status": "local"
|
||||
}),
|
||||
"CrSqliteChangeBatch" => json!({
|
||||
"schema_metadata": "schema",
|
||||
"max_db_version": null,
|
||||
"changes": []
|
||||
}),
|
||||
"KvResource" => json!({
|
||||
"id": "kv:sample",
|
||||
"resource": "resource:kv:sample",
|
||||
"name": "sample",
|
||||
"sync_status": "local"
|
||||
}),
|
||||
"KvEntry" => json!({
|
||||
"store": "kv:sample",
|
||||
"key": "key",
|
||||
"value": "value"
|
||||
}),
|
||||
"DocumentResource" => json!({
|
||||
"id": "document:sample",
|
||||
"resource": "resource:document:sample",
|
||||
"name": "sample",
|
||||
"sync_status": "local",
|
||||
"state_bytes": 2
|
||||
}),
|
||||
"DocumentState" => json!({
|
||||
"document": sample_for_type("DocumentResource"),
|
||||
"state_json": "{}",
|
||||
"updated_at": 1
|
||||
}),
|
||||
"PubsubMessage" => json!({
|
||||
"topic": "topic:sample",
|
||||
"message": "sample",
|
||||
"published_at": 1
|
||||
}),
|
||||
"PipeListener" => json!({
|
||||
"id": "pipe:sample",
|
||||
"name": "sample",
|
||||
"listened_at": 1,
|
||||
"note": "sample"
|
||||
}),
|
||||
"PipeConnection" => json!({
|
||||
"target": "sample",
|
||||
"connected_at": 1,
|
||||
"local_listener_found": true,
|
||||
"note": "sample"
|
||||
}),
|
||||
"PipeMessage" => json!({
|
||||
"pipe": "sample",
|
||||
"data_base64": "AA==",
|
||||
"received_at": 1,
|
||||
"source_node": null,
|
||||
"note": "sample"
|
||||
}),
|
||||
"SshProxyConnection" => json!({
|
||||
"target_node": "node:peer",
|
||||
"connected_at": 1,
|
||||
"local_sshd_target": "127.0.0.1:22",
|
||||
"admin_shell_available": false,
|
||||
"note": "sample"
|
||||
}),
|
||||
other => panic!("missing protocol sample for type {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn compact_type(ty: &str) -> String {
|
||||
ty.chars().filter(|ch| !ch.is_whitespace()).collect()
|
||||
}
|
||||
|
||||
fn peer_card_json() -> Value {
|
||||
json!({
|
||||
"node_id": "node:peer",
|
||||
"agent_id": "agent:peer",
|
||||
"endpoints": [],
|
||||
"issued_at": 1,
|
||||
"signature": {
|
||||
"namespace": "geth.peer-card.v1@geth.local",
|
||||
"signer": "agent:peer",
|
||||
"public_key": "public",
|
||||
"signature": "signature"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn control_request_response_serialization_roundtrip() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue