1pub mod cluster;
35pub mod sentinel;
36pub mod server;
37pub mod utils;
38
39use std::collections::{HashMap, HashSet, VecDeque};
40use std::sync::{Arc, Mutex};
41
42use redis::{
43 Cmd, ConnectionLike, ErrorKind, Pipeline, RedisError, RedisResult, ServerError, Value,
44};
45
46#[cfg(feature = "aio")]
47use futures::{FutureExt, future};
48
49#[cfg(feature = "aio")]
50use redis::{RedisFuture, aio::ConnectionLike as AioConnectionLike};
51
52pub trait IntoRedisValue {
56 fn into_redis_value(self) -> Value;
58}
59
60macro_rules! into_redis_value_impl_int {
61 ($t:ty) => {
62 impl IntoRedisValue for $t {
63 fn into_redis_value(self) -> Value {
64 Value::Int(self as i64)
65 }
66 }
67 };
68}
69
70into_redis_value_impl_int!(i8);
71into_redis_value_impl_int!(i16);
72into_redis_value_impl_int!(i32);
73into_redis_value_impl_int!(i64);
74into_redis_value_impl_int!(u8);
75into_redis_value_impl_int!(u16);
76into_redis_value_impl_int!(u32);
77
78macro_rules! into_redis_value_impl_float {
79 ($t:ty) => {
80 impl IntoRedisValue for $t {
81 fn into_redis_value(self) -> Value {
82 Value::Double(self as f64)
83 }
84 }
85 };
86}
87
88into_redis_value_impl_float!(f32);
89into_redis_value_impl_float!(f64);
90
91impl IntoRedisValue for String {
92 fn into_redis_value(self) -> Value {
93 Value::BulkString(self.as_bytes().to_vec())
94 }
95}
96
97impl IntoRedisValue for &str {
98 fn into_redis_value(self) -> Value {
99 Value::BulkString(self.as_bytes().to_vec())
100 }
101}
102
103impl IntoRedisValue for bool {
104 fn into_redis_value(self) -> Value {
105 Value::Boolean(self)
106 }
107}
108
109#[cfg(feature = "bytes")]
110impl IntoRedisValue for bytes::Bytes {
111 fn into_redis_value(self) -> Value {
112 Value::BulkString(self.to_vec())
113 }
114}
115
116impl IntoRedisValue for Vec<u8> {
117 fn into_redis_value(self) -> Value {
118 Value::BulkString(self)
119 }
120}
121
122impl IntoRedisValue for Vec<Value> {
123 fn into_redis_value(self) -> Value {
124 Value::Array(self)
125 }
126}
127
128impl IntoRedisValue for Vec<(Value, Value)> {
129 fn into_redis_value(self) -> Value {
130 Value::Map(self)
131 }
132}
133
134impl<K, V> IntoRedisValue for HashMap<K, V>
135where
136 K: IntoRedisValue,
137 V: IntoRedisValue,
138{
139 fn into_redis_value(self) -> Value {
140 Value::Map(
141 self.into_iter()
142 .map(|(k, v)| (k.into_redis_value(), v.into_redis_value()))
143 .collect(),
144 )
145 }
146}
147
148impl<V> IntoRedisValue for HashSet<V>
149where
150 V: IntoRedisValue,
151{
152 fn into_redis_value(self) -> Value {
153 Value::Set(
154 self.into_iter()
155 .map(IntoRedisValue::into_redis_value)
156 .collect(),
157 )
158 }
159}
160
161impl IntoRedisValue for Value {
162 fn into_redis_value(self) -> Value {
163 self
164 }
165}
166
167impl IntoRedisValue for ServerError {
168 fn into_redis_value(self) -> Value {
169 Value::ServerError(self)
170 }
171}
172
173#[macro_export]
202macro_rules! redis_value {
203 ({$($k:tt: $v:tt),* $(,)*}) => {
205 redis::Value::Map(vec![$(($crate::redis_value!($k), $crate::redis_value!($v))),*])
206 };
207
208 ([$($e:tt),* $(,)*]) => {
210 redis::Value::Array(vec![$($crate::redis_value!($e)),*])
211 };
212
213 (set:[$($e:tt),* $(,)*]) => {
215 redis::Value::Set(vec![$($crate::redis_value!($e)),*])
216 };
217
218 (simple:$e:tt) => {
220 redis::Value::SimpleString($e.to_string())
221 };
222
223 (nil) => {
225 redis::Value::Nil
226 };
227
228 (ok) => {
230 $crate::redis_value!(okay)
231 };
232
233 (okay) => {
234 redis::Value::Okay
235 };
236
237 (($context:tt:$e:tt)) => {
239 $crate::redis_value!($context:$e)
240 };
241
242 ($e:expr) => {
244 $crate::IntoRedisValue::into_redis_value($e)
245 };
246}
247
248pub trait IntoRedisCmdBytes {
251 fn into_redis_cmd_bytes(self) -> Vec<u8>;
253}
254
255impl IntoRedisCmdBytes for Cmd {
256 fn into_redis_cmd_bytes(self) -> Vec<u8> {
257 self.get_packed_command()
258 }
259}
260
261impl IntoRedisCmdBytes for &Cmd {
262 fn into_redis_cmd_bytes(self) -> Vec<u8> {
263 self.get_packed_command()
264 }
265}
266
267impl IntoRedisCmdBytes for &mut Cmd {
268 fn into_redis_cmd_bytes(self) -> Vec<u8> {
269 self.get_packed_command()
270 }
271}
272
273impl IntoRedisCmdBytes for Pipeline {
274 fn into_redis_cmd_bytes(self) -> Vec<u8> {
275 self.get_packed_pipeline()
276 }
277}
278
279impl IntoRedisCmdBytes for &Pipeline {
280 fn into_redis_cmd_bytes(self) -> Vec<u8> {
281 self.get_packed_pipeline()
282 }
283}
284
285impl IntoRedisCmdBytes for &mut Pipeline {
286 fn into_redis_cmd_bytes(self) -> Vec<u8> {
287 self.get_packed_pipeline()
288 }
289}
290
291#[derive(Clone)]
293pub struct MockCmd {
294 cmd_bytes: Vec<u8>,
295 responses: Result<Vec<Value>, RedisError>,
296}
297
298impl MockCmd {
299 pub fn new<C, V>(cmd: C, response: Result<V, RedisError>) -> Self
302 where
303 C: IntoRedisCmdBytes,
304 V: IntoRedisValue,
305 {
306 MockCmd {
307 cmd_bytes: cmd.into_redis_cmd_bytes(),
308 responses: response.map(|r| vec![r.into_redis_value()]),
309 }
310 }
311
312 pub fn with_values<C, V>(cmd: C, responses: Result<Vec<V>, RedisError>) -> Self
315 where
316 C: IntoRedisCmdBytes,
317 V: IntoRedisValue,
318 {
319 MockCmd {
320 cmd_bytes: cmd.into_redis_cmd_bytes(),
321 responses: responses.map(|xs| xs.into_iter().map(|x| x.into_redis_value()).collect()),
322 }
323 }
324}
325
326#[derive(Clone)]
329pub struct MockRedisConnection {
330 commands: Arc<Mutex<VecDeque<MockCmd>>>,
331 assert_is_empty_on_drop: bool,
332}
333
334impl MockRedisConnection {
335 pub fn new<I>(commands: I) -> Self
337 where
338 I: IntoIterator<Item = MockCmd>,
339 {
340 MockRedisConnection {
341 commands: Arc::new(Mutex::new(VecDeque::from_iter(commands))),
342 assert_is_empty_on_drop: false,
343 }
344 }
345
346 pub fn assert_all_commands_consumed(mut self) -> Self {
348 self.assert_is_empty_on_drop = true;
349 self
350 }
351}
352
353impl Drop for MockRedisConnection {
354 fn drop(&mut self) {
355 if self.assert_is_empty_on_drop {
356 let commands = self.commands.lock().unwrap();
357 if Arc::strong_count(&self.commands) == 1 {
358 assert!(commands.back().is_none());
359 }
360 }
361 }
362}
363
364impl MockRedisConnection {
365 pub fn is_empty(&self) -> bool {
366 self.commands.lock().unwrap().is_empty()
367 }
368}
369
370impl ConnectionLike for MockRedisConnection {
371 fn req_packed_command(&mut self, cmd: &[u8]) -> RedisResult<Value> {
372 let mut commands = self.commands.lock().unwrap();
373 let next_cmd = commands.pop_front().ok_or_else(|| {
374 self.assert_is_empty_on_drop = false;
375 RedisError::from((ErrorKind::Client, "TEST", "unexpected command".to_owned()))
376 })?;
377
378 if cmd != next_cmd.cmd_bytes {
379 self.assert_is_empty_on_drop = false;
380 return Err(RedisError::from((
381 ErrorKind::Client,
382 "TEST",
383 format!(
384 "unexpected command: expected={}, actual={}",
385 String::from_utf8(next_cmd.cmd_bytes)
386 .unwrap_or_else(|_| "decode error".to_owned()),
387 String::from_utf8(Vec::from(cmd)).unwrap_or_else(|_| "decode error".to_owned()),
388 ),
389 )));
390 }
391
392 next_cmd
393 .responses
394 .and_then(|values| match values.as_slice() {
395 [value] => Ok(value.clone()),
396 [] => {
397 self.assert_is_empty_on_drop = false;
398 Err(RedisError::from((
399 ErrorKind::Client,
400 "no value configured as response",
401 )))},
402 _ => {
403 self.assert_is_empty_on_drop = false;
404 Err(RedisError::from((
405 ErrorKind::Client,
406 "multiple values configured as response for command expecting a single value",
407 )))},
408 })
409 }
410
411 fn req_packed_commands(
412 &mut self,
413 cmd: &[u8],
414 _offset: usize,
415 _count: usize,
416 ) -> RedisResult<Vec<Value>> {
417 let mut commands = self.commands.lock().unwrap();
418 let next_cmd = commands.pop_front().ok_or_else(|| {
419 RedisError::from((ErrorKind::Client, "TEST", "unexpected command".to_owned()))
420 })?;
421
422 if cmd != next_cmd.cmd_bytes {
423 return Err(RedisError::from((
424 ErrorKind::Client,
425 "TEST",
426 format!(
427 "unexpected command: expected={}, actual={}",
428 String::from_utf8(next_cmd.cmd_bytes)
429 .unwrap_or_else(|_| "decode error".to_owned()),
430 String::from_utf8(Vec::from(cmd)).unwrap_or_else(|_| "decode error".to_owned()),
431 ),
432 )));
433 }
434
435 next_cmd.responses
436 }
437
438 fn get_db(&self) -> i64 {
439 0
440 }
441
442 fn check_connection(&mut self) -> bool {
443 true
444 }
445
446 fn is_open(&self) -> bool {
447 true
448 }
449}
450
451#[cfg(feature = "aio")]
452impl AioConnectionLike for MockRedisConnection {
453 fn req_packed_command<'a>(&'a mut self, cmd: &'a Cmd) -> RedisFuture<'a, Value> {
454 let packed_cmd = cmd.get_packed_command();
455 let response = <MockRedisConnection as ConnectionLike>::req_packed_command(
456 self,
457 packed_cmd.as_slice(),
458 );
459 future::ready(response).boxed()
460 }
461
462 fn req_packed_commands<'a>(
463 &'a mut self,
464 cmd: &'a Pipeline,
465 offset: usize,
466 count: usize,
467 ) -> RedisFuture<'a, Vec<Value>> {
468 let packed_cmd = cmd.get_packed_pipeline();
469 let response = <MockRedisConnection as ConnectionLike>::req_packed_commands(
470 self,
471 packed_cmd.as_slice(),
472 offset,
473 count,
474 );
475 future::ready(response).boxed()
476 }
477
478 fn get_db(&self) -> i64 {
479 0
480 }
481}
482
483#[cfg(test)]
484mod tests {
485 use super::{IntoRedisValue, MockCmd, MockRedisConnection};
486 use redis::{ErrorKind, ServerError, Value, cmd, make_extension_error, pipe};
487 use std::collections::{HashMap, HashSet};
488
489 #[test]
490 fn into_redis_value_i8() {
491 assert_eq!(42_i8.into_redis_value(), Value::Int(42));
492 }
493
494 #[test]
495 fn into_redis_value_i16() {
496 assert_eq!(42_i16.into_redis_value(), Value::Int(42));
497 }
498
499 #[test]
500 fn into_redis_value_i32() {
501 assert_eq!(42_i32.into_redis_value(), Value::Int(42));
502 }
503
504 #[test]
505 fn into_redis_value_i64() {
506 assert_eq!(42_i64.into_redis_value(), Value::Int(42));
507 }
508
509 #[test]
510 fn into_redis_value_u8() {
511 assert_eq!(42_u8.into_redis_value(), Value::Int(42));
512 }
513
514 #[test]
515 fn into_redis_value_u16() {
516 assert_eq!(42_u16.into_redis_value(), Value::Int(42));
517 }
518
519 #[test]
520 fn into_redis_value_u32() {
521 assert_eq!(42_u32.into_redis_value(), Value::Int(42));
522 }
523
524 #[test]
525 fn into_redis_value_string() {
526 let input = "foo".to_string();
527
528 let actual = input.into_redis_value();
529
530 let expected = Value::BulkString(vec![
531 0x66, 0x6f, 0x6f, ]);
535 assert_eq!(actual, expected);
536 }
537
538 #[test]
539 fn into_redis_value_str_ref() {
540 let input = "foo";
541
542 let actual = input.into_redis_value();
543
544 let expected = Value::BulkString(vec![
545 0x66, 0x6f, 0x6f, ]);
549 assert_eq!(actual, expected);
550 }
551
552 #[test]
553 fn into_redis_value_bool_true() {
554 assert_eq!(true.into_redis_value(), Value::Boolean(true));
555 }
556
557 #[test]
558 fn into_redis_value_bool_false() {
559 assert_eq!(false.into_redis_value(), Value::Boolean(false));
560 }
561
562 #[cfg(feature = "bytes")]
563 #[test]
564 fn into_redis_value_bytes() {
565 let input = bytes::Bytes::from("foo");
566
567 let actual = input.into_redis_value();
568
569 let expected = Value::BulkString(vec![
570 0x66, 0x6f, 0x6f, ]);
574 assert_eq!(actual, expected);
575 }
576
577 #[test]
578 fn into_redis_value_vec_u8() {
579 let input = vec![0x66 , 0x6f , 0x6f ];
580
581 let actual = input.into_redis_value();
582
583 let expected = Value::BulkString(vec![
584 0x66, 0x6f, 0x6f, ]);
588 assert_eq!(actual, expected);
589 }
590
591 #[test]
592 fn into_redis_value_vec_value() {
593 let input = vec![Value::Int(42), Value::Boolean(true)];
594
595 let actual = input.into_redis_value();
596
597 let expected = Value::Array(vec![Value::Int(42), Value::Boolean(true)]);
598 assert_eq!(actual, expected);
599 }
600
601 #[test]
602 fn into_redis_value_vec_value_value() {
603 let input = vec![
604 (Value::Int(42), Value::Boolean(true)),
605 (Value::Int(23), Value::Nil),
606 ];
607
608 let actual = input.into_redis_value();
609
610 let expected = Value::Map(vec![
611 (Value::Int(42), Value::Boolean(true)),
612 (Value::Int(23), Value::Nil),
613 ]);
614 assert_eq!(actual, expected);
615 }
616
617 #[test]
618 fn into_redis_value_hashmap() {
619 let input = HashMap::from([(23, true), (42, false)]);
620
621 let actual = input.into_redis_value();
622
623 let mut actual_entries = actual
624 .into_map_iter()
625 .expect("extracting elements should work")
626 .collect::<Vec<(Value, Value)>>();
627
628 actual_entries.sort_by(|a, b| {
630 let Value::Int(int_key_a) = a.0 else {
631 panic!("left-hand argument has to be a `Value::Int`");
632 };
633 let Value::Int(int_key_b) = b.0 else {
634 panic!("right-hand argument has to be a `Value::Int`");
635 };
636 int_key_a.cmp(&int_key_b)
637 });
638
639 let expected_entries = vec![
640 (Value::Int(23), Value::Boolean(true)),
641 (Value::Int(42), Value::Boolean(false)),
642 ];
643
644 assert_eq!(actual_entries, expected_entries);
645 }
646
647 #[test]
648 fn into_redis_value_hashset() {
649 let input = HashSet::from([23, 42]);
650
651 let actual = input.into_redis_value();
652
653 let mut actual_entries = actual
654 .into_sequence()
655 .expect("extracting elements should work");
656
657 actual_entries.sort_by(|a, b| {
659 let Value::Int(int_a) = a else {
660 panic!("left-hand argument has to be a `Value::Int`");
661 };
662 let Value::Int(int_b) = b else {
663 panic!("right-hand argument has to be a `Value::Int`");
664 };
665 int_a.cmp(int_b)
666 });
667
668 let expected_entries = vec![Value::Int(23), Value::Int(42)];
669
670 assert_eq!(actual_entries, expected_entries);
671 }
672
673 #[test]
674 fn into_redis_value_value() {
675 let input = Value::Int(42);
676
677 let actual = input.into_redis_value();
678
679 assert_eq!(actual, Value::Int(42));
680 }
681
682 #[test]
683 fn into_redis_value_server_error() {
684 let server_error = ServerError::try_from(make_extension_error("FOO".to_string(), None))
685 .expect("conversion should work");
686
687 let actual = server_error.clone().into_redis_value();
688
689 assert_eq!(actual, Value::ServerError(server_error));
690 }
691
692 #[test]
693 fn redis_simple_direct() {
694 assert_eq!(
695 redis_value!(simple:"foo"),
696 Value::SimpleString("foo".to_string())
697 );
698 }
699
700 #[test]
701 fn redis_simple_in_complex() {
702 let actual = redis_value!([(simple:"foo")]);
703
704 let expected = Value::Array(vec![Value::SimpleString("foo".to_string())]);
705 assert_eq!(actual, expected);
706 }
707
708 #[test]
709 fn redis_nil() {
710 assert_eq!(redis_value!(nil), Value::Nil);
711 }
712
713 #[test]
714 fn redis_ok() {
715 assert_eq!(redis_value!(ok), Value::Okay);
716 }
717
718 #[test]
719 fn redis_okay() {
720 assert_eq!(redis_value!(okay), Value::Okay);
721 }
722
723 #[test]
724 fn redis_i8() {
725 assert_eq!(redis_value!(42_i8), Value::Int(42));
726 }
727
728 #[test]
729 fn redis_i16() {
730 assert_eq!(redis_value!(42_i16), Value::Int(42));
731 }
732
733 #[test]
734 fn redis_i32() {
735 assert_eq!(redis_value!(42_i32), Value::Int(42));
736 }
737
738 #[test]
739 fn redis_i64() {
740 assert_eq!(redis_value!(42_i64), Value::Int(42));
741 }
742
743 #[test]
744 fn redis_u8() {
745 assert_eq!(redis_value!(42_u8), Value::Int(42));
746 }
747
748 #[test]
749 fn redis_u16() {
750 assert_eq!(redis_value!(42_u16), Value::Int(42));
751 }
752
753 #[test]
754 fn redis_u32() {
755 assert_eq!(redis_value!(42_u32), Value::Int(42));
756 }
757
758 #[test]
759 fn redis_string() {
760 let actual = redis_value!("foo".to_string());
761
762 let expected = Value::BulkString(vec![
763 0x66, 0x6f, 0x6f, ]);
767 assert_eq!(actual, expected);
768 }
769
770 #[test]
771 fn redis_str_ref() {
772 let actual = redis_value!("foo");
773
774 let expected = Value::BulkString(vec![
775 0x66, 0x6f, 0x6f, ]);
779 assert_eq!(actual, expected);
780 }
781
782 #[test]
783 fn redis_true() {
784 assert_eq!(redis_value!(true), Value::Boolean(true));
785 }
786
787 #[test]
788 fn redis_false() {
789 assert_eq!(redis_value!(false), Value::Boolean(false));
790 }
791
792 #[test]
793 fn redis_value() {
794 let actual = Value::Int(42);
795
796 assert_eq!(redis_value!(actual), Value::Int(42));
797 }
798
799 #[test]
800 fn redis_array_empty() {
801 assert_eq!(redis_value!([]), Value::Array(vec![]));
802 }
803
804 #[test]
805 fn redis_array_single_entry() {
806 let actual = redis_value!([42]);
807
808 let expected = Value::Array(vec![Value::Int(42)]);
809 assert_eq!(actual, expected);
810 }
811
812 #[test]
813 fn redis_array_single_entry_trailing_comma() {
814 let actual = redis_value!([42,]);
815
816 let expected = Value::Array(vec![Value::Int(42)]);
817 assert_eq!(actual, expected);
818 }
819
820 #[test]
821 fn redis_array_multiple_primitive_entries() {
822 let last_arg = Value::Boolean(true); let actual = redis_value!([42, "foo", nil, last_arg]);
824
825 let expected1 = Value::Int(42);
826 let expected2 = Value::BulkString(vec![
827 0x66, 0x6f, 0x6f, ]);
831 let expected3 = Value::Nil;
832 let expected4 = Value::Boolean(true);
833 let expected = Value::Array(vec![expected1, expected2, expected3, expected4]);
834 assert_eq!(actual, expected);
835 }
836
837 #[test]
838 fn redis_array_multiple_entries() {
839 let last_arg = Value::Boolean(true); let actual = redis_value!([42, ["foo", nil,], last_arg]);
841
842 let expected1 = Value::Int(42);
843 let expected21 = Value::BulkString(vec![
844 0x66, 0x6f, 0x6f, ]);
848 let expected22 = Value::Nil;
849 let expected2 = Value::Array(vec![expected21, expected22]);
850 let expected3 = Value::Boolean(true);
851 let expected = Value::Array(vec![expected1, expected2, expected3]);
852 assert_eq!(actual, expected);
853 }
854
855 #[test]
856 fn redis_set_empty() {
857 assert_eq!(redis_value!(set:[]), Value::Set(vec![]));
858 }
859
860 #[test]
861 fn redis_set_single_entry() {
862 let actual = redis_value!(set:[42]);
863
864 let expected = Value::Set(vec![Value::Int(42)]);
865 assert_eq!(actual, expected);
866 }
867
868 #[test]
869 fn redis_set_single_entry_trailing_comma() {
870 let actual = redis_value!(set:[42,]);
871
872 let expected = Value::Set(vec![Value::Int(42)]);
873 assert_eq!(actual, expected);
874 }
875
876 #[test]
877 fn redis_set_multiple_primitive_entries() {
878 let last_arg = Value::Boolean(true); let actual = redis_value!(set:[42, "foo", nil, last_arg]);
880
881 let expected1 = Value::Int(42);
882 let expected2 = Value::BulkString(vec![
883 0x66, 0x6f, 0x6f, ]);
887 let expected3 = Value::Nil;
888 let expected4 = Value::Boolean(true);
889 let expected = Value::Set(vec![expected1, expected2, expected3, expected4]);
890 assert_eq!(actual, expected);
891 }
892
893 #[test]
894 fn redis_set_multiple_entries() {
895 let last_arg = Value::Boolean(true); let actual = redis_value!(set:[42, (set:["foo", nil,]), last_arg]);
897
898 let expected1 = Value::Int(42);
899 let expected21 = Value::BulkString(vec![
900 0x66, 0x6f, 0x6f, ]);
904 let expected22 = Value::Nil;
905 let expected2 = Value::Set(vec![expected21, expected22]);
906 let expected3 = Value::Boolean(true);
907 let expected = Value::Set(vec![expected1, expected2, expected3]);
908 assert_eq!(actual, expected);
909 }
910
911 #[test]
912 fn redis_map_empty() {
913 assert_eq!(redis_value!({}), Value::Map(vec![]));
914 }
915
916 #[test]
917 fn redis_map_single_entry() {
918 let actual = redis_value!({42: true});
919
920 let expected = Value::Map(vec![(Value::Int(42), Value::Boolean(true))]);
921 assert_eq!(actual, expected);
922 }
923
924 #[test]
925 fn redis_map_single_entry_trailing_comma() {
926 let actual = redis_value!({42: true,});
927
928 let expected = Value::Map(vec![(Value::Int(42), Value::Boolean(true))]);
929 assert_eq!(actual, expected);
930 }
931
932 #[test]
933 fn redis_map_multiple_primitive_entries() {
934 let actual = redis_value!({42: true, nil: "foo"});
935
936 let expected1 = (Value::Int(42), Value::Boolean(true));
937 let expected2 = (
938 Value::Nil,
939 Value::BulkString(vec![
940 0x66, 0x6f, 0x6f, ]),
944 );
945 let expected = Value::Map(vec![expected1, expected2]);
946 assert_eq!(actual, expected);
947 }
948
949 #[test]
950 fn redis_map_multiple_entries() {
951 let actual = redis_value!({[42, false]: {true: [23, 4711],}, nil: "foo"});
952
953 let expected1_key = Value::Array(vec![Value::Int(42), Value::Boolean(false)]);
954 let expected1_value_key = Value::Boolean(true);
955 let expected1_value_value = Value::Array(vec![Value::Int(23), Value::Int(4711)]);
956 let expected1_value = Value::Map(vec![(expected1_value_key, expected1_value_value)]);
957 let expected1 = (expected1_key, expected1_value);
958 let expected2 = (
959 Value::Nil,
960 Value::BulkString(vec![
961 0x66, 0x6f, 0x6f, ]),
965 );
966 let expected = Value::Map(vec![expected1, expected2]);
967 assert_eq!(actual, expected);
968 }
969
970 #[test]
971 fn sync_basic_test() {
972 let mut conn = MockRedisConnection::new(vec![
973 MockCmd::new(cmd("SET").arg("foo").arg(42), Ok("")),
974 MockCmd::new(cmd("GET").arg("foo"), Ok(42)),
975 MockCmd::new(cmd("SET").arg("bar").arg("foo"), Ok("")),
976 MockCmd::new(cmd("GET").arg("bar"), Ok("foo")),
977 ])
978 .assert_all_commands_consumed();
979
980 cmd("SET").arg("foo").arg(42).exec(&mut conn).unwrap();
981 assert_eq!(cmd("GET").arg("foo").query(&mut conn), Ok(42));
982
983 cmd("SET").arg("bar").arg("foo").exec(&mut conn).unwrap();
984 assert_eq!(
985 cmd("GET").arg("bar").query(&mut conn),
986 Ok(Value::BulkString(b"foo".as_ref().into()))
987 );
988 }
989
990 #[cfg(feature = "aio")]
991 #[tokio::test]
992 async fn async_basic_test() {
993 let mut conn = MockRedisConnection::new(vec![
994 MockCmd::new(cmd("SET").arg("foo").arg(42), Ok("")),
995 MockCmd::new(cmd("GET").arg("foo"), Ok(42)),
996 MockCmd::new(cmd("SET").arg("bar").arg("foo"), Ok("")),
997 MockCmd::new(cmd("GET").arg("bar"), Ok("foo")),
998 ])
999 .assert_all_commands_consumed();
1000
1001 cmd("SET")
1002 .arg("foo")
1003 .arg("42")
1004 .exec_async(&mut conn)
1005 .await
1006 .unwrap();
1007 let result: Result<usize, _> = cmd("GET").arg("foo").query_async(&mut conn).await;
1008 assert_eq!(result, Ok(42));
1009
1010 cmd("SET")
1011 .arg("bar")
1012 .arg("foo")
1013 .exec_async(&mut conn)
1014 .await
1015 .unwrap();
1016 let result: Result<Vec<u8>, _> = cmd("GET").arg("bar").query_async(&mut conn).await;
1017 assert_eq!(result.as_deref(), Ok(&b"foo"[..]));
1018 }
1019
1020 #[test]
1021 fn errors_for_unexpected_commands() {
1022 let mut conn = MockRedisConnection::new(vec![
1023 MockCmd::new(cmd("SET").arg("foo").arg(42), Ok("")),
1024 MockCmd::new(cmd("GET").arg("foo"), Ok(42)),
1025 ])
1026 .assert_all_commands_consumed();
1027
1028 cmd("SET").arg("foo").arg(42).exec(&mut conn).unwrap();
1029 assert_eq!(cmd("GET").arg("foo").query(&mut conn), Ok(42));
1030
1031 let err = cmd("SET")
1032 .arg("bar")
1033 .arg("foo")
1034 .exec(&mut conn)
1035 .unwrap_err();
1036 assert_eq!(err.kind(), ErrorKind::Client);
1037 assert_eq!(err.detail(), Some("unexpected command"));
1038 }
1039
1040 #[test]
1041 fn errors_for_mismatched_commands() {
1042 let mut conn = MockRedisConnection::new(vec![
1043 MockCmd::new(cmd("SET").arg("foo").arg(42), Ok("")),
1044 MockCmd::new(cmd("GET").arg("foo"), Ok(42)),
1045 MockCmd::new(cmd("SET").arg("bar").arg("foo"), Ok("")),
1046 ])
1047 .assert_all_commands_consumed();
1048
1049 cmd("SET").arg("foo").arg(42).exec(&mut conn).unwrap();
1050 let err = cmd("SET")
1051 .arg("bar")
1052 .arg("foo")
1053 .exec(&mut conn)
1054 .unwrap_err();
1055 assert_eq!(err.kind(), ErrorKind::Client);
1056 assert!(err.detail().unwrap().contains("unexpected command"));
1057 }
1058
1059 #[test]
1060 fn pipeline_basic_test() {
1061 let mut conn = MockRedisConnection::new(vec![MockCmd::with_values(
1062 pipe().cmd("GET").arg("foo").cmd("GET").arg("bar"),
1063 Ok(vec!["hello", "world"]),
1064 )])
1065 .assert_all_commands_consumed();
1066
1067 let results: Vec<String> = pipe()
1068 .cmd("GET")
1069 .arg("foo")
1070 .cmd("GET")
1071 .arg("bar")
1072 .query(&mut conn)
1073 .expect("success");
1074 assert_eq!(results, vec!["hello", "world"]);
1075 }
1076
1077 #[test]
1078 fn pipeline_atomic_test() {
1079 let mut conn = MockRedisConnection::new(vec![MockCmd::with_values(
1080 pipe().atomic().cmd("GET").arg("foo").cmd("GET").arg("bar"),
1081 Ok(vec![Value::Array(
1082 vec!["hello", "world"]
1083 .into_iter()
1084 .map(|x| Value::BulkString(x.as_bytes().into()))
1085 .collect(),
1086 )]),
1087 )])
1088 .assert_all_commands_consumed();
1089
1090 let results: Vec<String> = pipe()
1091 .atomic()
1092 .cmd("GET")
1093 .arg("foo")
1094 .cmd("GET")
1095 .arg("bar")
1096 .query(&mut conn)
1097 .expect("success");
1098 assert_eq!(results, vec!["hello", "world"]);
1099 }
1100}