1use super::Serialize;
2use crate::consistency::Consistency;
3use crate::frame::traits::FromCursor;
4use crate::frame::Version;
5use crate::types::*;
6use crate::{error, Error};
7use derive_more::Display;
10use std::collections::HashMap;
11use std::io::{Cursor, Read};
12use std::net::SocketAddr;
13
14#[derive(Debug, PartialEq, Eq, Clone)]
18pub struct ErrorBody {
19 pub message: String,
21 pub ty: ErrorType,
23}
24
25impl Serialize for ErrorBody {
26 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
27 self.ty.to_error_code().serialize(cursor, version);
28 serialize_str(cursor, &self.message, version);
29 self.ty.serialize(cursor, version);
30 }
31}
32
33impl FromCursor for ErrorBody {
34 fn from_cursor(cursor: &mut Cursor<&[u8]>, version: Version) -> error::Result<ErrorBody> {
35 let error_code = CInt::from_cursor(cursor, version)?;
36 let message = from_cursor_str(cursor)?.to_string();
37 let ty = ErrorType::from_cursor_with_code(cursor, error_code, version)?;
38
39 Ok(ErrorBody { message, ty })
40 }
41}
42
43impl ErrorBody {
44 pub fn is_bad_protocol(&self) -> bool {
47 (self.ty == ErrorType::Server || self.ty == ErrorType::Protocol)
49 && (self
50 .message
51 .contains("Invalid or unsupported protocol version")
52 || self.message.contains("Beta version of the protocol used"))
53 }
54}
55
56#[derive(Debug, PartialEq, Eq, Clone)]
59#[non_exhaustive]
60pub enum FailureInfo {
61 NumFailures(CInt),
63 ReasonMap(HashMap<SocketAddr, CIntShort>),
65}
66
67impl Serialize for FailureInfo {
68 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
69 match self {
70 FailureInfo::NumFailures(count) => count.serialize(cursor, version),
71 FailureInfo::ReasonMap(map) => {
72 let num_failures = map.len() as CInt;
73 num_failures.serialize(cursor, version);
74
75 for (endpoint, error_code) in map {
76 endpoint.serialize(cursor, version);
77 error_code.serialize(cursor, version);
78 }
79 }
80 }
81 }
82}
83
84impl FromCursor for FailureInfo {
85 fn from_cursor(cursor: &mut Cursor<&[u8]>, version: Version) -> error::Result<Self> {
86 Ok(match version {
87 Version::V3 | Version::V4 => Self::NumFailures(CInt::from_cursor(cursor, version)?),
88 Version::V5 => {
89 let num_failures = CInt::from_cursor(cursor, version)?;
90 let mut map = HashMap::with_capacity(num_failures as usize);
91
92 for _ in 0..num_failures {
93 let endpoint = SocketAddr::from_cursor(cursor, version)?;
94 let error_code = CIntShort::from_cursor(cursor, version)?;
95 map.insert(endpoint, error_code);
96 }
97
98 Self::ReasonMap(map)
99 }
100 })
101 }
102}
103
104#[derive(Debug, PartialEq, Eq, Clone)]
107#[non_exhaustive]
108pub enum ErrorType {
109 Server,
110 Protocol,
111 Authentication,
112 Unavailable(UnavailableError),
113 Overloaded,
114 IsBootstrapping,
115 Truncate,
116 WriteTimeout(WriteTimeoutError),
117 ReadTimeout(ReadTimeoutError),
118 ReadFailure(ReadFailureError),
119 FunctionFailure(FunctionFailureError),
120 WriteFailure(WriteFailureError),
121 Syntax,
122 Unauthorized,
123 Invalid,
124 Config,
125 AlreadyExists(AlreadyExistsError),
126 Unprepared(UnpreparedError),
127}
128
129impl Serialize for ErrorType {
130 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
131 match self {
132 ErrorType::Unavailable(unavailable) => unavailable.serialize(cursor, version),
133 ErrorType::WriteTimeout(write_timeout) => write_timeout.serialize(cursor, version),
134 ErrorType::ReadTimeout(read_timeout) => read_timeout.serialize(cursor, version),
135 ErrorType::ReadFailure(read_failure) => read_failure.serialize(cursor, version),
136 ErrorType::FunctionFailure(function_failure) => {
137 function_failure.serialize(cursor, version)
138 }
139 ErrorType::WriteFailure(write_failure) => write_failure.serialize(cursor, version),
140 ErrorType::AlreadyExists(already_exists) => already_exists.serialize(cursor, version),
141 ErrorType::Unprepared(unprepared) => unprepared.serialize(cursor, version),
142 _ => {}
143 }
144 }
145}
146
147impl ErrorType {
148 pub fn from_cursor_with_code(
149 cursor: &mut Cursor<&[u8]>,
150 error_code: CInt,
151 version: Version,
152 ) -> error::Result<ErrorType> {
153 match error_code {
154 0x0000 => Ok(ErrorType::Server),
155 0x000A => Ok(ErrorType::Protocol),
156 0x0100 => Ok(ErrorType::Authentication),
157 0x1000 => UnavailableError::from_cursor(cursor, version).map(ErrorType::Unavailable),
158 0x1001 => Ok(ErrorType::Overloaded),
159 0x1002 => Ok(ErrorType::IsBootstrapping),
160 0x1003 => Ok(ErrorType::Truncate),
161 0x1100 => WriteTimeoutError::from_cursor(cursor, version).map(ErrorType::WriteTimeout),
162 0x1200 => ReadTimeoutError::from_cursor(cursor, version).map(ErrorType::ReadTimeout),
163 0x1300 => ReadFailureError::from_cursor(cursor, version).map(ErrorType::ReadFailure),
164 0x1400 => {
165 FunctionFailureError::from_cursor(cursor, version).map(ErrorType::FunctionFailure)
166 }
167 0x1500 => WriteFailureError::from_cursor(cursor, version).map(ErrorType::WriteFailure),
168 0x2000 => Ok(ErrorType::Syntax),
169 0x2100 => Ok(ErrorType::Unauthorized),
170 0x2200 => Ok(ErrorType::Invalid),
171 0x2300 => Ok(ErrorType::Config),
172 0x2400 => {
173 AlreadyExistsError::from_cursor(cursor, version).map(ErrorType::AlreadyExists)
174 }
175 0x2500 => UnpreparedError::from_cursor(cursor, version).map(ErrorType::Unprepared),
176 _ => Err(Error::UnexpectedErrorCode(error_code)),
177 }
178 }
179
180 pub fn to_error_code(&self) -> CInt {
181 match self {
182 ErrorType::Server => 0x0000,
183 ErrorType::Protocol => 0x000A,
184 ErrorType::Authentication => 0x0100,
185 ErrorType::Unavailable(_) => 0x1000,
186 ErrorType::Overloaded => 0x1001,
187 ErrorType::IsBootstrapping => 0x1002,
188 ErrorType::Truncate => 0x1003,
189 ErrorType::WriteTimeout(_) => 0x1100,
190 ErrorType::ReadTimeout(_) => 0x1200,
191 ErrorType::ReadFailure(_) => 0x1300,
192 ErrorType::FunctionFailure(_) => 0x1400,
193 ErrorType::WriteFailure(_) => 0x1500,
194 ErrorType::Syntax => 0x2000,
195 ErrorType::Unauthorized => 0x2100,
196 ErrorType::Invalid => 0x2200,
197 ErrorType::Config => 0x2300,
198 ErrorType::AlreadyExists(_) => 0x2400,
199 ErrorType::Unprepared(_) => 0x2500,
200 }
201 }
202}
203
204#[derive(Debug, PartialEq, Ord, PartialOrd, Eq, Copy, Clone, Hash)]
207pub struct UnavailableError {
208 pub cl: Consistency,
210 pub required: CInt,
212 pub alive: CInt,
214}
215
216impl Serialize for UnavailableError {
217 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
218 self.cl.serialize(cursor, version);
219 self.required.serialize(cursor, version);
220 self.alive.serialize(cursor, version);
221 }
222}
223
224impl FromCursor for UnavailableError {
225 fn from_cursor(
226 cursor: &mut Cursor<&[u8]>,
227 version: Version,
228 ) -> error::Result<UnavailableError> {
229 let cl = Consistency::from_cursor(cursor, version)?;
230 let required = CInt::from_cursor(cursor, version)?;
231 let alive = CInt::from_cursor(cursor, version)?;
232
233 Ok(UnavailableError {
234 cl,
235 required,
236 alive,
237 })
238 }
239}
240
241#[derive(Debug, PartialEq, Clone, Ord, PartialOrd, Eq, Hash)]
243pub struct WriteTimeoutError {
244 pub cl: Consistency,
246 pub received: CInt,
248 pub block_for: CInt,
250 pub write_type: WriteType,
252 pub contentions: Option<CIntShort>,
255}
256
257impl Serialize for WriteTimeoutError {
258 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
259 self.cl.serialize(cursor, version);
260 self.received.serialize(cursor, version);
261 self.block_for.serialize(cursor, version);
262 self.write_type.serialize(cursor, version);
263
264 if let Some(contentions) = self.contentions {
265 contentions.serialize(cursor, version);
266 }
267 }
268}
269
270impl FromCursor for WriteTimeoutError {
271 fn from_cursor(
272 cursor: &mut Cursor<&[u8]>,
273 version: Version,
274 ) -> error::Result<WriteTimeoutError> {
275 let cl = Consistency::from_cursor(cursor, version)?;
276 let received = CInt::from_cursor(cursor, version)?;
277 let block_for = CInt::from_cursor(cursor, version)?;
278 let write_type = WriteType::from_cursor(cursor, version)?;
279 let contentions = if write_type == WriteType::Cas {
280 Some(CIntShort::from_cursor(cursor, version)?)
281 } else {
282 None
283 };
284
285 Ok(WriteTimeoutError {
286 cl,
287 received,
288 block_for,
289 write_type,
290 contentions,
291 })
292 }
293}
294
295#[derive(Debug, PartialEq, Ord, PartialOrd, Eq, Copy, Clone, Hash)]
297pub struct ReadTimeoutError {
298 pub cl: Consistency,
300 pub received: CInt,
302 pub block_for: CInt,
304 data_present: u8,
305}
306
307impl Serialize for ReadTimeoutError {
308 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
309 self.cl.serialize(cursor, version);
310 self.received.serialize(cursor, version);
311 self.block_for.serialize(cursor, version);
312 self.data_present.serialize(cursor, version);
313 }
314}
315
316impl ReadTimeoutError {
317 #[inline]
319 pub fn replica_has_responded(&self) -> bool {
320 self.data_present != 0
321 }
322}
323
324impl FromCursor for ReadTimeoutError {
325 fn from_cursor(
326 cursor: &mut Cursor<&[u8]>,
327 version: Version,
328 ) -> error::Result<ReadTimeoutError> {
329 let cl = Consistency::from_cursor(cursor, version)?;
330 let received = CInt::from_cursor(cursor, version)?;
331 let block_for = CInt::from_cursor(cursor, version)?;
332
333 let mut buff = [0];
334 cursor.read_exact(&mut buff)?;
335
336 let data_present = buff[0];
337
338 Ok(ReadTimeoutError {
339 cl,
340 received,
341 block_for,
342 data_present,
343 })
344 }
345}
346
347#[derive(Debug, PartialEq, Eq, Clone)]
349pub struct ReadFailureError {
350 pub cl: Consistency,
352 pub received: CInt,
354 pub block_for: CInt,
356 pub failure_info: FailureInfo,
358 data_present: u8,
359}
360
361impl Serialize for ReadFailureError {
362 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
363 self.cl.serialize(cursor, version);
364 self.received.serialize(cursor, version);
365 self.block_for.serialize(cursor, version);
366 self.failure_info.serialize(cursor, version);
367 self.data_present.serialize(cursor, version);
368 }
369}
370
371impl ReadFailureError {
372 #[inline]
374 pub fn replica_has_responded(&self) -> bool {
375 self.data_present != 0
376 }
377}
378
379impl FromCursor for ReadFailureError {
380 fn from_cursor(
381 cursor: &mut Cursor<&[u8]>,
382 version: Version,
383 ) -> error::Result<ReadFailureError> {
384 let cl = Consistency::from_cursor(cursor, version)?;
385 let received = CInt::from_cursor(cursor, version)?;
386 let block_for = CInt::from_cursor(cursor, version)?;
387 let failure_info = FailureInfo::from_cursor(cursor, version)?;
388
389 let mut buff = [0];
390 cursor.read_exact(&mut buff)?;
391
392 let data_present = buff[0];
393
394 Ok(ReadFailureError {
395 cl,
396 received,
397 block_for,
398 failure_info,
399 data_present,
400 })
401 }
402}
403
404#[derive(Debug, PartialEq, Ord, PartialOrd, Eq, Hash, Clone)]
406pub struct FunctionFailureError {
407 pub keyspace: String,
409 pub function: String,
411 pub arg_types: Vec<String>,
413}
414
415impl Serialize for FunctionFailureError {
416 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
417 serialize_str(cursor, &self.keyspace, version);
418 serialize_str(cursor, &self.function, version);
419 serialize_str_list(cursor, self.arg_types.iter().map(|x| x.as_str()), version);
420 }
421}
422
423impl FromCursor for FunctionFailureError {
424 fn from_cursor(
425 cursor: &mut Cursor<&[u8]>,
426 _version: Version,
427 ) -> error::Result<FunctionFailureError> {
428 let keyspace = from_cursor_str(cursor)?.to_string();
429 let function = from_cursor_str(cursor)?.to_string();
430 let arg_types = from_cursor_string_list(cursor)?;
431
432 Ok(FunctionFailureError {
433 keyspace,
434 function,
435 arg_types,
436 })
437 }
438}
439
440#[derive(Debug, PartialEq, Eq, Clone)]
442pub struct WriteFailureError {
443 pub cl: Consistency,
445 pub received: CInt,
447 pub block_for: CInt,
449 pub failure_info: FailureInfo,
451 pub write_type: WriteType,
453}
454
455impl Serialize for WriteFailureError {
456 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
457 self.cl.serialize(cursor, version);
458 self.received.serialize(cursor, version);
459 self.block_for.serialize(cursor, version);
460 self.failure_info.serialize(cursor, version);
461 self.write_type.serialize(cursor, version);
462 }
463}
464
465impl FromCursor for WriteFailureError {
466 fn from_cursor(
467 cursor: &mut Cursor<&[u8]>,
468 version: Version,
469 ) -> error::Result<WriteFailureError> {
470 let cl = Consistency::from_cursor(cursor, version)?;
471 let received = CInt::from_cursor(cursor, version)?;
472 let block_for = CInt::from_cursor(cursor, version)?;
473 let failure_info = FailureInfo::from_cursor(cursor, version)?;
474 let write_type = WriteType::from_cursor(cursor, version)?;
475
476 Ok(WriteFailureError {
477 cl,
478 received,
479 block_for,
480 failure_info,
481 write_type,
482 })
483 }
484}
485
486#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Display)]
489#[non_exhaustive]
490pub enum WriteType {
491 Simple,
493 Batch,
496 UnloggedBatch,
498 Counter,
500 BatchLog,
503 Cas,
505 View,
508 Cdc,
511 Unknown(String),
513}
514
515impl Serialize for WriteType {
516 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
517 match self {
518 WriteType::Simple => serialize_str(cursor, "SIMPLE", version),
519 WriteType::Batch => serialize_str(cursor, "BATCH", version),
520 WriteType::UnloggedBatch => serialize_str(cursor, "UNLOGGED_BATCH", version),
521 WriteType::Counter => serialize_str(cursor, "COUNTER", version),
522 WriteType::BatchLog => serialize_str(cursor, "BATCH_LOG", version),
523 WriteType::Cas => serialize_str(cursor, "CAS", version),
524 WriteType::View => serialize_str(cursor, "VIEW", version),
525 WriteType::Cdc => serialize_str(cursor, "CDC", version),
526 WriteType::Unknown(write_type) => serialize_str(cursor, write_type, version),
527 }
528 }
529}
530
531impl FromCursor for WriteType {
532 fn from_cursor(cursor: &mut Cursor<&[u8]>, _version: Version) -> error::Result<WriteType> {
533 match from_cursor_str(cursor)? {
534 "SIMPLE" => Ok(WriteType::Simple),
535 "BATCH" => Ok(WriteType::Batch),
536 "UNLOGGED_BATCH" => Ok(WriteType::UnloggedBatch),
537 "COUNTER" => Ok(WriteType::Counter),
538 "BATCH_LOG" => Ok(WriteType::BatchLog),
539 "CAS" => Ok(WriteType::Cas),
540 "VIEW" => Ok(WriteType::View),
541 "CDC" => Ok(WriteType::Cdc),
542 wt => Ok(WriteType::Unknown(wt.into())),
543 }
544 }
545}
546
547#[derive(Debug, PartialEq, Ord, PartialOrd, Eq, Hash, Clone)]
550pub struct AlreadyExistsError {
551 pub ks: String,
554 pub table: String,
556}
557
558impl Serialize for AlreadyExistsError {
559 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
560 serialize_str(cursor, &self.ks, version);
561 serialize_str(cursor, &self.table, version);
562 }
563}
564
565impl FromCursor for AlreadyExistsError {
566 fn from_cursor(
567 cursor: &mut Cursor<&[u8]>,
568 _version: Version,
569 ) -> error::Result<AlreadyExistsError> {
570 let ks = from_cursor_str(cursor)?.to_string();
571 let table = from_cursor_str(cursor)?.to_string();
572
573 Ok(AlreadyExistsError { ks, table })
574 }
575}
576
577#[derive(Debug, PartialEq, Ord, PartialOrd, Eq, Hash, Clone)]
581pub struct UnpreparedError {
582 pub id: CBytesShort,
584}
585
586impl Serialize for UnpreparedError {
587 fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
588 self.id.serialize(cursor, version);
589 }
590}
591
592impl FromCursor for UnpreparedError {
593 fn from_cursor(cursor: &mut Cursor<&[u8]>, version: Version) -> error::Result<UnpreparedError> {
594 let id = CBytesShort::from_cursor(cursor, version)?;
595 Ok(UnpreparedError { id })
596 }
597}
598
599#[cfg(test)]
601fn test_encode_decode(bytes: &[u8], expected: ErrorBody) {
602 {
603 let mut cursor: Cursor<&[u8]> = Cursor::new(bytes);
604 let result = ErrorBody::from_cursor(&mut cursor, Version::V4).unwrap();
605 assert_eq!(expected, result);
606 }
607
608 {
609 let mut buffer = Vec::new();
610 let mut cursor = Cursor::new(&mut buffer);
611 expected.serialize(&mut cursor, Version::V4);
612 assert_eq!(buffer, bytes);
613 }
614}
615
616#[cfg(test)]
617mod error_tests {
618 use super::*;
619
620 #[test]
621 fn server() {
622 let bytes = &[
623 0, 0, 0, 0, 0, 3, 102, 111, 111, ];
626 let expected = ErrorBody {
627 message: "foo".into(),
628 ty: ErrorType::Server,
629 };
630 test_encode_decode(bytes, expected);
631 }
632
633 #[test]
634 fn protocol() {
635 let bytes = &[
636 0, 0, 0, 10, 0, 3, 102, 111, 111, ];
639 let expected = ErrorBody {
640 message: "foo".into(),
641 ty: ErrorType::Protocol,
642 };
643 test_encode_decode(bytes, expected);
644 }
645
646 #[test]
647 fn authentication() {
648 let bytes = &[
649 0, 0, 1, 0, 0, 3, 102, 111, 111, ];
652 let expected = ErrorBody {
653 message: "foo".into(),
654 ty: ErrorType::Authentication,
655 };
656 test_encode_decode(bytes, expected);
657 }
658
659 #[test]
660 fn unavailable() {
661 let bytes = &[
662 0, 0, 16, 0, 0, 3, 102, 111, 111, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, ];
670 let expected = ErrorBody {
671 message: "foo".into(),
672 ty: ErrorType::Unavailable(UnavailableError {
673 cl: Consistency::Any,
674 required: 1,
675 alive: 1,
676 }),
677 };
678 test_encode_decode(bytes, expected);
679 }
680
681 #[test]
682 fn overloaded() {
683 let bytes = &[
684 0, 0, 16, 1, 0, 3, 102, 111, 111, ];
687 let expected = ErrorBody {
688 message: "foo".into(),
689 ty: ErrorType::Overloaded,
690 };
691 test_encode_decode(bytes, expected);
692 }
693
694 #[test]
695 fn is_bootstrapping() {
696 let bytes = &[
697 0, 0, 16, 2, 0, 3, 102, 111, 111, ];
700 let expected = ErrorBody {
701 message: "foo".into(),
702 ty: ErrorType::IsBootstrapping,
703 };
704 test_encode_decode(bytes, expected);
705 }
706
707 #[test]
708 fn truncate() {
709 let bytes = &[
710 0, 0, 16, 3, 0, 3, 102, 111, 111, ];
713 let expected = ErrorBody {
714 message: "foo".into(),
715 ty: ErrorType::Truncate,
716 };
717 test_encode_decode(bytes, expected);
718 }
719
720 #[test]
721 fn write_timeout() {
722 let bytes = &[
723 0, 0, 17, 0, 0, 3, 102, 111, 111, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 6, 83, 73, 77, 80, 76, 69, ];
732 let expected = ErrorBody {
733 message: "foo".into(),
734 ty: ErrorType::WriteTimeout(WriteTimeoutError {
735 cl: Consistency::Any,
736 received: 1,
737 block_for: 1,
738 write_type: WriteType::Simple,
739 contentions: None,
740 }),
741 };
742 test_encode_decode(bytes, expected);
743 }
744
745 #[test]
746 fn read_timeout() {
747 let bytes = &[
748 0, 0, 18, 0, 0, 3, 102, 111, 111, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, ];
757 let expected = ErrorBody {
758 message: "foo".into(),
759 ty: ErrorType::ReadTimeout(ReadTimeoutError {
760 cl: Consistency::Any,
761 received: 1,
762 block_for: 1,
763 data_present: 0,
764 }),
765 };
766 test_encode_decode(bytes, expected);
767 }
768
769 #[test]
770 fn read_failure() {
771 let bytes = &[
772 0, 0, 19, 0, 0, 3, 102, 111, 111, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, ];
782 let expected = ErrorBody {
783 message: "foo".into(),
784 ty: ErrorType::ReadFailure(ReadFailureError {
785 cl: Consistency::Any,
786 received: 1,
787 block_for: 1,
788 failure_info: FailureInfo::NumFailures(1),
789 data_present: 0,
790 }),
791 };
792 test_encode_decode(bytes, expected);
793 }
794
795 #[test]
796 fn syntax() {
797 let bytes = &[
798 0, 0, 32, 0, 0, 3, 102, 111, 111, ];
801 let expected = ErrorBody {
802 message: "foo".into(),
803 ty: ErrorType::Syntax,
804 };
805 test_encode_decode(bytes, expected);
806 }
807
808 #[test]
809 fn unauthorized() {
810 let bytes = &[
811 0, 0, 33, 0, 0, 3, 102, 111, 111, ];
814 let expected = ErrorBody {
815 message: "foo".into(),
816 ty: ErrorType::Unauthorized,
817 };
818 test_encode_decode(bytes, expected);
819 }
820
821 #[test]
822 fn invalid() {
823 let bytes = &[
824 0, 0, 34, 0, 0, 3, 102, 111, 111, ];
827 let expected = ErrorBody {
828 message: "foo".into(),
829 ty: ErrorType::Invalid,
830 };
831 test_encode_decode(bytes, expected);
832 }
833
834 #[test]
835 fn config() {
836 let bytes = &[
837 0, 0, 35, 0, 0, 3, 102, 111, 111, ];
840 let expected = ErrorBody {
841 message: "foo".into(),
842 ty: ErrorType::Config,
843 };
844 test_encode_decode(bytes, expected);
845 }
846}