use prost::Message;
use super::*;
use crate::common::test_utils::helpers::proto_response;
use crate::messages::ResponseMessage;
#[test]
fn test_decoded_error_default() {
let d = DecodedError::default();
assert_eq!(d.request_id, UNSPECIFIED_REQUEST_ID);
assert_eq!(d.error_code, 0);
assert_eq!(d.error_message, "");
assert_eq!(d.error_time, None);
assert_eq!(d.advanced_order_reject_json, "");
}
#[test]
fn test_notice_from_decoded_preserves_rich_payload() {
use crate::messages::Notice;
use time::OffsetDateTime;
let payload = DecodedError {
request_id: 42,
error_code: 2104,
error_message: "Market data farm OK".into(),
error_time: Some(1_700_000_000_000),
advanced_order_reject_json: "{\"reject\":1}".into(),
};
let notice = Notice::from(payload);
assert_eq!(notice.code, 2104);
assert_eq!(notice.message, "Market data farm OK");
assert_eq!(notice.advanced_order_reject_json, "{\"reject\":1}");
let expected = OffsetDateTime::from_unix_timestamp_nanos(1_700_000_000_000_i128 * 1_000_000).unwrap();
assert_eq!(notice.error_time, Some(expected));
}
#[test]
fn test_notice_from_decoded_missing_optionals() {
use crate::messages::Notice;
let payload = DecodedError {
request_id: -1,
error_code: 200,
error_message: "no security".into(),
error_time: None,
advanced_order_reject_json: String::new(),
};
let notice = Notice::from(payload);
assert_eq!(notice.code, 200);
assert_eq!(notice.error_time, None);
assert_eq!(notice.advanced_order_reject_json, "");
}
#[test]
fn test_error_from_decoded_projects_to_notice() {
let payload = DecodedError {
request_id: 42,
error_code: 200,
error_message: "no security".into(),
error_time: None,
advanced_order_reject_json: String::new(),
};
let err = crate::Error::from(payload);
match err {
crate::Error::Notice(notice) => {
assert_eq!(notice.code, 200);
assert_eq!(notice.message, "no security");
}
other => panic!("expected Error::Notice, got {other:?}"),
}
}
#[test]
fn test_determine_routing_error_protobuf_malformed() {
let raw_bytes = vec![0xFFu8; 16];
let message = proto_response(IncomingMessages::Error, raw_bytes);
match determine_routing(&message) {
RoutingDecision::Error(payload) => {
assert_eq!(payload.request_id, UNSPECIFIED_REQUEST_ID);
assert_eq!(payload.error_code, 0);
assert_eq!(payload.error_message, "");
}
routing => panic!("Expected Error routing, got {routing:?}"),
}
}
#[test]
fn test_determine_routing_by_request_id() {
let message_str = "63\01\0123\0DU123456\0AccountType\0ADVISOR\0USD\0";
let message = ResponseMessage::from(message_str);
match determine_routing(&message) {
RoutingDecision::ByRequestId(id) => assert_eq!(id, 123),
routing => panic!("Expected ByRequestId routing, got {routing:?}"),
}
}
#[test]
fn test_determine_routing_error_protobuf() {
let envelope = crate::proto::ErrorMessage {
id: Some(42),
error_time: Some(1700000000000),
error_code: Some(2100),
error_msg: Some("Market data farm connection is OK".to_string()),
advanced_order_reject_json: Some("{\"hint\":\"check filters\"}".to_string()),
};
let mut raw_bytes = Vec::new();
prost::Message::encode(&envelope, &mut raw_bytes).expect("encode error envelope");
let message = proto_response(IncomingMessages::Error, raw_bytes);
match determine_routing(&message) {
RoutingDecision::Error(payload) => {
assert_eq!(payload.request_id, 42);
assert_eq!(payload.error_code, 2100);
assert_eq!(payload.error_message, "Market data farm connection is OK");
assert_eq!(payload.error_time, Some(1700000000000));
assert_eq!(payload.advanced_order_reject_json, "{\"hint\":\"check filters\"}");
}
routing => panic!("Expected Error routing, got {routing:?}"),
}
}
#[test]
fn test_determine_routing_error_protobuf_unspecified_id() {
let envelope = crate::proto::ErrorMessage {
id: None,
error_time: None,
error_code: Some(2104),
error_msg: Some("Market data farm connection is OK".to_string()),
advanced_order_reject_json: None,
};
let mut raw_bytes = Vec::new();
prost::Message::encode(&envelope, &mut raw_bytes).expect("encode error envelope");
let message = proto_response(IncomingMessages::Error, raw_bytes);
match determine_routing(&message) {
RoutingDecision::Error(payload) => {
assert_eq!(payload.request_id, UNSPECIFIED_REQUEST_ID);
assert_eq!(payload.error_code, 2104);
assert_eq!(payload.error_message, "Market data farm connection is OK");
assert_eq!(payload.error_time, None);
assert_eq!(payload.advanced_order_reject_json, "");
}
routing => panic!("Expected Error routing, got {routing:?}"),
}
}
#[test]
fn test_determine_routing_shared_message() {
let message_str = "15\01\0DU123456,DU234567\0";
let message = ResponseMessage::from(message_str);
match determine_routing(&message) {
RoutingDecision::SharedMessage(msg_type) => {
assert_eq!(msg_type, IncomingMessages::ManagedAccounts);
}
routing => panic!("Expected SharedMessage routing, got {routing:?}"),
}
}
#[test]
fn test_is_warning_error() {
assert!(is_warning_error(2100));
assert!(is_warning_error(2169));
assert!(is_warning_error(2119));
assert!(is_warning_error(2150));
assert!(!is_warning_error(2099));
assert!(!is_warning_error(2170));
assert!(!is_warning_error(200));
assert!(!is_warning_error(2200));
}
#[test]
fn test_order_message_routing_without_order_id_returns_sentinel() {
let completed_orders_end = proto_response(IncomingMessages::CompletedOrdersEnd, Vec::new());
match determine_routing(&completed_orders_end) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, -1),
routing => panic!("Expected ByOrderId(-1) routing, got {routing:?}"),
}
let commission_report = proto_response(
IncomingMessages::CommissionsReport,
crate::proto::CommissionAndFeesReport {
exec_id: Some("exec123".into()),
..Default::default()
}
.encode_to_vec(),
);
match determine_routing(&commission_report) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, -1),
routing => panic!("Expected ByOrderId(-1) routing, got {routing:?}"),
}
}
#[test]
fn test_determine_routing_protobuf_open_order() {
let bytes = crate::proto::OpenOrder {
order_id: Some(58),
..Default::default()
}
.encode_to_vec();
let message = proto_response(IncomingMessages::OpenOrder, bytes);
match determine_routing(&message) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, 58),
routing => panic!("Expected ByOrderId(58), got {routing:?}"),
}
}
#[test]
fn test_determine_routing_protobuf_order_status() {
let bytes = crate::proto::OrderStatus {
order_id: Some(58),
status: Some("Filled".into()),
..Default::default()
}
.encode_to_vec();
let message = proto_response(IncomingMessages::OrderStatus, bytes);
match determine_routing(&message) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, 58),
routing => panic!("Expected ByOrderId(58), got {routing:?}"),
}
}
#[test]
fn test_determine_routing_protobuf_execution_data_uses_nested_order_id() {
let bytes = crate::proto::ExecutionDetails {
req_id: Some(-1),
contract: None,
execution: Some(crate::proto::Execution {
order_id: Some(58),
..Default::default()
}),
}
.encode_to_vec();
let message = proto_response(IncomingMessages::ExecutionData, bytes);
match determine_routing(&message) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, 58),
routing => panic!("Expected ByOrderId(58), got {routing:?}"),
}
}
#[test]
fn test_determine_routing_protobuf_execution_data_end() {
let bytes = crate::proto::ExecutionDetailsEnd { req_id: Some(7) }.encode_to_vec();
let message = proto_response(IncomingMessages::ExecutionDataEnd, bytes);
match determine_routing(&message) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, 7),
routing => panic!("Expected ByOrderId(7), got {routing:?}"),
}
}
#[test]
fn test_determine_routing_protobuf_commissions_report_no_order_id() {
let bytes = crate::proto::CommissionAndFeesReport {
exec_id: Some("0000e0d5.69fb6496.01.01".into()),
..Default::default()
}
.encode_to_vec();
let message = proto_response(IncomingMessages::CommissionsReport, bytes);
match determine_routing(&message) {
RoutingDecision::ByOrderId(id) => assert_eq!(id, -1),
routing => panic!("Expected ByOrderId(-1), got {routing:?}"),
}
}
#[test]
fn test_determine_routing_protobuf_request_id_message() {
let bytes = crate::proto::AccountSummary {
req_id: Some(314),
..Default::default()
}
.encode_to_vec();
let message = proto_response(IncomingMessages::AccountSummary, bytes);
match determine_routing(&message) {
RoutingDecision::ByRequestId(id) => assert_eq!(id, 314),
routing => panic!("Expected ByRequestId(314), got {routing:?}"),
}
}