1 #![allow(clippy::let_unit_value)]
2 
3 use redis::{Commands, ConnectionInfo, ConnectionLike, ControlFlow, PubSubCommands};
4 
5 use std::collections::{BTreeMap, BTreeSet};
6 use std::collections::{HashMap, HashSet};
7 use std::io::BufReader;
8 use std::thread::{sleep, spawn};
9 use std::time::Duration;
10 
11 use crate::support::*;
12 
13 mod support;
14 
15 #[test]
test_parse_redis_url()16 fn test_parse_redis_url() {
17     let redis_url = "redis://127.0.0.1:1234/0".to_string();
18     redis::parse_redis_url(&redis_url).unwrap();
19     redis::parse_redis_url("unix:/var/run/redis/redis.sock").unwrap();
20     assert!(redis::parse_redis_url("127.0.0.1").is_err());
21 }
22 
23 #[test]
test_redis_url_fromstr()24 fn test_redis_url_fromstr() {
25     let _info: ConnectionInfo = "redis://127.0.0.1:1234/0".parse().unwrap();
26 }
27 
28 #[test]
test_args()29 fn test_args() {
30     let ctx = TestContext::new();
31     let mut con = ctx.connection();
32 
33     redis::cmd("SET").arg("key1").arg(b"foo").execute(&mut con);
34     redis::cmd("SET").arg(&["key2", "bar"]).execute(&mut con);
35 
36     assert_eq!(
37         redis::cmd("MGET").arg(&["key1", "key2"]).query(&mut con),
38         Ok(("foo".to_string(), b"bar".to_vec()))
39     );
40 }
41 
42 #[test]
test_getset()43 fn test_getset() {
44     let ctx = TestContext::new();
45     let mut con = ctx.connection();
46 
47     redis::cmd("SET").arg("foo").arg(42).execute(&mut con);
48     assert_eq!(redis::cmd("GET").arg("foo").query(&mut con), Ok(42));
49 
50     redis::cmd("SET").arg("bar").arg("foo").execute(&mut con);
51     assert_eq!(
52         redis::cmd("GET").arg("bar").query(&mut con),
53         Ok(b"foo".to_vec())
54     );
55 }
56 
57 #[test]
test_incr()58 fn test_incr() {
59     let ctx = TestContext::new();
60     let mut con = ctx.connection();
61 
62     redis::cmd("SET").arg("foo").arg(42).execute(&mut con);
63     assert_eq!(redis::cmd("INCR").arg("foo").query(&mut con), Ok(43usize));
64 }
65 
66 #[test]
test_info()67 fn test_info() {
68     let ctx = TestContext::new();
69     let mut con = ctx.connection();
70 
71     let info: redis::InfoDict = redis::cmd("INFO").query(&mut con).unwrap();
72     assert_eq!(
73         info.find(&"role"),
74         Some(&redis::Value::Status("master".to_string()))
75     );
76     assert_eq!(info.get("role"), Some("master".to_string()));
77     assert_eq!(info.get("loading"), Some(false));
78     assert!(!info.is_empty());
79     assert!(info.contains_key(&"role"));
80 }
81 
82 #[test]
test_hash_ops()83 fn test_hash_ops() {
84     let ctx = TestContext::new();
85     let mut con = ctx.connection();
86 
87     redis::cmd("HSET")
88         .arg("foo")
89         .arg("key_1")
90         .arg(1)
91         .execute(&mut con);
92     redis::cmd("HSET")
93         .arg("foo")
94         .arg("key_2")
95         .arg(2)
96         .execute(&mut con);
97 
98     let h: HashMap<String, i32> = redis::cmd("HGETALL").arg("foo").query(&mut con).unwrap();
99     assert_eq!(h.len(), 2);
100     assert_eq!(h.get("key_1"), Some(&1i32));
101     assert_eq!(h.get("key_2"), Some(&2i32));
102 
103     let h: BTreeMap<String, i32> = redis::cmd("HGETALL").arg("foo").query(&mut con).unwrap();
104     assert_eq!(h.len(), 2);
105     assert_eq!(h.get("key_1"), Some(&1i32));
106     assert_eq!(h.get("key_2"), Some(&2i32));
107 }
108 
109 #[test]
test_set_ops()110 fn test_set_ops() {
111     let ctx = TestContext::new();
112     let mut con = ctx.connection();
113 
114     redis::cmd("SADD").arg("foo").arg(1).execute(&mut con);
115     redis::cmd("SADD").arg("foo").arg(2).execute(&mut con);
116     redis::cmd("SADD").arg("foo").arg(3).execute(&mut con);
117 
118     let mut s: Vec<i32> = redis::cmd("SMEMBERS").arg("foo").query(&mut con).unwrap();
119     s.sort();
120     assert_eq!(s.len(), 3);
121     assert_eq!(&s, &[1, 2, 3]);
122 
123     let set: HashSet<i32> = redis::cmd("SMEMBERS").arg("foo").query(&mut con).unwrap();
124     assert_eq!(set.len(), 3);
125     assert!(set.contains(&1i32));
126     assert!(set.contains(&2i32));
127     assert!(set.contains(&3i32));
128 
129     let set: BTreeSet<i32> = redis::cmd("SMEMBERS").arg("foo").query(&mut con).unwrap();
130     assert_eq!(set.len(), 3);
131     assert!(set.contains(&1i32));
132     assert!(set.contains(&2i32));
133     assert!(set.contains(&3i32));
134 }
135 
136 #[test]
test_scan()137 fn test_scan() {
138     let ctx = TestContext::new();
139     let mut con = ctx.connection();
140 
141     redis::cmd("SADD").arg("foo").arg(1).execute(&mut con);
142     redis::cmd("SADD").arg("foo").arg(2).execute(&mut con);
143     redis::cmd("SADD").arg("foo").arg(3).execute(&mut con);
144 
145     let (cur, mut s): (i32, Vec<i32>) = redis::cmd("SSCAN")
146         .arg("foo")
147         .arg(0)
148         .query(&mut con)
149         .unwrap();
150     s.sort();
151     assert_eq!(cur, 0i32);
152     assert_eq!(s.len(), 3);
153     assert_eq!(&s, &[1, 2, 3]);
154 }
155 
156 #[test]
test_optionals()157 fn test_optionals() {
158     let ctx = TestContext::new();
159     let mut con = ctx.connection();
160 
161     redis::cmd("SET").arg("foo").arg(1).execute(&mut con);
162 
163     let (a, b): (Option<i32>, Option<i32>) = redis::cmd("MGET")
164         .arg("foo")
165         .arg("missing")
166         .query(&mut con)
167         .unwrap();
168     assert_eq!(a, Some(1i32));
169     assert_eq!(b, None);
170 
171     let a = redis::cmd("GET")
172         .arg("missing")
173         .query(&mut con)
174         .unwrap_or(0i32);
175     assert_eq!(a, 0i32);
176 }
177 
178 #[test]
test_scanning()179 fn test_scanning() {
180     let ctx = TestContext::new();
181     let mut con = ctx.connection();
182     let mut unseen = HashSet::new();
183 
184     for x in 0..1000 {
185         redis::cmd("SADD").arg("foo").arg(x).execute(&mut con);
186         unseen.insert(x);
187     }
188 
189     let iter = redis::cmd("SSCAN")
190         .arg("foo")
191         .cursor_arg(0)
192         .clone()
193         .iter(&mut con)
194         .unwrap();
195 
196     for x in iter {
197         // type inference limitations
198         let x: usize = x;
199         unseen.remove(&x);
200     }
201 
202     assert_eq!(unseen.len(), 0);
203 }
204 
205 #[test]
test_filtered_scanning()206 fn test_filtered_scanning() {
207     let ctx = TestContext::new();
208     let mut con = ctx.connection();
209     let mut unseen = HashSet::new();
210 
211     for x in 0..3000 {
212         let _: () = con
213             .hset("foo", format!("key_{}_{}", x % 100, x), x)
214             .unwrap();
215         if x % 100 == 0 {
216             unseen.insert(x);
217         }
218     }
219 
220     let iter = con.hscan_match("foo", "key_0_*").unwrap();
221 
222     for x in iter {
223         // type inference limitations
224         let x: usize = x;
225         unseen.remove(&x);
226     }
227 
228     assert_eq!(unseen.len(), 0);
229 }
230 
231 #[test]
test_pipeline()232 fn test_pipeline() {
233     let ctx = TestContext::new();
234     let mut con = ctx.connection();
235 
236     let ((k1, k2),): ((i32, i32),) = redis::pipe()
237         .cmd("SET")
238         .arg("key_1")
239         .arg(42)
240         .ignore()
241         .cmd("SET")
242         .arg("key_2")
243         .arg(43)
244         .ignore()
245         .cmd("MGET")
246         .arg(&["key_1", "key_2"])
247         .query(&mut con)
248         .unwrap();
249 
250     assert_eq!(k1, 42);
251     assert_eq!(k2, 43);
252 }
253 
254 #[test]
test_empty_pipeline()255 fn test_empty_pipeline() {
256     let ctx = TestContext::new();
257     let mut con = ctx.connection();
258 
259     let _: () = redis::pipe().cmd("PING").ignore().query(&mut con).unwrap();
260 
261     let _: () = redis::pipe().query(&mut con).unwrap();
262 }
263 
264 #[test]
test_pipeline_transaction()265 fn test_pipeline_transaction() {
266     let ctx = TestContext::new();
267     let mut con = ctx.connection();
268 
269     let ((k1, k2),): ((i32, i32),) = redis::pipe()
270         .atomic()
271         .cmd("SET")
272         .arg("key_1")
273         .arg(42)
274         .ignore()
275         .cmd("SET")
276         .arg("key_2")
277         .arg(43)
278         .ignore()
279         .cmd("MGET")
280         .arg(&["key_1", "key_2"])
281         .query(&mut con)
282         .unwrap();
283 
284     assert_eq!(k1, 42);
285     assert_eq!(k2, 43);
286 }
287 
288 #[test]
test_pipeline_reuse_query()289 fn test_pipeline_reuse_query() {
290     let ctx = TestContext::new();
291     let mut con = ctx.connection();
292 
293     let mut pl = redis::pipe();
294 
295     let ((k1,),): ((i32,),) = pl
296         .cmd("SET")
297         .arg("pkey_1")
298         .arg(42)
299         .ignore()
300         .cmd("MGET")
301         .arg(&["pkey_1"])
302         .query(&mut con)
303         .unwrap();
304 
305     assert_eq!(k1, 42);
306 
307     redis::cmd("DEL").arg("pkey_1").execute(&mut con);
308 
309     // The internal commands vector of the pipeline still contains the previous commands.
310     let ((k1,), (k2, k3)): ((i32,), (i32, i32)) = pl
311         .cmd("SET")
312         .arg("pkey_2")
313         .arg(43)
314         .ignore()
315         .cmd("MGET")
316         .arg(&["pkey_1"])
317         .arg(&["pkey_2"])
318         .query(&mut con)
319         .unwrap();
320 
321     assert_eq!(k1, 42);
322     assert_eq!(k2, 42);
323     assert_eq!(k3, 43);
324 }
325 
326 #[test]
test_pipeline_reuse_query_clear()327 fn test_pipeline_reuse_query_clear() {
328     let ctx = TestContext::new();
329     let mut con = ctx.connection();
330 
331     let mut pl = redis::pipe();
332 
333     let ((k1,),): ((i32,),) = pl
334         .cmd("SET")
335         .arg("pkey_1")
336         .arg(44)
337         .ignore()
338         .cmd("MGET")
339         .arg(&["pkey_1"])
340         .query(&mut con)
341         .unwrap();
342     pl.clear();
343 
344     assert_eq!(k1, 44);
345 
346     redis::cmd("DEL").arg("pkey_1").execute(&mut con);
347 
348     let ((k1, k2),): ((bool, i32),) = pl
349         .cmd("SET")
350         .arg("pkey_2")
351         .arg(45)
352         .ignore()
353         .cmd("MGET")
354         .arg(&["pkey_1"])
355         .arg(&["pkey_2"])
356         .query(&mut con)
357         .unwrap();
358     pl.clear();
359 
360     assert_eq!(k1, false);
361     assert_eq!(k2, 45);
362 }
363 
364 #[test]
test_real_transaction()365 fn test_real_transaction() {
366     let ctx = TestContext::new();
367     let mut con = ctx.connection();
368 
369     let key = "the_key";
370     let _: () = redis::cmd("SET").arg(key).arg(42).query(&mut con).unwrap();
371 
372     loop {
373         let _: () = redis::cmd("WATCH").arg(key).query(&mut con).unwrap();
374         let val: isize = redis::cmd("GET").arg(key).query(&mut con).unwrap();
375         let response: Option<(isize,)> = redis::pipe()
376             .atomic()
377             .cmd("SET")
378             .arg(key)
379             .arg(val + 1)
380             .ignore()
381             .cmd("GET")
382             .arg(key)
383             .query(&mut con)
384             .unwrap();
385 
386         match response {
387             None => {
388                 continue;
389             }
390             Some(response) => {
391                 assert_eq!(response, (43,));
392                 break;
393             }
394         }
395     }
396 }
397 
398 #[test]
test_real_transaction_highlevel()399 fn test_real_transaction_highlevel() {
400     let ctx = TestContext::new();
401     let mut con = ctx.connection();
402 
403     let key = "the_key";
404     let _: () = redis::cmd("SET").arg(key).arg(42).query(&mut con).unwrap();
405 
406     let response: (isize,) = redis::transaction(&mut con, &[key], |con, pipe| {
407         let val: isize = redis::cmd("GET").arg(key).query(con)?;
408         pipe.cmd("SET")
409             .arg(key)
410             .arg(val + 1)
411             .ignore()
412             .cmd("GET")
413             .arg(key)
414             .query(con)
415     })
416     .unwrap();
417 
418     assert_eq!(response, (43,));
419 }
420 
421 #[test]
test_pubsub()422 fn test_pubsub() {
423     use std::sync::{Arc, Barrier};
424     let ctx = TestContext::new();
425     let mut con = ctx.connection();
426 
427     // Connection for subscriber api
428     let mut pubsub_con = ctx.connection();
429 
430     // Barrier is used to make test thread wait to publish
431     // until after the pubsub thread has subscribed.
432     let barrier = Arc::new(Barrier::new(2));
433     let pubsub_barrier = barrier.clone();
434 
435     let thread = spawn(move || {
436         let mut pubsub = pubsub_con.as_pubsub();
437         pubsub.subscribe("foo").unwrap();
438 
439         let _ = pubsub_barrier.wait();
440 
441         let msg = pubsub.get_message().unwrap();
442         assert_eq!(msg.get_channel(), Ok("foo".to_string()));
443         assert_eq!(msg.get_payload(), Ok(42));
444 
445         let msg = pubsub.get_message().unwrap();
446         assert_eq!(msg.get_channel(), Ok("foo".to_string()));
447         assert_eq!(msg.get_payload(), Ok(23));
448     });
449 
450     let _ = barrier.wait();
451     redis::cmd("PUBLISH").arg("foo").arg(42).execute(&mut con);
452     // We can also call the command directly
453     assert_eq!(con.publish("foo", 23), Ok(1));
454 
455     thread.join().expect("Something went wrong");
456 }
457 
458 #[test]
test_pubsub_unsubscribe()459 fn test_pubsub_unsubscribe() {
460     let ctx = TestContext::new();
461     let mut con = ctx.connection();
462 
463     {
464         let mut pubsub = con.as_pubsub();
465         pubsub.subscribe("foo").unwrap();
466         pubsub.subscribe("bar").unwrap();
467         pubsub.subscribe("baz").unwrap();
468         pubsub.psubscribe("foo*").unwrap();
469         pubsub.psubscribe("bar*").unwrap();
470         pubsub.psubscribe("baz*").unwrap();
471     }
472 
473     // Connection should be usable again for non-pubsub commands
474     let _: redis::Value = con.set("foo", "bar").unwrap();
475     let value: String = con.get("foo").unwrap();
476     assert_eq!(&value[..], "bar");
477 }
478 
479 #[test]
test_pubsub_unsubscribe_no_subs()480 fn test_pubsub_unsubscribe_no_subs() {
481     let ctx = TestContext::new();
482     let mut con = ctx.connection();
483 
484     {
485         let _pubsub = con.as_pubsub();
486     }
487 
488     // Connection should be usable again for non-pubsub commands
489     let _: redis::Value = con.set("foo", "bar").unwrap();
490     let value: String = con.get("foo").unwrap();
491     assert_eq!(&value[..], "bar");
492 }
493 
494 #[test]
test_pubsub_unsubscribe_one_sub()495 fn test_pubsub_unsubscribe_one_sub() {
496     let ctx = TestContext::new();
497     let mut con = ctx.connection();
498 
499     {
500         let mut pubsub = con.as_pubsub();
501         pubsub.subscribe("foo").unwrap();
502     }
503 
504     // Connection should be usable again for non-pubsub commands
505     let _: redis::Value = con.set("foo", "bar").unwrap();
506     let value: String = con.get("foo").unwrap();
507     assert_eq!(&value[..], "bar");
508 }
509 
510 #[test]
test_pubsub_unsubscribe_one_sub_one_psub()511 fn test_pubsub_unsubscribe_one_sub_one_psub() {
512     let ctx = TestContext::new();
513     let mut con = ctx.connection();
514 
515     {
516         let mut pubsub = con.as_pubsub();
517         pubsub.subscribe("foo").unwrap();
518         pubsub.psubscribe("foo*").unwrap();
519     }
520 
521     // Connection should be usable again for non-pubsub commands
522     let _: redis::Value = con.set("foo", "bar").unwrap();
523     let value: String = con.get("foo").unwrap();
524     assert_eq!(&value[..], "bar");
525 }
526 
527 #[test]
scoped_pubsub()528 fn scoped_pubsub() {
529     let ctx = TestContext::new();
530     let mut con = ctx.connection();
531 
532     // Connection for subscriber api
533     let mut pubsub_con = ctx.connection();
534 
535     let thread = spawn(move || {
536         let mut count = 0;
537         pubsub_con
538             .subscribe(&["foo", "bar"], |msg| {
539                 count += 1;
540                 match count {
541                     1 => {
542                         assert_eq!(msg.get_channel(), Ok("foo".to_string()));
543                         assert_eq!(msg.get_payload(), Ok(42));
544                         ControlFlow::Continue
545                     }
546                     2 => {
547                         assert_eq!(msg.get_channel(), Ok("bar".to_string()));
548                         assert_eq!(msg.get_payload(), Ok(23));
549                         ControlFlow::Break(())
550                     }
551                     _ => ControlFlow::Break(()),
552                 }
553             })
554             .unwrap();
555 
556         pubsub_con
557     });
558 
559     // Can't use a barrier in this case since there's no opportunity to run code
560     // between channel subscription and blocking for messages.
561     sleep(Duration::from_millis(100));
562 
563     redis::cmd("PUBLISH").arg("foo").arg(42).execute(&mut con);
564     assert_eq!(con.publish("bar", 23), Ok(1));
565 
566     // Wait for thread
567     let mut pubsub_con = thread.join().expect("pubsub thread terminates ok");
568 
569     // Connection should be usable again for non-pubsub commands
570     let _: redis::Value = pubsub_con.set("foo", "bar").unwrap();
571     let value: String = pubsub_con.get("foo").unwrap();
572     assert_eq!(&value[..], "bar");
573 }
574 
575 #[test]
576 #[cfg(feature = "script")]
test_script()577 fn test_script() {
578     let ctx = TestContext::new();
579     let mut con = ctx.connection();
580 
581     let script = redis::Script::new(
582         r"
583        return {redis.call('GET', KEYS[1]), ARGV[1]}
584     ",
585     );
586 
587     let _: () = redis::cmd("SET")
588         .arg("my_key")
589         .arg("foo")
590         .query(&mut con)
591         .unwrap();
592     let response = script.key("my_key").arg(42).invoke(&mut con);
593 
594     assert_eq!(response, Ok(("foo".to_string(), 42)));
595 }
596 
597 #[test]
test_tuple_args()598 fn test_tuple_args() {
599     let ctx = TestContext::new();
600     let mut con = ctx.connection();
601 
602     redis::cmd("HMSET")
603         .arg("my_key")
604         .arg(&[("field_1", 42), ("field_2", 23)])
605         .execute(&mut con);
606 
607     assert_eq!(
608         redis::cmd("HGET")
609             .arg("my_key")
610             .arg("field_1")
611             .query(&mut con),
612         Ok(42)
613     );
614     assert_eq!(
615         redis::cmd("HGET")
616             .arg("my_key")
617             .arg("field_2")
618             .query(&mut con),
619         Ok(23)
620     );
621 }
622 
623 #[test]
test_nice_api()624 fn test_nice_api() {
625     let ctx = TestContext::new();
626     let mut con = ctx.connection();
627 
628     assert_eq!(con.set("my_key", 42), Ok(()));
629     assert_eq!(con.get("my_key"), Ok(42));
630 
631     let (k1, k2): (i32, i32) = redis::pipe()
632         .atomic()
633         .set("key_1", 42)
634         .ignore()
635         .set("key_2", 43)
636         .ignore()
637         .get("key_1")
638         .get("key_2")
639         .query(&mut con)
640         .unwrap();
641 
642     assert_eq!(k1, 42);
643     assert_eq!(k2, 43);
644 }
645 
646 #[test]
test_auto_m_versions()647 fn test_auto_m_versions() {
648     let ctx = TestContext::new();
649     let mut con = ctx.connection();
650 
651     assert_eq!(con.set_multiple(&[("key1", 1), ("key2", 2)]), Ok(()));
652     assert_eq!(con.get(&["key1", "key2"]), Ok((1, 2)));
653 }
654 
655 #[test]
test_nice_hash_api()656 fn test_nice_hash_api() {
657     let ctx = TestContext::new();
658     let mut con = ctx.connection();
659 
660     assert_eq!(
661         con.hset_multiple("my_hash", &[("f1", 1), ("f2", 2), ("f3", 4), ("f4", 8)]),
662         Ok(())
663     );
664 
665     let hm: HashMap<String, isize> = con.hgetall("my_hash").unwrap();
666     assert_eq!(hm.get("f1"), Some(&1));
667     assert_eq!(hm.get("f2"), Some(&2));
668     assert_eq!(hm.get("f3"), Some(&4));
669     assert_eq!(hm.get("f4"), Some(&8));
670     assert_eq!(hm.len(), 4);
671 
672     let hm: BTreeMap<String, isize> = con.hgetall("my_hash").unwrap();
673     assert_eq!(hm.get("f1"), Some(&1));
674     assert_eq!(hm.get("f2"), Some(&2));
675     assert_eq!(hm.get("f3"), Some(&4));
676     assert_eq!(hm.get("f4"), Some(&8));
677     assert_eq!(hm.len(), 4);
678 
679     let v: Vec<(String, isize)> = con.hgetall("my_hash").unwrap();
680     assert_eq!(
681         v,
682         vec![
683             ("f1".to_string(), 1),
684             ("f2".to_string(), 2),
685             ("f3".to_string(), 4),
686             ("f4".to_string(), 8),
687         ]
688     );
689 
690     assert_eq!(con.hget("my_hash", &["f2", "f4"]), Ok((2, 8)));
691     assert_eq!(con.hincr("my_hash", "f1", 1), Ok(2));
692     assert_eq!(con.hincr("my_hash", "f2", 1.5f32), Ok(3.5f32));
693     assert_eq!(con.hexists("my_hash", "f2"), Ok(true));
694     assert_eq!(con.hdel("my_hash", &["f1", "f2"]), Ok(()));
695     assert_eq!(con.hexists("my_hash", "f2"), Ok(false));
696 
697     let iter: redis::Iter<'_, (String, isize)> = con.hscan("my_hash").unwrap();
698     let mut found = HashSet::new();
699     for item in iter {
700         found.insert(item);
701     }
702 
703     assert_eq!(found.len(), 2);
704     assert_eq!(found.contains(&("f3".to_string(), 4)), true);
705     assert_eq!(found.contains(&("f4".to_string(), 8)), true);
706 }
707 
708 #[test]
test_nice_list_api()709 fn test_nice_list_api() {
710     let ctx = TestContext::new();
711     let mut con = ctx.connection();
712 
713     assert_eq!(con.rpush("my_list", &[1, 2, 3, 4]), Ok(4));
714     assert_eq!(con.rpush("my_list", &[5, 6, 7, 8]), Ok(8));
715     assert_eq!(con.llen("my_list"), Ok(8));
716 
717     assert_eq!(con.lpop("my_list"), Ok(1));
718     assert_eq!(con.llen("my_list"), Ok(7));
719 
720     assert_eq!(con.lrange("my_list", 0, 2), Ok((2, 3, 4)));
721 
722     assert_eq!(con.lset("my_list", 0, 4), Ok(true));
723     assert_eq!(con.lrange("my_list", 0, 2), Ok((4, 3, 4)));
724 }
725 
726 #[test]
test_tuple_decoding_regression()727 fn test_tuple_decoding_regression() {
728     let ctx = TestContext::new();
729     let mut con = ctx.connection();
730 
731     assert_eq!(con.del("my_zset"), Ok(()));
732     assert_eq!(con.zadd("my_zset", "one", 1), Ok(1));
733     assert_eq!(con.zadd("my_zset", "two", 2), Ok(1));
734 
735     let vec: Vec<(String, u32)> = con.zrangebyscore_withscores("my_zset", 0, 10).unwrap();
736     assert_eq!(vec.len(), 2);
737 
738     assert_eq!(con.del("my_zset"), Ok(1));
739 
740     let vec: Vec<(String, u32)> = con.zrangebyscore_withscores("my_zset", 0, 10).unwrap();
741     assert_eq!(vec.len(), 0);
742 }
743 
744 #[test]
test_bit_operations()745 fn test_bit_operations() {
746     let ctx = TestContext::new();
747     let mut con = ctx.connection();
748 
749     assert_eq!(con.setbit("bitvec", 10, true), Ok(false));
750     assert_eq!(con.getbit("bitvec", 10), Ok(true));
751 }
752 
753 #[test]
test_invalid_protocol()754 fn test_invalid_protocol() {
755     use redis::{Parser, RedisResult};
756     use std::error::Error;
757     use std::io::Write;
758     use std::net::TcpListener;
759     use std::thread;
760 
761     let listener = TcpListener::bind("127.0.0.1:0").unwrap();
762     let port = listener.local_addr().unwrap().port();
763 
764     let child = thread::spawn(move || -> Result<(), Box<dyn Error + Send + Sync>> {
765         let mut stream = BufReader::new(listener.incoming().next().unwrap()?);
766         // read the request and respond with garbage
767         let _: redis::Value = Parser::new().parse_value(&mut stream)?;
768         stream.get_mut().write_all(b"garbage ---!#!#\r\n\r\n\n\r")?;
769         // block until the stream is shutdown by the client
770         let _: RedisResult<redis::Value> = Parser::new().parse_value(&mut stream);
771         Ok(())
772     });
773     sleep(Duration::from_millis(100));
774     // some work here
775     let cli = redis::Client::open(&format!("redis://127.0.0.1:{}", port)[..]).unwrap();
776     let mut con = cli.get_connection().unwrap();
777 
778     let mut result: redis::RedisResult<u8>;
779     // first requests returns ResponseError
780     result = con.del("my_zset");
781     assert_eq!(result.unwrap_err().kind(), redis::ErrorKind::ResponseError);
782     // from now on it's IoError due to the closed connection
783     result = con.del("my_zset");
784     assert_eq!(result.unwrap_err().kind(), redis::ErrorKind::IoError);
785 
786     child.join().unwrap().unwrap();
787 }
788 
789 #[test]
test_redis_server_down()790 fn test_redis_server_down() {
791     let mut ctx = TestContext::new();
792     let mut con = ctx.connection();
793 
794     let ping = redis::cmd("PING").query::<String>(&mut con);
795     assert_eq!(ping, Ok("PONG".into()));
796 
797     ctx.stop_server();
798 
799     let ping = redis::cmd("PING").query::<String>(&mut con);
800 
801     assert_eq!(ping.is_err(), true);
802     eprintln!("{}", ping.unwrap_err());
803     assert_eq!(con.is_open(), false);
804 }
805