use bytes::BytesMut;
use cheetah_string::CheetahString;
use rocketmq_protocol::protocol::LanguageCode;
use rocketmq_protocol::protocol::SerializeType;
use rocketmq_protocol::RemotingCommand;
fn round_trip(mut command: RemotingCommand) -> RemotingCommand {
let mut encoded = BytesMut::new();
command
.try_fast_header_encode(&mut encoded)
.expect("command should encode");
RemotingCommand::decode(&mut encoded)
.expect("command should decode")
.expect("command frame should be complete")
}
#[test]
fn add_ext_field_on_absent_matches_java() {
for serialize_type in [SerializeType::JSON, SerializeType::ROCKETMQ] {
let mut command = RemotingCommand::create_success_response_command().set_serialize_type(serialize_type);
assert!(command.ext_fields().is_none());
command.add_ext_field("regionId", "DefaultRegion");
let decoded = round_trip(command);
assert_eq!(
decoded
.ext_fields()
.and_then(|fields| fields.get("regionId"))
.map(CheetahString::as_str),
Some("DefaultRegion")
);
}
}
#[test]
fn add_ext_field_if_not_exist_on_absent_matches_java() {
for serialize_type in [SerializeType::JSON, SerializeType::ROCKETMQ] {
let mut command = RemotingCommand::create_success_response_command().set_serialize_type(serialize_type);
assert!(command.ext_fields().is_none());
command.add_ext_field_if_not_exist("traceOn", "true");
command.add_ext_field_if_not_exist("traceOn", "false");
let decoded = round_trip(command);
assert_eq!(
decoded
.ext_fields()
.and_then(|fields| fields.get("traceOn"))
.map(CheetahString::as_str),
Some("true")
);
}
}
#[test]
fn node_js_language_code_matches_java() {
const EXISTING_CODES: [(u8, LanguageCode); 13] = [
(0, LanguageCode::JAVA),
(1, LanguageCode::CPP),
(2, LanguageCode::DOTNET),
(3, LanguageCode::PYTHON),
(4, LanguageCode::DELPHI),
(5, LanguageCode::ERLANG),
(6, LanguageCode::RUBY),
(7, LanguageCode::OTHER),
(8, LanguageCode::HTTP),
(9, LanguageCode::GO),
(10, LanguageCode::PHP),
(11, LanguageCode::OMS),
(12, LanguageCode::RUST),
];
for (code, language) in EXISTING_CODES {
assert_eq!(language.get_code(), code);
assert_eq!(LanguageCode::value_of(code), Some(language));
}
assert_eq!(LanguageCode::NODE_JS.get_code(), 13);
assert_eq!(LanguageCode::value_of(13), Some(LanguageCode::NODE_JS));
assert_eq!(LanguageCode::value_of(14), Some(LanguageCode::OTHER));
assert_eq!(LanguageCode::get_code_from_name("NODE_JS"), Some(LanguageCode::NODE_JS));
for serialize_type in [SerializeType::JSON, SerializeType::ROCKETMQ] {
let command = RemotingCommand::create_success_response_command()
.set_language(LanguageCode::NODE_JS)
.set_serialize_type(serialize_type);
let decoded = round_trip(command);
assert_eq!(decoded.language(), LanguageCode::NODE_JS);
assert_eq!(decoded.get_serialize_type(), serialize_type);
}
let serde_fallback: RemotingCommand = serde_json::from_str(
r#"{"code":0,"language":"NODE_JS","version":0,"opaque":0,"flag":1,"remark":null,"serializeTypeCurrentRPC":"JSON"}"#,
)
.expect("serde fallback should recognize NODE_JS");
assert_eq!(serde_fallback.language(), LanguageCode::NODE_JS);
}
#[test]
fn ext_key_length_matches_java_signed_short_boundary() {
let maximum = i16::MAX as usize;
for key_length in [maximum - 1, maximum] {
let key = "k".repeat(key_length);
let mut command =
RemotingCommand::create_success_response_command().set_serialize_type(SerializeType::ROCKETMQ);
command.add_ext_field(key.clone(), "value");
let decoded = round_trip(command);
assert_eq!(
decoded
.ext_fields()
.and_then(|fields| fields.get(key.as_str()))
.map(CheetahString::as_str),
Some("value")
);
}
let oversized_key = "k".repeat(maximum + 1);
let mut binary_command =
RemotingCommand::create_success_response_command().set_serialize_type(SerializeType::ROCKETMQ);
binary_command.add_ext_field(oversized_key.clone(), "value");
let mut destination = BytesMut::from(&b"prefix"[..]);
let error = binary_command
.try_fast_header_encode(&mut destination)
.expect_err("a key larger than Java's signed-short range must be rejected");
assert_eq!(destination.as_ref(), b"prefix");
assert_eq!(error.descriptor(), &rocketmq_error::PROTOCOL_HEADER_INVALID);
let mut json_command = RemotingCommand::create_success_response_command().set_serialize_type(SerializeType::JSON);
json_command.add_ext_field(oversized_key.clone(), "value");
let decoded = round_trip(json_command);
assert_eq!(
decoded
.ext_fields()
.and_then(|fields| fields.get(oversized_key.as_str()))
.map(CheetahString::as_str),
Some("value")
);
}