1#[allow(clippy::large_enum_variant)]
8#[path = "generated/geode.rs"]
9mod generated;
10
11pub use generated::*;
13
14use prost::Message;
15
16use crate::error::Result;
19
20pub fn encode_with_length_prefix(msg: &QuicClientMessage) -> Vec<u8> {
27 let data = msg.encode_to_vec();
28 let length = data.len() as u32;
29 let mut result = Vec::with_capacity(4 + data.len());
30 result.extend(&length.to_be_bytes());
31 result.extend(data);
32 result
33}
34
35pub fn decode_length_prefix(data: &[u8]) -> Result<u32> {
37 if data.len() < 4 {
38 return Err(crate::error::Error::protocol(
39 "Insufficient data for length prefix",
40 ));
41 }
42 Ok(u32::from_be_bytes([data[0], data[1], data[2], data[3]]))
43}
44
45pub fn decode_quic_server_message(data: &[u8]) -> Result<QuicServerMessage> {
47 QuicServerMessage::decode(data)
48 .map_err(|e| crate::error::Error::protocol(format!("Protobuf decode error: {}", e)))
49}
50
51#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn test_encode_decode_hello_roundtrip() {
61 let req = HelloRequest {
62 username: "admin".to_string(),
63 password: "secret".to_string(),
64 tenant_id: Some("tenant1".to_string()),
65 client_name: String::new(),
66 client_version: String::new(),
67 wanted_conformance: String::new(),
68 graph: None,
69 };
70 let msg = QuicClientMessage {
71 msg: Some(quic_client_message::Msg::Hello(req)),
72 };
73 let encoded = msg.encode_to_vec();
74 assert!(!encoded.is_empty());
75
76 let decoded = QuicClientMessage::decode(encoded.as_slice()).unwrap();
78 match decoded.msg {
79 Some(quic_client_message::Msg::Hello(hello)) => {
80 assert_eq!(hello.username, "admin");
81 assert_eq!(hello.password, "secret");
82 assert_eq!(hello.tenant_id, Some("tenant1".to_string()));
83 }
84 _ => panic!("Expected Hello variant"),
85 }
86 }
87
88 #[test]
89 fn test_encode_decode_execute_roundtrip() {
90 let params = vec![
91 Param {
92 name: "name".to_string(),
93 value: Some(Value {
94 kind: Some(value::Kind::StringVal(StringValue {
95 value: "Alice".to_string(),
96 kind: 0,
97 })),
98 }),
99 },
100 Param {
101 name: "age".to_string(),
102 value: Some(Value {
103 kind: Some(value::Kind::IntVal(IntValue { value: 30, kind: 0 })),
104 }),
105 },
106 ];
107
108 let req = ExecuteRequest {
109 session_id: "session123".to_string(),
110 query: "MATCH (n) RETURN n".to_string(),
111 params,
112 };
113 let msg = QuicClientMessage {
114 msg: Some(quic_client_message::Msg::Execute(req)),
115 };
116 let encoded = msg.encode_to_vec();
117 assert!(!encoded.is_empty());
118
119 let decoded = QuicClientMessage::decode(encoded.as_slice()).unwrap();
120 match decoded.msg {
121 Some(quic_client_message::Msg::Execute(exec)) => {
122 assert_eq!(exec.session_id, "session123");
123 assert_eq!(exec.query, "MATCH (n) RETURN n");
124 assert_eq!(exec.params.len(), 2);
125 }
126 _ => panic!("Expected Execute variant"),
127 }
128 }
129
130 #[test]
131 fn test_encode_with_length_prefix() {
132 let msg = QuicClientMessage {
133 msg: Some(quic_client_message::Msg::Ping(PingRequest {})),
134 };
135 let encoded = encode_with_length_prefix(&msg);
136 assert!(encoded.len() >= 4);
138 let length = u32::from_be_bytes([encoded[0], encoded[1], encoded[2], encoded[3]]);
139 assert_eq!(length as usize, encoded.len() - 4);
140 }
141
142 #[test]
143 fn test_decode_length_prefix() {
144 let data = [0x00, 0x00, 0x00, 0x10];
145 let length = decode_length_prefix(&data).unwrap();
146 assert_eq!(length, 16);
147 }
148
149 #[test]
150 fn test_decode_length_prefix_insufficient_data() {
151 let data = [0x00, 0x00];
152 let result = decode_length_prefix(&data);
153 assert!(result.is_err());
154 }
155
156 #[test]
157 fn test_decode_hello_response() {
158 let resp = HelloResponse {
160 success: true,
161 session_id: "sess123".to_string(),
162 error_message: String::new(),
163 capabilities: vec![],
164 password_reset_required: false,
165 graph: None,
166 };
167 let encoded = resp.encode_to_vec();
168 let decoded = HelloResponse::decode(encoded.as_slice()).unwrap();
169 assert!(decoded.success);
170 assert_eq!(decoded.session_id, "sess123");
171 }
172
173 #[test]
174 fn test_decode_ping_response() {
175 let resp = PingResponse { ok: true };
176 let encoded = resp.encode_to_vec();
177 let decoded = PingResponse::decode(encoded.as_slice()).unwrap();
178 assert!(decoded.ok);
179 }
180
181 #[test]
182 fn test_value_null() {
183 let val = Value {
184 kind: Some(value::Kind::NullVal(NullValue {})),
185 };
186 assert!(matches!(val.kind, Some(value::Kind::NullVal(_))));
187 }
188
189 #[test]
190 fn test_value_default() {
191 let val = Value::default();
192 assert!(val.kind.is_none());
193 }
194
195 #[test]
196 fn test_message_defaults() {
197 let client_msg = QuicClientMessage::default();
198 assert!(client_msg.msg.is_none());
199
200 let server_msg = QuicServerMessage::default();
201 assert!(server_msg.msg.is_none());
202 }
203}