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