use std::fs; use std::path::PathBuf; use mxgateway_client::generated::mxaccess_gateway::v1::{ mx_command, mx_value, MxCommand, MxCommandKind, MxCommandRequest, MxDataType, MxEvent, MxEventFamily, MxValue, OpenSessionReply, ProtocolStatusCode, RegisterCommand, }; use mxgateway_client::{GATEWAY_PROTOCOL_VERSION, WORKER_PROTOCOL_VERSION}; use serde_json::Value; #[test] fn generated_golden_fixtures_are_available() { for fixture_name in [ "open-session-reply.ok.json", "register-command-request.json", "on-data-change-event.json", ] { let fixture = read_fixture(fixture_name); assert!( fixture.is_object(), "{fixture_name} must remain a protobuf JSON object" ); } } #[test] fn open_session_fixture_matches_protocol_versions() { let fixture = read_fixture("open-session-reply.ok.json"); let reply = OpenSessionReply { session_id: string_field(&fixture, "sessionId"), backend_name: string_field(&fixture, "backendName"), worker_process_id: i32_field(&fixture, "workerProcessId"), worker_protocol_version: u32_field(&fixture, "workerProtocolVersion"), gateway_protocol_version: u32_field(&fixture, "gatewayProtocolVersion"), protocol_status: Some( mxgateway_client::generated::mxaccess_gateway::v1::ProtocolStatus { code: ProtocolStatusCode::Ok as i32, message: string_field(&fixture["protocolStatus"], "message"), }, ), ..OpenSessionReply::default() }; assert_eq!(reply.gateway_protocol_version, GATEWAY_PROTOCOL_VERSION); assert_eq!(reply.worker_protocol_version, WORKER_PROTOCOL_VERSION); } #[test] fn register_fixture_can_build_generated_request() { let fixture = read_fixture("register-command-request.json"); let command = &fixture["command"]; let request = MxCommandRequest { session_id: string_field(&fixture, "sessionId"), client_correlation_id: string_field(&fixture, "clientCorrelationId"), command: Some(MxCommand { kind: MxCommandKind::Register as i32, payload: Some(mx_command::Payload::Register(RegisterCommand { client_name: string_field(&command["register"], "clientName"), })), }), }; assert_eq!(request.session_id, "session-fixture"); assert_eq!( request.command.unwrap().kind, MxCommandKind::Register as i32 ); } #[test] fn on_data_change_fixture_can_build_generated_event() { let fixture = read_fixture("on-data-change-event.json"); let event = MxEvent { family: MxEventFamily::OnDataChange as i32, session_id: string_field(&fixture, "sessionId"), server_handle: i32_field(&fixture, "serverHandle"), item_handle: i32_field(&fixture, "itemHandle"), value: Some(MxValue { data_type: MxDataType::Integer as i32, variant_type: string_field(&fixture["value"], "variantType"), kind: Some(mx_value::Kind::Int32Value(i32_field( &fixture["value"], "int32Value", ))), ..MxValue::default() }), quality: i32_field(&fixture, "quality"), worker_sequence: u64_field(&fixture, "workerSequence"), ..MxEvent::default() }; assert_eq!(event.family, MxEventFamily::OnDataChange as i32); assert_eq!(event.value.unwrap().data_type, MxDataType::Integer as i32); } fn read_fixture(name: &str) -> Value { let path = fixture_root().join(name); let data = fs::read_to_string(&path).unwrap_or_else(|error| { panic!("failed to read fixture {}: {error}", path.display()); }); serde_json::from_str(&data).unwrap_or_else(|error| { panic!("failed to parse fixture {}: {error}", path.display()); }) } fn fixture_root() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../proto/fixtures/golden") } fn string_field(value: &Value, name: &str) -> String { value[name] .as_str() .unwrap_or_else(|| panic!("missing string field {name}")) .to_owned() } fn i32_field(value: &Value, name: &str) -> i32 { value[name] .as_i64() .unwrap_or_else(|| panic!("missing i32 field {name}")) .try_into() .unwrap_or_else(|_| panic!("field {name} does not fit in i32")) } fn u32_field(value: &Value, name: &str) -> u32 { value[name] .as_u64() .unwrap_or_else(|| panic!("missing u32 field {name}")) .try_into() .unwrap_or_else(|_| panic!("field {name} does not fit in u32")) } fn u64_field(value: &Value, name: &str) -> u64 { if let Some(number) = value[name].as_u64() { return number; } value[name] .as_str() .unwrap_or_else(|| panic!("missing u64 field {name}")) .parse() .unwrap_or_else(|_| panic!("field {name} does not parse as u64")) }