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