1use std::sync::Arc;
75
76use yo_reactor::{BATCH_MAX, Engine, Reactor};
77
78use crate::dispatch::table;
79use crate::dispatch::{self, Flow, Parked, Server};
80use crate::front::{Front, Wrote};
81use crate::proto::Limits;
82use yo_kv::Keyspace;
83
84pub use crate::front::Cmd;
85
86pub type ConnId = u32;
88
89const SWEEP_LOOKS: usize = yo_reactor::MAINTENANCE_UNITS as usize;
96
97pub trait Sink {
103 fn write(&mut self, conn: ConnId, bytes: &[u8]) -> usize;
108
109 fn closed(&mut self, conn: ConnId) {
111 let _ = conn;
112 }
113}
114
115#[derive(Debug, Default)]
117pub struct Recorder {
118 sent: Vec<Vec<u8>>,
119 closed: Vec<ConnId>,
120}
121
122impl Recorder {
123 #[must_use]
125 pub fn new() -> Recorder {
126 Recorder::default()
127 }
128
129 #[must_use]
131 pub fn sent(&self, conn: ConnId) -> &[u8] {
132 self.sent.get(conn as usize).map_or(&[], Vec::as_slice)
133 }
134
135 #[must_use]
137 pub fn was_closed(&self, conn: ConnId) -> bool {
138 self.closed.contains(&conn)
139 }
140
141 pub fn clear(&mut self) {
143 for c in &mut self.sent {
144 c.clear();
145 }
146 self.closed.clear();
147 }
148}
149
150impl Sink for Recorder {
151 fn write(&mut self, conn: ConnId, bytes: &[u8]) -> usize {
152 yo_alloc::allow(|| {
154 if self.sent.len() <= conn as usize {
155 self.sent.resize_with(conn as usize + 1, Vec::new);
156 }
157 self.sent[conn as usize].extend_from_slice(bytes);
158 });
159 bytes.len()
160 }
161
162 fn closed(&mut self, conn: ConnId) {
163 yo_alloc::allow(|| self.closed.push(conn));
164 }
165}
166
167pub struct Wire<S> {
177 front: Front<S>,
178 server: Arc<Server>,
179 parked: Vec<Parked>,
186 post: Vec<dispatch::Envelope>,
193}
194
195impl<S: Sink> Wire<S> {
196 #[must_use]
198 pub fn new(sink: S) -> Wire<S> {
199 Wire::with_server(Server::new(), sink)
200 }
201
202 #[must_use]
205 pub fn with_server(server: Server, sink: S) -> Wire<S> {
206 Wire::over(Arc::new(server), sink)
207 }
208
209 #[must_use]
218 pub fn over(server: Arc<Server>, sink: S) -> Wire<S> {
219 Wire {
220 front: Front::new(sink),
221 parked: Vec::new(),
222 post: Vec::new(),
223 server,
224 }
225 }
226
227 #[must_use]
229 pub fn server(&self) -> &Server {
230 &self.server
231 }
232
233 #[must_use]
236 pub fn shared(&self) -> Arc<Server> {
237 Arc::clone(&self.server)
238 }
239
240 pub fn server_mut(&mut self) -> &mut Server {
255 Arc::get_mut(&mut self.server)
256 .expect("the server is set up before the threads that share it are started")
257 }
258
259 #[must_use]
261 pub const fn sink(&self) -> &S {
262 self.front.sink()
263 }
264
265 pub const fn sink_mut(&mut self) -> &mut S {
267 self.front.sink_mut()
268 }
269
270 pub fn set_limits(&mut self, limits: Limits) {
272 self.front.set_limits(limits);
273 }
274
275 pub fn accept(&mut self) -> ConnId {
277 self.server.counted().opened();
278 let at = self.front.open(self.server.next_client());
279 self.note_buffers();
280 at
281 }
282
283 fn note_buffers(&mut self) {
288 let delta = self.front.buffer_delta();
289 if delta != 0 {
290 self.server.note_conn_bytes(delta);
291 }
292 }
293
294 pub fn hangup(&mut self, conn: ConnId) {
300 if !self.front.live(conn) {
301 return;
302 }
303 self.front.mark_gone(conn);
304 if self.front.blocked(conn) {
309 self.front.unpark(conn);
310 }
311 if self.front.pending(conn) == 0 {
312 self.release(conn);
313 }
314 self.note_buffers();
315 }
316
317 fn serve_waiters(&mut self) {
330 let now = self.server.now_ms();
331 let mine = self.server.my_slot();
332 self.server.waiters().mine(mine, &mut self.parked);
333 for at in 0..self.parked.len() {
334 let p = self.parked[at];
335 if !self.front.answers(p.conn, p.client) {
340 self.server.forget_waiters(p.client);
341 continue;
342 }
343 let served = {
347 let Wire { server, front, .. } = self;
348 server.serve_waiter(p.client, now, front.out(p.conn))
349 };
350 if served {
351 self.server.forget_waiters(p.client);
352 self.front.unpark(p.conn);
353 self.front.soil(p.conn);
354 }
355 }
356 self.parked.clear();
357 }
358
359 fn deliver(&mut self) {
368 let mut post = core::mem::take(&mut self.post);
371 self.server.take_mail(&mut post);
372 for env in post.drain(..) {
373 let conn = env.conn();
374 if !self.front.answers(conn, env.client()) {
375 continue;
376 }
377 env.write(self.front.out(conn));
378 self.front.soil(conn);
379 }
380 self.post = post;
381 }
382
383 #[must_use]
385 pub fn clients(&self) -> usize {
386 self.front.clients()
387 }
388
389 #[must_use]
391 pub fn ready(&self) -> usize {
392 self.front.ready()
393 }
394
395 #[must_use]
401 pub fn owed(&self) -> usize {
402 self.front.owed()
403 }
404
405 #[must_use]
414 pub fn waiting(&self) -> usize {
415 self.server.parked_here()
416 }
417
418 #[must_use]
427 pub fn posted(&self) -> usize {
428 self.server.posted()
429 }
430
431 #[must_use]
438 pub fn stopping(&self) -> bool {
439 self.server.stopping()
440 }
441
442 #[must_use]
444 pub fn decoders(&self) -> usize {
445 self.front.decoders()
446 }
447
448 #[must_use]
450 pub fn buffer_bytes(&self) -> usize {
451 self.front.buffer_bytes()
452 }
453
454 pub fn feed(&mut self, conn: ConnId, bytes: &[u8]) {
460 self.front.feed(conn, bytes);
461 self.note_buffers();
462 }
463
464 fn release(&mut self, conn: ConnId) {
466 if let Some(session) = self.front.session_mut(conn) {
470 dispatch::forget_session(&self.server, session);
471 }
472 let Some(client) = self.front.close(conn) else {
473 return;
474 };
475 self.forget(client);
476 }
477
478 fn forget(&mut self, client: u64) {
485 self.server.forget_waiters(client);
486 self.server.counted().closed();
487 }
488
489 pub fn take_ready(&mut self, into: &mut Vec<Cmd>, max: usize) -> usize {
494 self.front.take_ready(into, max)
495 }
496
497 pub fn tick(&mut self) {
503 self.server.refresh_clock();
504 }
505
506 pub fn maintain(&mut self) -> Option<usize> {
524 self.server.refresh_memory();
530 self.server.backup_expire();
534 self.server.expire_slice(SWEEP_LOOKS);
539 self.server.compact_step()
540 }
541}
542
543impl<S: Sink> Engine for Wire<S> {
544 type Work = Cmd;
545
546 fn key_hash(&self, cmd: &Cmd) -> Option<u64> {
547 let spec = table::at(cmd.spec)?;
552 if spec.first_key <= 0 {
553 return None;
554 }
555 let args = self.front.args(cmd);
556 let key = args.opt(spec.first_key as usize)?;
561 Some(Keyspace::hash_of(key))
562 }
563
564 fn prefetch(&self, cmd: &Cmd, hash: u64) {
565 let db = self.front.db(cmd.conn());
566 self.server.striped_ref(db).prefetch_hashed(hash);
571 }
572
573 fn run(&mut self, cmd: Cmd, _hash: Option<u64>) -> yo_reactor::Flow {
574 let conn = cmd.conn();
575 if self.front.blocked(conn) {
580 self.front.park(conn, cmd);
581 return yo_reactor::Flow::Next;
582 }
583
584 let flow = if self.front.start(&cmd) {
588 let Wire { front, server, .. } = self;
589 let (args, session, out) = front.parts(&cmd);
590 let spec = table::at(cmd.spec);
591 dispatch::resolved(server, session, spec, args, out)
592 } else {
593 Flow::Continue
597 };
598
599 self.front.done(&cmd);
600 if self.front.gone(conn) {
601 if self.front.pending(conn) == 0 {
602 self.release(conn);
603 }
604 } else {
605 match flow {
606 Flow::Close => {
607 self.front.quit(conn);
608 self.front.soil(conn);
609 }
610 Flow::Block => {
615 self.front.block(conn);
616 let client = self.front.client(conn);
617 self.server.bind_waiter(client, conn);
618 }
619 Flow::Continue => self.front.soil(conn),
620 }
621 }
622
623 if self.server.parked_here() != 0 {
628 self.serve_waiters();
629 }
630 yo_reactor::Flow::Next
631 }
632
633 fn flush(&mut self) {
634 if self.server.parked_here() != 0 {
645 self.server.refresh_clock();
646 self.serve_waiters();
647 }
648
649 if self.server.mail_here() != 0 {
654 self.deliver();
655 }
656
657 let mut dirty = self.front.take_dirty();
661 let mut at = 0;
662 while at < dirty.len() {
663 let conn = dirty[at];
664 match self.front.write_out(conn) {
665 Wrote::Owed => at += 1,
669 Wrote::Done => {
670 dirty.swap_remove(at);
671 }
672 Wrote::Ended(client) => {
673 self.forget(client);
674 dirty.swap_remove(at);
675 }
676 }
677 }
678 self.front.give_dirty(dirty);
679 self.note_buffers();
680 }
681
682 fn maintain(&mut self, budget: &mut yo_reactor::Budget) {
683 if !budget.spend(1) {
686 return;
687 }
688 self.tick();
689 let looks = budget.left() as usize;
695 let spent = self.server.expire_slice(looks);
696 budget.spend(u32::try_from(spent).unwrap_or(u32::MAX));
697 }
698}
699
700pub fn pump<S: Sink>(reactor: &mut Reactor<Wire<S>>, batch: &mut Vec<Cmd>) -> usize {
707 let mut ran = 0;
708 reactor.engine_mut().tick();
709 loop {
710 batch.clear();
711 if reactor.engine_mut().take_ready(batch, BATCH_MAX) == 0 {
712 break;
713 }
714 let armed = yo_alloc::guard();
724 ran += reactor.execute_all(batch.drain(..));
725 drop(armed);
726 reactor.engine_mut().flush();
727 reactor.engine_mut().maintain();
730 }
731 reactor.engine_mut().maintain();
734 reactor.engine_mut().flush();
742 ran
743}
744
745#[cfg(test)]
746mod tests {
747 use super::*;
748
749 fn wire(args: &[&[u8]]) -> Vec<u8> {
751 let mut b = format!("*{}\r\n", args.len()).into_bytes();
752 for a in args {
753 b.extend_from_slice(format!("${}\r\n", a.len()).as_bytes());
754 b.extend_from_slice(a);
755 b.extend_from_slice(b"\r\n");
756 }
757 b
758 }
759
760 fn engine() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
761 let mut r = Reactor::inline(Wire::new(Recorder::new()));
762 let conn = r.engine_mut().accept();
763 (r, conn, Vec::new())
764 }
765
766 const START_MS: u64 = 1_000_000;
768
769 fn timed() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
775 let server = crate::dispatch::Server::with_clock(yo_kv::Clock::fixed(START_MS));
776 let mut r = Reactor::inline(Wire::with_server(server, Recorder::new()));
777 let conn = r.engine_mut().accept();
778 (r, conn, Vec::new())
779 }
780
781 #[test]
782 fn a_pipelined_batch_comes_back_in_order_and_in_one_write() {
783 let (mut r, conn, mut batch) = engine();
784 let mut stream = wire(&[b"SET", b"k", b"v"]);
785 stream.extend(wire(&[b"GET", b"k"]));
786 stream.extend(wire(&[b"INCR", b"n"]));
787
788 r.engine_mut().feed(conn, &stream);
789 assert_eq!(r.engine().ready(), 3);
790 assert_eq!(pump(&mut r, &mut batch), 3);
791
792 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$1\r\nv\r\n:1\r\n");
793 assert_eq!(r.engine().ready(), 0);
794 }
795
796 #[test]
799 fn a_command_split_across_reads_resumes_rather_than_restarts() {
800 let (mut r, conn, mut batch) = engine();
801 let bytes = wire(&[b"SET", b"key", b"value"]);
802
803 for at in 1..bytes.len() {
804 r.engine_mut().feed(conn, &bytes[at - 1..at]);
805 assert_eq!(r.engine().ready(), 0, "not a command yet at {at}");
806 }
807 r.engine_mut().feed(conn, &bytes[bytes.len() - 1..]);
808 assert_eq!(r.engine().ready(), 1);
809 assert_eq!(pump(&mut r, &mut batch), 1);
810 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
811
812 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
815 pump(&mut r, &mut batch);
816 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$5\r\nvalue\r\n");
817 }
818
819 #[test]
820 fn two_connections_are_two_sessions_over_one_server() {
821 let (mut r, a, mut batch) = engine();
822 let b = r.engine_mut().accept();
823
824 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
825 r.engine_mut().feed(a, &wire(&[b"SET", b"k", b"a"]));
826 r.engine_mut().feed(b, &wire(&[b"SET", b"k", b"b"]));
827 r.engine_mut().feed(a, &wire(&[b"GET", b"k"]));
828 r.engine_mut().feed(b, &wire(&[b"GET", b"k"]));
829 pump(&mut r, &mut batch);
830
831 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n+OK\r\n$1\r\na\r\n");
832 assert_eq!(r.engine().sink().sent(b), b"+OK\r\n$1\r\nb\r\n");
833 assert_eq!(r.engine().clients(), 2);
834 }
835
836 #[test]
848 fn two_threads_write_into_one_server() {
849 const EACH: usize = 200;
850
851 let mut server = Server::new();
852 server.set_threads(2);
853 let first = Wire::with_server(server, Recorder::new());
854 let second = Wire::over(first.shared(), Recorder::new());
855 let server = first.shared();
856
857 std::thread::scope(|s| {
858 for (at, engine) in [first, second].into_iter().enumerate() {
859 s.spawn(move || {
860 let mut r = Reactor::inline(engine);
861 let mut batch = Vec::new();
862 let conn = r.engine_mut().accept();
863 for i in 0..EACH {
864 let key = format!("t{at}:{i}");
865 r.engine_mut()
866 .feed(conn, &wire(&[b"SET", key.as_bytes(), b"v"]));
867 pump(&mut r, &mut batch);
868 }
869 });
870 }
871 });
872
873 assert_eq!(server.striped_ref(0).len(), 2 * EACH);
876 assert_eq!(server.totals().connections, 2);
879 }
880
881 #[test]
884 fn a_waiter_belongs_to_the_thread_that_parked_it() {
885 let mut server = Server::new();
886 server.set_threads(2);
887 let first = Wire::with_server(server, Recorder::new());
888 let second = Wire::over(first.shared(), Recorder::new());
889 let server = first.shared();
890
891 let parked = std::sync::Barrier::new(2);
892 let swept = std::sync::Barrier::new(2);
893
894 std::thread::scope(|s| {
895 let (parked, swept) = (&parked, &swept);
896 s.spawn(move || {
897 let mut r = Reactor::inline(first);
898 let mut batch = Vec::new();
899 let conn = r.engine_mut().accept();
900 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
901 pump(&mut r, &mut batch);
902 parked.wait();
903
904 for _ in 0..50 {
907 pump(&mut r, &mut batch);
908 }
909 swept.wait();
910 assert!(r.engine().sink().sent(conn).is_empty(), "nothing to say");
911 });
912 s.spawn(move || {
913 let mut r = Reactor::inline(second);
914 let mut batch = Vec::new();
915 let conn = r.engine_mut().accept();
916 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"b", b"0"]));
917 pump(&mut r, &mut batch);
918 parked.wait();
919 swept.wait();
920
921 let pusher = r.engine_mut().accept();
924 r.engine_mut().feed(pusher, &wire(&[b"RPUSH", b"b", b"v"]));
925 pump(&mut r, &mut batch);
926 assert_eq!(
927 r.engine().sink().sent(conn),
928 b"*2\r\n$1\r\nb\r\n$1\r\nv\r\n",
929 "served by the thread that parked it"
930 );
931 });
932 });
933
934 assert_eq!(server.parked(), 1, "and the other one is still waiting");
935 }
936
937 #[test]
943 fn a_thread_counts_the_clients_it_blocked_and_nobody_else_s() {
944 let mut server = Server::new();
945 server.set_threads(2);
946 let first = Wire::with_server(server, Recorder::new());
947 let second = Wire::over(first.shared(), Recorder::new());
948 let server = first.shared();
949
950 let parked = std::sync::Barrier::new(2);
951 let looked = std::sync::Barrier::new(2);
952
953 std::thread::scope(|s| {
954 let (parked, looked) = (&parked, &looked);
955 s.spawn(move || {
956 let mut r = Reactor::inline(first);
957 let mut batch = Vec::new();
958 let conn = r.engine_mut().accept();
959 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
960 pump(&mut r, &mut batch);
961 assert_eq!(r.engine().waiting(), 1, "the one this thread blocked");
962 parked.wait();
963 looked.wait();
964
965 let other = r.engine_mut().accept();
969 r.engine_mut().feed(other, &wire(&[b"PING"]));
970 pump(&mut r, &mut batch);
971 r.engine_mut().hangup(other);
972 pump(&mut r, &mut batch);
973 assert_eq!(r.engine().waiting(), 1, "still just the blocked one");
974 });
975 s.spawn(move || {
976 let mut r = Reactor::inline(second);
977 let mut batch = Vec::new();
978 parked.wait();
979
980 pump(&mut r, &mut batch);
983 assert_eq!(r.engine().waiting(), 0, "none of them are this one's");
984 assert_eq!(r.engine().server().parked(), 1, "one on the server");
985 looked.wait();
986 });
987 });
988
989 assert_eq!(server.parked(), 1);
990 }
991
992 #[test]
995 fn client_ids_are_the_server_s_to_hand_out() {
996 let first = Wire::new(Recorder::new());
997 let second = Wire::over(first.shared(), Recorder::new());
998 let mut a = Reactor::inline(first);
999 let mut b = Reactor::inline(second);
1000
1001 let (one, two) = (a.engine_mut().accept(), b.engine_mut().accept());
1002 assert_eq!(one, two, "the same slot on each front");
1003
1004 let mut batch = Vec::new();
1009 a.engine_mut().feed(one, &wire(&[b"HELLO", b"3"]));
1010 b.engine_mut().feed(two, &wire(&[b"HELLO", b"3"]));
1011 pump(&mut a, &mut batch);
1012 pump(&mut b, &mut batch);
1013
1014 let first = String::from_utf8_lossy(a.engine().sink().sent(one)).into_owned();
1015 let second = String::from_utf8_lossy(b.engine().sink().sent(two)).into_owned();
1016 assert!(first.contains(":1\r\n"), "{first}");
1017 assert!(second.contains(":2\r\n"), "{second}");
1018 }
1019
1020 #[test]
1021 fn quit_is_answered_and_then_the_connection_goes() {
1022 let (mut r, conn, mut batch) = engine();
1023 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1024 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1025 pump(&mut r, &mut batch);
1026
1027 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1028 assert!(r.engine().sink().was_closed(conn));
1029 assert_eq!(r.engine().clients(), 0);
1030
1031 let again = r.engine_mut().accept();
1033 assert_eq!(again, conn);
1034 assert_eq!(r.engine().clients(), 1);
1035 }
1036
1037 #[test]
1040 fn what_a_client_pipelined_behind_quit_is_never_run() {
1041 let (mut r, conn, mut batch) = engine();
1042 let mut stream = wire(&[b"QUIT"]);
1043 stream.extend(wire(&[b"SET", b"foo", b"bar"]));
1044 r.engine_mut().feed(conn, &stream);
1045 assert_eq!(r.engine().ready(), 2);
1047 pump(&mut r, &mut batch);
1048
1049 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
1051 assert!(r.engine().sink().was_closed(conn));
1052
1053 r.engine_mut().sink_mut().clear();
1058 let next = r.engine_mut().accept();
1059 r.engine_mut().feed(next, &wire(&[b"GET", b"foo"]));
1060 pump(&mut r, &mut batch);
1061 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1062 }
1063
1064 #[test]
1074 fn a_slot_that_last_spoke_resp3_answers_the_next_client_in_resp2() {
1075 let (mut r, conn, mut batch) = engine();
1076 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1077 r.engine_mut().feed(conn, &wire(&[b"GET", b"nothing"]));
1078 pump(&mut r, &mut batch);
1079 assert!(r.engine().sink().sent(conn).ends_with(b"_\r\n"));
1080 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1081 pump(&mut r, &mut batch);
1082
1083 r.engine_mut().sink_mut().clear();
1084 let next = r.engine_mut().accept();
1085 assert_eq!(next, conn, "the same slot, which is what this is about");
1086 r.engine_mut().feed(next, &wire(&[b"GET", b"nothing"]));
1087 pump(&mut r, &mut batch);
1088 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1089 }
1090
1091 #[test]
1093 fn commands_that_arrived_before_a_protocol_error_are_still_answered() {
1094 let (mut r, conn, mut batch) = engine();
1095 let mut stream = wire(&[b"SET", b"k", b"v"]);
1096 stream.extend(wire(&[b"GET", b"k"]));
1097 stream.extend_from_slice(b"*1\r\n+notabulk\r\n");
1098 r.engine_mut().feed(conn, &stream);
1099 pump(&mut r, &mut batch);
1100
1101 let sent = r.engine().sink().sent(conn);
1104 assert!(
1105 sent.starts_with(b"+OK\r\n$1\r\nv\r\n-ERR Protocol error: "),
1106 "{sent:?}"
1107 );
1108 assert!(r.engine().sink().was_closed(conn));
1109 }
1110
1111 #[test]
1112 fn a_protocol_error_is_written_and_closes_the_connection() {
1113 let (mut r, conn, mut batch) = engine();
1114 r.engine_mut().feed(conn, b"*1\r\n+notabulk\r\n");
1116 pump(&mut r, &mut batch);
1117
1118 let sent = r.engine().sink().sent(conn);
1119 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1120 assert!(r.engine().sink().was_closed(conn));
1121 assert_eq!(r.engine().clients(), 0);
1122 }
1123
1124 #[test]
1128 fn a_decoder_that_came_back_mid_command_starts_the_next_one_clean() {
1129 let (mut r, conn, mut batch) = engine();
1130 r.engine_mut()
1132 .feed(conn, b"*3\r\n$3\r\nSET\r\n$1\r\nx\r\n$blabla\r\n");
1133 pump(&mut r, &mut batch);
1134 let sent = r.engine().sink().sent(conn);
1135 assert!(
1136 sent.starts_with(b"-ERR Protocol error: invalid bulk length"),
1137 "{sent:?}"
1138 );
1139
1140 r.engine_mut().sink_mut().clear();
1144 let next = r.engine_mut().accept();
1145 r.engine_mut().feed(next, &wire(&[b"GET", b"k"]));
1146 pump(&mut r, &mut batch);
1147 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1148
1149 r.engine_mut().sink_mut().clear();
1150 let third = r.engine_mut().accept();
1151 r.engine_mut().feed(third, b"*1\r\n+notabulk\r\n");
1152 pump(&mut r, &mut batch);
1153 let sent = r.engine().sink().sent(third);
1154 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1155 }
1156
1157 #[test]
1160 fn a_hangup_with_commands_in_flight_waits_for_them() {
1161 let (mut r, conn, mut batch) = engine();
1162 r.engine_mut().feed(conn, &wire(&[b"SET", b"k", b"v"]));
1163 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1164
1165 batch.clear();
1166 r.engine_mut().take_ready(&mut batch, BATCH_MAX);
1167 r.engine_mut().hangup(conn);
1168 assert_eq!(r.engine().clients(), 1, "still holding the buffer");
1169
1170 r.execute_all(batch.drain(..));
1171 r.engine_mut().flush();
1172 assert_eq!(r.engine().clients(), 0);
1173 assert!(r.engine().sink().sent(conn).is_empty(), "nobody to answer");
1174
1175 let decoders = r.engine().decoders();
1178 let again = r.engine_mut().accept();
1179 assert_eq!(again, conn);
1180 r.engine_mut().feed(again, &wire(&[b"PING"]));
1181 pump(&mut r, &mut batch);
1182 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1183 assert_eq!(r.engine().decoders(), decoders);
1184 }
1185
1186 #[test]
1189 fn the_buffers_and_the_decoder_pool_stop_growing() {
1190 let (mut r, conn, mut batch) = engine();
1191 let mut stream = Vec::new();
1192 for i in 0..32 {
1193 stream.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1194 }
1195
1196 r.engine_mut().feed(conn, &stream);
1197 pump(&mut r, &mut batch);
1198 let decoders = r.engine().decoders();
1199 let batch_cap = batch.capacity();
1200
1201 for _ in 0..10 {
1202 r.engine_mut().feed(conn, &stream);
1203 pump(&mut r, &mut batch);
1204 }
1205 assert_eq!(r.engine().decoders(), decoders, "the pool is reused");
1206 assert_eq!(batch.capacity(), batch_cap, "the batch buffer is reused");
1207 assert!(
1208 decoders <= BATCH_MAX + 1,
1209 "{decoders} decoders for 32 commands"
1210 );
1211 }
1212
1213 #[test]
1222 fn a_pipelining_client_does_not_grow_the_read_buffer() {
1223 let (mut r, conn, mut batch) = engine();
1224 let mut round = Vec::new();
1225 for i in 0..16 {
1226 round.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1227 }
1228
1229 r.engine_mut().feed(conn, &round);
1230 pump(&mut r, &mut batch);
1231 r.engine_mut().sink_mut().clear();
1232 let after_one = r.engine().buffer_bytes();
1233
1234 let rounds = if cfg!(miri) { 50 } else { 1000 };
1243 for _ in 0..rounds {
1244 r.engine_mut().feed(conn, &round);
1245 pump(&mut r, &mut batch);
1246 r.engine_mut().sink_mut().clear();
1247 }
1248
1249 assert_eq!(
1250 r.engine().buffer_bytes(),
1251 after_one,
1252 "the buffers grew over {rounds} rounds of the same sixteen commands"
1253 );
1254 assert!(
1255 r.engine().server().memory_bytes() >= after_one,
1256 "the buffers are counted in what the server reports"
1257 );
1258 }
1259
1260 #[test]
1263 fn a_command_split_across_reads_survives_compaction() {
1264 let (mut r, conn, mut batch) = engine();
1265 let cmd = wire(&[b"SET", b"key", b"value"]);
1266 let (head, tail) = cmd.split_at(cmd.len() - 4);
1267
1268 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1271 r.engine_mut().feed(conn, head);
1272 pump(&mut r, &mut batch);
1273 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n");
1274
1275 r.engine_mut().feed(conn, tail);
1277 pump(&mut r, &mut batch);
1278 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1279
1280 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
1281 pump(&mut r, &mut batch);
1282 assert!(r.engine().sink().sent(conn).ends_with(b"$5\r\nvalue\r\n"));
1283 }
1284
1285 #[test]
1288 fn the_batch_goes_through_the_reactors_two_walks() {
1289 let (mut r, conn, mut batch) = engine();
1290 for i in 0..100 {
1291 r.engine_mut()
1292 .feed(conn, &wire(&[b"INCR", format!("k{}", i % 7).as_bytes()]));
1293 }
1294 let ran = pump(&mut r, &mut batch);
1295
1296 assert_eq!(ran, 100);
1297 assert_eq!(r.commands(), 100);
1298 assert_eq!(r.turns(), 2);
1300 assert!(r.engine().sink().sent(conn).ends_with(b":15\r\n"));
1302 }
1303
1304 #[derive(Default)]
1307 struct Trickle {
1308 sent: Vec<u8>,
1309 writes: usize,
1310 }
1311
1312 impl Sink for Trickle {
1313 fn write(&mut self, _conn: ConnId, bytes: &[u8]) -> usize {
1314 self.writes += 1;
1315 let n = bytes.len().min(4);
1316 self.sent.extend_from_slice(&bytes[..n]);
1317 n
1318 }
1319 }
1320
1321 #[test]
1324 fn a_blpop_on_a_list_with_something_in_it_never_waits() {
1325 let (mut r, conn, mut batch) = engine();
1326 r.engine_mut().feed(conn, &wire(&[b"RPUSH", b"q", b"a"]));
1327 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"0"]));
1328 pump(&mut r, &mut batch);
1329
1330 assert_eq!(
1331 r.engine().sink().sent(conn),
1332 b":1\r\n*2\r\n$1\r\nq\r\n$1\r\na\r\n"
1333 );
1334 assert_eq!(r.engine().server().parked(), 0);
1335 }
1336
1337 #[test]
1340 fn a_parked_client_is_answered_by_another_connections_push() {
1341 let (mut r, a, mut batch) = engine();
1342 let b = r.engine_mut().accept();
1343
1344 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1345 pump(&mut r, &mut batch);
1346 assert!(r.engine().sink().sent(a).is_empty(), "nothing to say yet");
1347 assert_eq!(r.engine().server().parked(), 1);
1348
1349 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"one"]));
1350 pump(&mut r, &mut batch);
1351
1352 assert_eq!(r.engine().sink().sent(a), b"*2\r\n$1\r\nq\r\n$3\r\none\r\n");
1353 assert_eq!(r.engine().sink().sent(b), b":1\r\n");
1356 assert_eq!(r.engine().server().parked(), 0);
1357 }
1358
1359 #[test]
1362 fn only_a_list_arriving_under_a_named_key_wakes_a_waiter() {
1363 let (mut r, a, mut batch) = engine();
1364 let b = r.engine_mut().accept();
1365 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1366 pump(&mut r, &mut batch);
1367
1368 r.engine_mut()
1369 .feed(b, &wire(&[b"RPUSH", b"elsewhere", b"x"]));
1370 r.engine_mut().feed(b, &wire(&[b"SADD", b"q", b"x"]));
1371 pump(&mut r, &mut batch);
1372
1373 assert!(r.engine().sink().sent(a).is_empty());
1374 assert_eq!(r.engine().server().parked(), 1, "still waiting");
1375 assert_eq!(r.engine().sink().sent(b), b":1\r\n:1\r\n");
1378 }
1379
1380 #[test]
1383 fn two_parked_clients_are_served_in_the_order_they_arrived() {
1384 let (mut r, a, mut batch) = engine();
1385 let b = r.engine_mut().accept();
1386 let c = r.engine_mut().accept();
1387
1388 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1389 pump(&mut r, &mut batch);
1390 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"q", b"0"]));
1391 pump(&mut r, &mut batch);
1392 assert_eq!(r.engine().server().parked(), 2);
1393
1394 r.engine_mut()
1395 .feed(c, &wire(&[b"RPUSH", b"q", b"first", b"second"]));
1396 pump(&mut r, &mut batch);
1397
1398 assert_eq!(
1399 r.engine().sink().sent(a),
1400 b"*2\r\n$1\r\nq\r\n$5\r\nfirst\r\n"
1401 );
1402 assert_eq!(
1403 r.engine().sink().sent(b),
1404 b"*2\r\n$1\r\nq\r\n$6\r\nsecond\r\n"
1405 );
1406 assert_eq!(r.engine().server().parked(), 0);
1407 }
1408
1409 #[test]
1412 fn what_a_client_pipelined_behind_a_block_waits_for_the_block() {
1413 let (mut r, a, mut batch) = engine();
1414 let b = r.engine_mut().accept();
1415
1416 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1419 stream.extend(wire(&[b"PING"]));
1420 r.engine_mut().feed(a, &stream);
1421 pump(&mut r, &mut batch);
1422 assert!(
1423 r.engine().sink().sent(a).is_empty(),
1424 "the PING went out in front of the answer it was sent behind"
1425 );
1426
1427 r.engine_mut().feed(a, &wire(&[b"ECHO", b"after"]));
1429 pump(&mut r, &mut batch);
1430 assert!(r.engine().sink().sent(a).is_empty());
1431
1432 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1433 pump(&mut r, &mut batch);
1434 assert_eq!(
1435 r.engine().sink().sent(a),
1436 b"*2\r\n$1\r\nq\r\n$1\r\nx\r\n+PONG\r\n$5\r\nafter\r\n"
1437 );
1438 }
1439
1440 #[test]
1445 fn a_waiter_is_served_between_two_pipelined_pushes() {
1446 let (mut r, a, mut batch) = engine();
1447 let b = r.engine_mut().accept();
1448 r.engine_mut()
1449 .feed(a, &wire(&[b"BLPOP", b"p1", b"p2", b"0"]));
1450 pump(&mut r, &mut batch);
1451
1452 let mut stream = wire(&[b"RPUSH", b"p2", b"second"]);
1453 stream.extend(wire(&[b"RPUSH", b"p1", b"first"]));
1454 r.engine_mut().feed(b, &stream);
1455 pump(&mut r, &mut batch);
1456
1457 assert_eq!(
1458 r.engine().sink().sent(a),
1459 b"*2\r\n$2\r\np2\r\n$6\r\nsecond\r\n"
1460 );
1461 r.engine_mut()
1463 .feed(b, &wire(&[b"LRANGE", b"p1", b"0", b"-1"]));
1464 pump(&mut r, &mut batch);
1465 assert!(
1466 r.engine()
1467 .sink()
1468 .sent(b)
1469 .ends_with(b"*1\r\n$5\r\nfirst\r\n")
1470 );
1471 }
1472
1473 #[test]
1477 fn a_waiter_woken_by_another_waiter() {
1478 let (mut r, a, mut batch) = engine();
1479 let b = r.engine_mut().accept();
1480 let c = r.engine_mut().accept();
1481
1482 r.engine_mut()
1483 .feed(a, &wire(&[b"BLMOVE", b"x", b"y", b"LEFT", b"RIGHT", b"0"]));
1484 pump(&mut r, &mut batch);
1485 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"y", b"0"]));
1486 pump(&mut r, &mut batch);
1487 assert_eq!(r.engine().server().parked(), 2);
1488
1489 r.engine_mut().feed(c, &wire(&[b"RPUSH", b"x", b"chain"]));
1490 pump(&mut r, &mut batch);
1491
1492 assert_eq!(r.engine().sink().sent(a), b"$5\r\nchain\r\n");
1493 assert_eq!(
1494 r.engine().sink().sent(b),
1495 b"*2\r\n$1\r\ny\r\n$5\r\nchain\r\n"
1496 );
1497 assert_eq!(r.engine().server().parked(), 0);
1498 }
1499
1500 #[test]
1503 fn a_waiter_is_only_woken_on_the_database_it_blocked_on() {
1504 let (mut r, a, mut batch) = engine();
1505 let b = r.engine_mut().accept();
1506 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
1507 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1508 pump(&mut r, &mut batch);
1509 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n");
1510
1511 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"wrongdb"]));
1512 pump(&mut r, &mut batch);
1513 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n", "still waiting");
1514
1515 r.engine_mut().feed(b, &wire(&[b"SELECT", b"3"]));
1516 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"rightdb"]));
1517 pump(&mut r, &mut batch);
1518 assert!(r.engine().sink().sent(a).ends_with(b"$7\r\nrightdb\r\n"));
1519 }
1520
1521 #[test]
1523 fn a_client_that_waited_long_enough_gets_a_null_array() {
1524 let (mut r, conn, mut batch) = timed();
1525 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"30"]));
1526 pump(&mut r, &mut batch);
1527 assert!(r.engine().sink().sent(conn).is_empty());
1528
1529 r.engine_mut().server_mut().set_clock_ms(START_MS + 29_999);
1530 pump(&mut r, &mut batch);
1531 assert!(
1532 r.engine().sink().sent(conn).is_empty(),
1533 "a millisecond short"
1534 );
1535
1536 r.engine_mut().server_mut().set_clock_ms(START_MS + 30_000);
1537 pump(&mut r, &mut batch);
1538 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n");
1540 assert_eq!(r.engine().server().parked(), 0);
1541 }
1542
1543 #[test]
1547 fn every_blocking_command_times_out_with_the_same_null_array() {
1548 for cmd in [
1549 &[b"BLPOP".as_slice(), b"q", b"0.001"][..],
1550 &[b"BRPOP", b"q", b"0.001"],
1551 &[b"BLMOVE", b"q", b"d", b"LEFT", b"RIGHT", b"0.001"],
1552 &[b"BRPOPLPUSH", b"q", b"d", b"0.001"],
1553 &[b"BLMPOP", b"0.001", b"1", b"q", b"LEFT"],
1554 ] {
1555 let (mut r, conn, mut batch) = timed();
1556 r.engine_mut().feed(conn, &wire(cmd));
1557 pump(&mut r, &mut batch);
1558 r.engine_mut().server_mut().set_clock_ms(START_MS + 1);
1559 pump(&mut r, &mut batch);
1560 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n", "for {cmd:?}");
1561 }
1562 }
1563
1564 #[test]
1567 fn a_waiter_that_timed_out_does_not_eat_a_later_push() {
1568 let (mut r, a, mut batch) = timed();
1569 let b = r.engine_mut().accept();
1570 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"1"]));
1571 pump(&mut r, &mut batch);
1572 r.engine_mut().server_mut().set_clock_ms(START_MS + 1000);
1573 pump(&mut r, &mut batch);
1574 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n");
1575
1576 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"late"]));
1577 r.engine_mut()
1578 .feed(b, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1579 pump(&mut r, &mut batch);
1580 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n", "nothing more");
1581 assert!(r.engine().sink().sent(b).ends_with(b"*1\r\n$4\r\nlate\r\n"));
1582 }
1583
1584 #[test]
1589 fn a_client_that_goes_away_while_it_waits_takes_its_waiter_with_it() {
1590 let (mut r, a, mut batch) = engine();
1591 let b = r.engine_mut().accept();
1592 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1593 pump(&mut r, &mut batch);
1594 assert_eq!(r.engine().server().parked(), 1);
1595
1596 r.engine_mut().hangup(a);
1597 pump(&mut r, &mut batch);
1598 assert_eq!(r.engine().server().parked(), 0);
1599 assert_eq!(r.engine().clients(), 1);
1600
1601 let again = r.engine_mut().accept();
1604 assert_eq!(again, a);
1605 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1606 r.engine_mut()
1607 .feed(again, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1608 pump(&mut r, &mut batch);
1609 assert_eq!(r.engine().sink().sent(again), b"*1\r\n$1\r\nx\r\n");
1610 }
1611
1612 #[test]
1616 fn a_hangup_while_parked_gives_back_the_slot_and_the_decoders() {
1617 let (mut r, a, mut batch) = engine();
1618 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1619 stream.extend(wire(&[b"PING"]));
1620 stream.extend(wire(&[b"PING"]));
1621 r.engine_mut().feed(a, &stream);
1622 pump(&mut r, &mut batch);
1623
1624 let decoders = r.engine().decoders();
1625 r.engine_mut().hangup(a);
1626 pump(&mut r, &mut batch);
1627
1628 assert_eq!(r.engine().clients(), 0);
1629 assert!(r.engine().sink().was_closed(a));
1630 assert_eq!(r.engine().decoders(), decoders, "the pool came back whole");
1631 let again = r.engine_mut().accept();
1632 assert_eq!(again, a);
1633 r.engine_mut().feed(again, &wire(&[b"PING"]));
1634 pump(&mut r, &mut batch);
1635 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1636 }
1637
1638 #[test]
1641 fn a_published_message_lands_on_the_subscriber() {
1642 let (mut r, sub, mut batch) = engine();
1643 let pubr = r.engine_mut().accept();
1644
1645 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1646 pump(&mut r, &mut batch);
1647 assert_eq!(
1648 r.engine().sink().sent(sub),
1649 b"*3\r\n$9\r\nsubscribe\r\n$4\r\nnews\r\n:1\r\n"
1650 );
1651 r.engine_mut().sink_mut().clear();
1652
1653 r.engine_mut()
1654 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1655 pump(&mut r, &mut batch);
1656 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1657 assert_eq!(
1658 r.engine().sink().sent(sub),
1659 b"*3\r\n$7\r\nmessage\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1660 );
1661 }
1662
1663 #[test]
1666 fn a_pattern_subscriber_is_told_the_pattern_and_the_channel() {
1667 let (mut r, sub, mut batch) = engine();
1668 let pubr = r.engine_mut().accept();
1669
1670 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"ne*"]));
1671 pump(&mut r, &mut batch);
1672 r.engine_mut().sink_mut().clear();
1673
1674 r.engine_mut()
1675 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1676 pump(&mut r, &mut batch);
1677 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1678 assert_eq!(
1679 r.engine().sink().sent(sub),
1680 b"*4\r\n$8\r\npmessage\r\n$3\r\nne*\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1681 );
1682 }
1683
1684 #[test]
1689 fn resp2_takes_almost_nothing_from_a_subscriber() {
1690 let (mut r, conn, mut batch) = engine();
1691
1692 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1693 pump(&mut r, &mut batch);
1694 r.engine_mut().sink_mut().clear();
1695
1696 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1697 pump(&mut r, &mut batch);
1698 assert_eq!(
1699 r.engine().sink().sent(conn),
1700 b"-ERR Can't execute 'get': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context\r\n"
1701 );
1702 r.engine_mut().sink_mut().clear();
1703
1704 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1706 pump(&mut r, &mut batch);
1707 assert_eq!(
1708 r.engine().sink().sent(conn),
1709 b"*2\r\n$4\r\npong\r\n$0\r\n\r\n"
1710 );
1711 r.engine_mut().sink_mut().clear();
1712
1713 r.engine_mut().feed(conn, &wire(&[b"UNSUBSCRIBE", b"a"]));
1715 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1716 pump(&mut r, &mut batch);
1717 assert_eq!(
1718 r.engine().sink().sent(conn),
1719 b"*3\r\n$11\r\nunsubscribe\r\n$1\r\na\r\n:0\r\n$-1\r\n"
1720 );
1721 }
1722
1723 #[test]
1727 fn a_shard_channel_and_a_pattern_do_not_hear_each_other() {
1728 let (mut r, sub, mut batch) = engine();
1729 let pubr = r.engine_mut().accept();
1730
1731 r.engine_mut().feed(sub, &wire(&[b"SSUBSCRIBE", b"sx"]));
1732 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"s*"]));
1733 pump(&mut r, &mut batch);
1734 r.engine_mut().sink_mut().clear();
1735
1736 r.engine_mut()
1737 .feed(pubr, &wire(&[b"SPUBLISH", b"sx", b"one"]));
1738 pump(&mut r, &mut batch);
1739 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1740 assert_eq!(
1741 r.engine().sink().sent(sub),
1742 b"*3\r\n$8\r\nsmessage\r\n$2\r\nsx\r\n$3\r\none\r\n"
1743 );
1744 r.engine_mut().sink_mut().clear();
1745
1746 r.engine_mut()
1747 .feed(pubr, &wire(&[b"PUBLISH", b"sx", b"two"]));
1748 pump(&mut r, &mut batch);
1749 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1750 assert_eq!(
1751 r.engine().sink().sent(sub),
1752 b"*4\r\n$8\r\npmessage\r\n$2\r\ns*\r\n$2\r\nsx\r\n$3\r\ntwo\r\n"
1753 );
1754 }
1755
1756 #[test]
1760 fn a_subscriber_that_goes_away_leaves_the_registry() {
1761 let (mut r, sub, mut batch) = engine();
1762 let pubr = r.engine_mut().accept();
1763
1764 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1765 pump(&mut r, &mut batch);
1766 r.engine_mut().hangup(sub);
1767 pump(&mut r, &mut batch);
1768 r.engine_mut().sink_mut().clear();
1769
1770 r.engine_mut()
1771 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1772 pump(&mut r, &mut batch);
1773 assert_eq!(r.engine().sink().sent(pubr), b":0\r\n");
1774
1775 let next = r.engine_mut().accept();
1777 assert_eq!(next, sub);
1778 r.engine_mut()
1779 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1780 pump(&mut r, &mut batch);
1781 assert_eq!(r.engine().sink().sent(next), b"");
1782 }
1783
1784 #[test]
1793 fn resp3_delivers_a_message_as_a_push() {
1794 let (mut r, conn, mut batch) = engine();
1795
1796 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1797 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1798 pump(&mut r, &mut batch);
1799 r.engine_mut().sink_mut().clear();
1800
1801 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1802 r.engine_mut().feed(conn, &wire(&[b"PUBLISH", b"a", b"w"]));
1803 pump(&mut r, &mut batch);
1804 assert_eq!(
1805 r.engine().sink().sent(conn),
1806 b"_\r\n:1\r\n>3\r\n$7\r\nmessage\r\n$1\r\na\r\n$1\r\nw\r\n"
1807 );
1808 }
1809
1810 #[test]
1813 fn a_write_reaches_a_keyspace_subscriber() {
1814 let (mut r, sub, mut batch) = engine();
1815 let writer = r.engine_mut().accept();
1816
1817 r.engine_mut().feed(
1818 writer,
1819 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"KEA"]),
1820 );
1821 r.engine_mut()
1822 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1823 pump(&mut r, &mut batch);
1824 r.engine_mut().sink_mut().clear();
1825
1826 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1827 pump(&mut r, &mut batch);
1828 assert_eq!(r.engine().sink().sent(writer), b"+OK\r\n");
1829 assert_eq!(
1830 r.engine().sink().sent(sub),
1831 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1832 $16\r\n__keyspace@0__:k\r\n$3\r\nset\r\n\
1833 *4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1834 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n"
1835 );
1836 }
1837
1838 #[test]
1841 fn a_write_says_nothing_until_the_setting_turns_it_on() {
1842 let (mut r, sub, mut batch) = engine();
1843 let writer = r.engine_mut().accept();
1844
1845 r.engine_mut()
1846 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1847 pump(&mut r, &mut batch);
1848 r.engine_mut().sink_mut().clear();
1849
1850 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1851 pump(&mut r, &mut batch);
1852 assert_eq!(r.engine().sink().sent(sub), b"");
1853 }
1854
1855 #[test]
1858 fn only_the_classes_that_were_asked_for_are_published() {
1859 let (mut r, sub, mut batch) = engine();
1860 let writer = r.engine_mut().accept();
1861
1862 r.engine_mut().feed(
1863 writer,
1864 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"Eg"]),
1865 );
1866 r.engine_mut()
1867 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1868 pump(&mut r, &mut batch);
1869 r.engine_mut().sink_mut().clear();
1870
1871 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1872 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
1873 pump(&mut r, &mut batch);
1874 assert_eq!(
1875 r.engine().sink().sent(sub),
1876 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1877 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
1878 );
1879 }
1880
1881 #[test]
1884 fn a_write_with_a_deadline_on_it_says_two_things() {
1885 let (mut r, sub, mut batch) = engine();
1886 let writer = r.engine_mut().accept();
1887
1888 r.engine_mut().feed(
1889 writer,
1890 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
1891 );
1892 r.engine_mut()
1893 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
1894 pump(&mut r, &mut batch);
1895 r.engine_mut().sink_mut().clear();
1896
1897 r.engine_mut()
1898 .feed(writer, &wire(&[b"SETEX", b"k", b"100", b"v"]));
1899 pump(&mut r, &mut batch);
1900 assert_eq!(
1901 r.engine().sink().sent(sub),
1902 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
1903 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
1904 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
1905 $21\r\n__keyevent@0__:expire\r\n$1\r\nk\r\n"
1906 );
1907 }
1908
1909 fn watching() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
1915 watching_flags(b"EA")
1916 }
1917
1918 fn watching_flags(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
1920 let (mut r, sub, mut batch) = engine();
1921 let writer = r.engine_mut().accept();
1922 r.engine_mut().feed(
1923 writer,
1924 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
1925 );
1926 r.engine_mut()
1927 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
1928 pump(&mut r, &mut batch);
1929 r.engine_mut().sink_mut().clear();
1930 (r, sub, writer, batch)
1931 }
1932
1933 fn fired(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
1939 fired_on(r, sub, 0)
1940 }
1941
1942 fn fired_on(r: &Reactor<Wire<Recorder>>, sub: ConnId, db: usize) -> Vec<(String, String)> {
1945 let head = format!("__keyevent@{db}__:");
1946 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
1947 let mut out = Vec::new();
1948 let mut parts = sent.split("\r\n");
1949 while let Some(p) = parts.next() {
1950 let Some(event) = p.strip_prefix(head.as_str()) else {
1951 continue;
1952 };
1953 if event == "*" {
1956 continue;
1957 }
1958 parts.next();
1959 let key = parts.next().unwrap_or_default();
1960 out.push((event.to_owned(), key.to_owned()));
1961 }
1962 out
1963 }
1964
1965 #[test]
1968 fn taking_the_last_of_a_collection_says_the_key_went_with_it() {
1969 let (mut r, sub, writer, mut batch) = watching();
1970
1971 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"k", b"a"]));
1972 r.engine_mut().feed(writer, &wire(&[b"LPOP", b"k"]));
1973 pump(&mut r, &mut batch);
1974 assert_eq!(
1975 fired(&r, sub),
1976 [("rpush", "k"), ("lpop", "k"), ("del", "k")]
1977 .map(|(e, k)| (e.to_owned(), k.to_owned()))
1978 );
1979 }
1980
1981 #[test]
1984 fn a_move_onto_a_member_already_there_says_only_the_removal() {
1985 let (mut r, sub, writer, mut batch) = watching();
1986
1987 r.engine_mut().feed(writer, &wire(&[b"SADD", b"a", b"m"]));
1988 r.engine_mut()
1989 .feed(writer, &wire(&[b"SADD", b"b", b"m", b"n"]));
1990 pump(&mut r, &mut batch);
1991 r.engine_mut().sink_mut().clear();
1992
1993 r.engine_mut()
1994 .feed(writer, &wire(&[b"SMOVE", b"a", b"b", b"m"]));
1995 pump(&mut r, &mut batch);
1996 assert_eq!(
1997 fired(&r, sub),
1998 [("srem", "a"), ("del", "a")].map(|(e, k)| (e.to_owned(), k.to_owned()))
1999 );
2000 }
2001
2002 #[test]
2005 fn a_score_that_did_not_move_says_nothing() {
2006 let (mut r, sub, writer, mut batch) = watching();
2007
2008 r.engine_mut()
2009 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2010 pump(&mut r, &mut batch);
2011 r.engine_mut().sink_mut().clear();
2012
2013 r.engine_mut()
2014 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2015 r.engine_mut()
2016 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"0", b"m"]));
2017 pump(&mut r, &mut batch);
2018 assert_eq!(fired(&r, sub), []);
2019
2020 r.engine_mut()
2023 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"1", b"m"]));
2024 pump(&mut r, &mut batch);
2025 assert_eq!(fired(&r, sub), [("zincr".to_owned(), "z".to_owned())]);
2026 }
2027
2028 #[test]
2031 fn a_stream_write_says_what_the_trim_behind_it_took() {
2032 let (mut r, sub, writer, mut batch) = watching();
2033
2034 r.engine_mut()
2035 .feed(writer, &wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]));
2036 r.engine_mut().feed(
2037 writer,
2038 &wire(&[b"XADD", b"s", b"MAXLEN", b"9", b"2-1", b"f", b"v"]),
2039 );
2040 r.engine_mut().feed(
2041 writer,
2042 &wire(&[b"XADD", b"s", b"MAXLEN", b"1", b"3-1", b"f", b"v"]),
2043 );
2044 pump(&mut r, &mut batch);
2045 assert_eq!(
2046 fired(&r, sub),
2047 [("xadd", "s"), ("xadd", "s"), ("xadd", "s"), ("xtrim", "s")]
2048 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2049 );
2050 }
2051
2052 #[test]
2056 fn acknowledging_an_entry_that_is_already_gone_says_nothing() {
2057 let (mut r, sub, writer, mut batch) = watching();
2058
2059 for cmd in [
2060 wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]),
2061 wire(&[b"XGROUP", b"CREATE", b"s", b"g", b"0"]),
2062 wire(&[b"XREADGROUP", b"GROUP", b"g", b"c", b"STREAMS", b"s", b">"]),
2063 wire(&[b"XDEL", b"s", b"1-1"]),
2064 ] {
2065 r.engine_mut().feed(writer, &cmd);
2066 }
2067 pump(&mut r, &mut batch);
2068 r.engine_mut().sink_mut().clear();
2069
2070 r.engine_mut().feed(
2071 writer,
2072 &wire(&[b"XACKDEL", b"s", b"g", b"IDS", b"1", b"1-1"]),
2073 );
2074 pump(&mut r, &mut batch);
2075 assert_eq!(fired(&r, sub), []);
2076 }
2077
2078 #[test]
2081 fn emptying_a_hash_says_the_key_went_with_the_last_field() {
2082 let (mut r, sub, writer, mut batch) = watching();
2083
2084 r.engine_mut()
2085 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2086 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"a"]));
2087 r.engine_mut()
2090 .feed(writer, &wire(&[b"HDEL", b"h", b"b", b"a"]));
2091 pump(&mut r, &mut batch);
2092 assert_eq!(
2093 fired(&r, sub),
2094 [("hset", "h"), ("hdel", "h"), ("hdel", "h"), ("del", "h")]
2095 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2096 );
2097 }
2098
2099 #[test]
2102 fn a_field_deadline_already_past_reads_as_a_removal() {
2103 let (mut r, sub, writer, mut batch) = watching();
2104
2105 r.engine_mut()
2106 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2107 pump(&mut r, &mut batch);
2108 r.engine_mut().sink_mut().clear();
2109
2110 r.engine_mut().feed(
2111 writer,
2112 &wire(&[b"HEXPIRE", b"h", b"0", b"FIELDS", b"1", b"a"]),
2113 );
2114 r.engine_mut().feed(
2115 writer,
2116 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"b"]),
2117 );
2118 pump(&mut r, &mut batch);
2119 assert_eq!(
2120 fired(&r, sub),
2121 [("hdel", "h"), ("hexpire", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2122 );
2123 }
2124
2125 #[test]
2128 fn a_write_under_a_deadline_already_gone_says_the_write_first() {
2129 let (mut r, sub, writer, mut batch) = watching();
2130
2131 r.engine_mut().feed(
2132 writer,
2133 &wire(&[b"HSETEX", b"h", b"EXAT", b"1", b"FIELDS", b"1", b"a", b"1"]),
2134 );
2135 pump(&mut r, &mut batch);
2136 assert_eq!(
2137 fired(&r, sub),
2138 [("hset", "h"), ("hdel", "h"), ("del", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2139 );
2140 }
2141
2142 #[test]
2145 fn clearing_a_deadline_that_was_never_set_says_nothing() {
2146 let (mut r, sub, writer, mut batch) = watching();
2147
2148 r.engine_mut()
2149 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2150 r.engine_mut().feed(
2151 writer,
2152 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"a"]),
2153 );
2154 pump(&mut r, &mut batch);
2155 r.engine_mut().sink_mut().clear();
2156
2157 r.engine_mut()
2158 .feed(writer, &wire(&[b"HPERSIST", b"h", b"FIELDS", b"1", b"b"]));
2159 r.engine_mut().feed(
2160 writer,
2161 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"1", b"b"]),
2162 );
2163 pump(&mut r, &mut batch);
2164 assert_eq!(fired(&r, sub), []);
2165
2166 r.engine_mut().feed(
2169 writer,
2170 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"2", b"a", b"b"]),
2171 );
2172 pump(&mut r, &mut batch);
2173 assert_eq!(fired(&r, sub), [("hpersist".to_owned(), "h".to_owned())]);
2174 }
2175
2176 #[test]
2179 fn a_key_that_was_not_there_before_says_so() {
2180 let (mut r, sub, writer, mut batch) = watching_flags(b"En");
2181
2182 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2183 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2184 r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"x"]));
2185 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2186 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2187 pump(&mut r, &mut batch);
2188 assert_eq!(
2189 fired(&r, sub),
2190 [("new", "k"), ("new", "l")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2191 );
2192 }
2193
2194 #[test]
2197 fn the_news_of_a_new_key_comes_before_the_write_that_made_it() {
2198 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2199
2200 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2201 r.engine_mut().feed(writer, &wire(&[b"SET", b"b", b"2"]));
2202 pump(&mut r, &mut batch);
2203 r.engine_mut().sink_mut().clear();
2204
2205 r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2209 pump(&mut r, &mut batch);
2210 assert_eq!(
2211 fired(&r, sub),
2212 [("new", "b"), ("rename_from", "a"), ("rename_to", "b")]
2213 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2214 );
2215 }
2216
2217 #[test]
2221 fn writing_over_a_destination_is_not_a_key_arriving() {
2222 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2223
2224 r.engine_mut()
2225 .feed(writer, &wire(&[b"RPUSH", b"l", b"c", b"a", b"b"]));
2226 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"d", b"x"]));
2227 pump(&mut r, &mut batch);
2228 r.engine_mut().sink_mut().clear();
2229
2230 r.engine_mut()
2231 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2232 pump(&mut r, &mut batch);
2233 assert_eq!(fired(&r, sub), [("sortstore".to_owned(), "d".to_owned())]);
2234 r.engine_mut().sink_mut().clear();
2235
2236 r.engine_mut().feed(writer, &wire(&[b"DEL", b"d"]));
2239 r.engine_mut()
2240 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2241 pump(&mut r, &mut batch);
2242 assert_eq!(
2243 fired(&r, sub),
2244 [("del", "d"), ("new", "d"), ("sortstore", "d")]
2245 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2246 );
2247 }
2248
2249 #[test]
2252 fn replacing_a_value_says_what_went_and_whether_the_kind_changed() {
2253 let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2254
2255 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2256 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2257 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2258 r.engine_mut().feed(writer, &wire(&[b"SET", b"l", b"v"]));
2259 pump(&mut r, &mut batch);
2260 assert_eq!(
2261 fired(&r, sub),
2262 [
2263 ("overwritten", "k"),
2264 ("overwritten", "l"),
2265 ("type_changed", "l")
2266 ]
2267 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2268 );
2269 }
2270
2271 #[test]
2274 fn a_write_that_changes_part_of_a_value_has_not_replaced_it() {
2275 let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2276
2277 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"1"]));
2278 r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"2"]));
2279 r.engine_mut().feed(writer, &wire(&[b"INCR", b"k"]));
2280 r.engine_mut()
2281 .feed(writer, &wire(&[b"SETRANGE", b"k", b"0", b"9"]));
2282 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2283 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2284 pump(&mut r, &mut batch);
2285 assert_eq!(fired(&r, sub), []);
2286 }
2287
2288 #[test]
2292 fn a_rename_says_what_it_replaced_after_saying_what_it_did() {
2293 let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2294
2295 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2296 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"b", b"x"]));
2297 pump(&mut r, &mut batch);
2298 r.engine_mut().sink_mut().clear();
2299
2300 r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2301 pump(&mut r, &mut batch);
2302 assert_eq!(
2303 fired(&r, sub),
2304 [
2305 ("new", "b"),
2306 ("rename_from", "a"),
2307 ("rename_to", "b"),
2308 ("overwritten", "b"),
2309 ("type_changed", "b")
2310 ]
2311 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2312 );
2313 }
2314
2315 #[test]
2318 fn a_store_form_says_what_it_replaced_before_saying_what_it_did() {
2319 let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2320
2321 r.engine_mut().feed(writer, &wire(&[b"SADD", b"s", b"m"]));
2322 r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"q"]));
2323 pump(&mut r, &mut batch);
2324 r.engine_mut().sink_mut().clear();
2325
2326 r.engine_mut()
2327 .feed(writer, &wire(&[b"SINTERSTORE", b"d", b"s"]));
2328 pump(&mut r, &mut batch);
2329 assert_eq!(
2330 fired(&r, sub),
2331 [
2332 ("overwritten", "d"),
2333 ("type_changed", "d"),
2334 ("sinterstore", "d")
2335 ]
2336 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2337 );
2338 }
2339
2340 #[test]
2343 fn a_bit_write_that_left_the_value_alone_says_nothing() {
2344 let (mut r, sub, writer, mut batch) = watching();
2345
2346 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2350 pump(&mut r, &mut batch);
2351 r.engine_mut().sink_mut().clear();
2352
2353 r.engine_mut()
2354 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"1"]));
2355 r.engine_mut()
2356 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2357 r.engine_mut()
2358 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2359 r.engine_mut()
2363 .feed(writer, &wire(&[b"SETBIT", b"k", b"100", b"0"]));
2364 pump(&mut r, &mut batch);
2365 assert_eq!(
2366 fired(&r, sub),
2367 [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2368 );
2369 }
2370
2371 #[test]
2374 fn a_bitfield_that_wrote_the_same_values_back_says_nothing() {
2375 let (mut r, sub, writer, mut batch) = watching();
2376
2377 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2378 pump(&mut r, &mut batch);
2379 r.engine_mut().sink_mut().clear();
2380
2381 r.engine_mut().feed(
2383 writer,
2384 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"97"]),
2385 );
2386 r.engine_mut()
2387 .feed(writer, &wire(&[b"BITFIELD", b"k", b"GET", b"u8", b"0"]));
2388 r.engine_mut().feed(
2389 writer,
2390 &wire(&[b"BITFIELD", b"k", b"INCRBY", b"u8", b"0", b"0"]),
2391 );
2392 pump(&mut r, &mut batch);
2393 assert_eq!(fired(&r, sub), []);
2394
2395 r.engine_mut().feed(
2398 writer,
2399 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"98"]),
2400 );
2401 r.engine_mut().feed(
2402 writer,
2403 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"800", b"0"]),
2404 );
2405 pump(&mut r, &mut batch);
2406 assert_eq!(
2407 fired(&r, sub),
2408 [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2409 );
2410 }
2411
2412 #[test]
2415 fn the_sketch_commands_say_what_a_mass_add_says() {
2416 let (mut r, sub, writer, mut batch) = watching();
2417
2418 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2419 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2421 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h"]));
2423 r.engine_mut().feed(writer, &wire(&[b"PFMERGE", b"d"]));
2425 r.engine_mut()
2426 .feed(writer, &wire(&[b"PFMERGE", b"d", b"h"]));
2427 pump(&mut r, &mut batch);
2428 assert_eq!(
2429 fired(&r, sub),
2430 [("pfadd", "h"), ("pfadd", "d"), ("pfadd", "d")]
2431 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2432 );
2433 }
2434
2435 #[test]
2438 fn the_geo_commands_say_what_the_sorted_set_under_them_did() {
2439 let (mut r, sub, writer, mut batch) = watching();
2440
2441 let point: &[&[u8]] = &[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"];
2442 r.engine_mut().feed(writer, &wire(point));
2443 r.engine_mut().feed(writer, &wire(point));
2445 r.engine_mut().feed(
2447 writer,
2448 &wire(&[b"GEOADD", b"g", b"14.0", b"38.115556", b"P"]),
2449 );
2450 r.engine_mut().feed(
2451 writer,
2452 &wire(&[
2453 b"GEORADIUS",
2454 b"g",
2455 b"14.0",
2456 b"38.0",
2457 b"200",
2458 b"km",
2459 b"STORE",
2460 b"d",
2461 ]),
2462 );
2463 r.engine_mut().feed(
2464 writer,
2465 &wire(&[
2466 b"GEOSEARCHSTORE",
2467 b"e",
2468 b"g",
2469 b"FROMLONLAT",
2470 b"14.0",
2471 b"38.0",
2472 b"BYRADIUS",
2473 b"200",
2474 b"km",
2475 ]),
2476 );
2477 pump(&mut r, &mut batch);
2478 assert_eq!(
2479 fired(&r, sub),
2480 [
2481 ("zadd", "g"),
2482 ("zadd", "g"),
2483 ("georadiusstore", "d"),
2484 ("geosearchstore", "e")
2485 ]
2486 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2487 );
2488 }
2489
2490 #[test]
2493 fn a_geo_store_that_found_nothing_takes_the_destination_with_it() {
2494 let (mut r, sub, writer, mut batch) = watching();
2495
2496 r.engine_mut().feed(
2497 writer,
2498 &wire(&[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"]),
2499 );
2500 r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"x"]));
2501 pump(&mut r, &mut batch);
2502 r.engine_mut().sink_mut().clear();
2503
2504 r.engine_mut().feed(
2505 writer,
2506 &wire(&[
2507 b"GEORADIUS",
2508 b"g",
2509 b"1.0",
2510 b"1.0",
2511 b"1",
2512 b"km",
2513 b"STORE",
2514 b"d",
2515 ]),
2516 );
2517 r.engine_mut().feed(
2520 writer,
2521 &wire(&[
2522 b"GEORADIUS",
2523 b"g",
2524 b"1.0",
2525 b"1.0",
2526 b"1",
2527 b"km",
2528 b"STORE",
2529 b"d",
2530 ]),
2531 );
2532 pump(&mut r, &mut batch);
2533 assert_eq!(
2534 fired(&r, sub),
2535 [("del", "d")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2536 );
2537 }
2538
2539 #[test]
2543 fn a_key_that_lands_on_another_database_is_new_over_there() {
2544 let (mut r, sub, mut batch) = engine();
2545 let writer = r.engine_mut().accept();
2546 r.engine_mut().feed(
2547 writer,
2548 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EAnoc"]),
2549 );
2550 r.engine_mut().feed(
2551 sub,
2552 &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*", b"__keyevent@1__:*"]),
2553 );
2554 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2555 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2556 pump(&mut r, &mut batch);
2557 r.engine_mut().sink_mut().clear();
2558
2559 r.engine_mut()
2560 .feed(writer, &wire(&[b"COPY", b"a", b"b", b"DB", b"1"]));
2561 r.engine_mut().feed(writer, &wire(&[b"MOVE", b"k", b"1"]));
2562 pump(&mut r, &mut batch);
2563 assert_eq!(
2564 fired_on(&r, sub, 1),
2565 [
2566 ("new", "b"),
2567 ("copy_to", "b"),
2568 ("new", "k"),
2569 ("move_to", "k")
2570 ]
2571 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2572 );
2573 assert_eq!(
2576 fired_on(&r, sub, 0),
2577 [("move_from", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2578 );
2579 }
2580
2581 #[test]
2587 fn a_read_that_found_nothing_says_which_key_it_was() {
2588 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2589
2590 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2591 r.engine_mut()
2592 .feed(writer, &wire(&[b"MGET", b"a", b"nk", b"nk"]));
2593 r.engine_mut()
2594 .feed(writer, &wire(&[b"EXISTS", b"nj", b"a"]));
2595 pump(&mut r, &mut batch);
2596 assert_eq!(
2597 fired(&r, sub),
2598 [("keymiss", "nk"), ("keymiss", "nk"), ("keymiss", "nj")]
2599 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2600 );
2601 }
2602
2603 #[test]
2606 fn only_the_shape_of_a_write_that_reads_says_it() {
2607 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2608
2609 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2612 r.engine_mut().feed(
2613 writer,
2614 &wire(&[b"BITFIELD", b"nk", b"SET", b"u8", b"0", b"1"]),
2615 );
2616 r.engine_mut().feed(writer, &wire(&[b"LPOP", b"nk"]));
2617 pump(&mut r, &mut batch);
2618 assert_eq!(fired(&r, sub), []);
2619
2620 r.engine_mut()
2622 .feed(writer, &wire(&[b"SET", b"nj", b"v", b"GET"]));
2623 r.engine_mut()
2624 .feed(writer, &wire(&[b"BITFIELD", b"nl", b"GET", b"u8", b"0"]));
2625 r.engine_mut().feed(writer, &wire(&[b"GETDEL", b"nm"]));
2626 pump(&mut r, &mut batch);
2627 assert_eq!(
2628 fired(&r, sub),
2629 [("keymiss", "nj"), ("keymiss", "nl"), ("keymiss", "nm")]
2630 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2631 );
2632 }
2633
2634 #[test]
2637 fn a_store_form_says_it_only_for_its_sources() {
2638 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2639
2640 r.engine_mut()
2641 .feed(writer, &wire(&[b"SINTERSTORE", b"dst", b"nk", b"nj"]));
2642 r.engine_mut()
2643 .feed(writer, &wire(&[b"ZUNIONSTORE", b"dst", b"1", b"nz"]));
2644 r.engine_mut()
2645 .feed(writer, &wire(&[b"ZRANGESTORE", b"dst", b"nz", b"0", b"-1"]));
2646 pump(&mut r, &mut batch);
2647 assert_eq!(
2648 fired(&r, sub),
2649 [
2650 ("keymiss", "nk"),
2651 ("keymiss", "nj"),
2652 ("keymiss", "nz"),
2653 ("keymiss", "nz")
2654 ]
2655 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2656 );
2657 }
2658
2659 #[test]
2663 fn the_stream_reads_say_it_for_the_keys_behind_the_keyword() {
2664 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2665
2666 r.engine_mut().feed(
2667 writer,
2668 &wire(&[b"XREAD", b"STREAMS", b"nk", b"nj", b"0", b"0"]),
2669 );
2670 pump(&mut r, &mut batch);
2671 assert_eq!(
2672 fired(&r, sub),
2673 [
2674 ("keymiss", "nk"),
2675 ("keymiss", "nj"),
2676 ("keymiss", "nk"),
2677 ("keymiss", "nj")
2678 ]
2679 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2680 );
2681 }
2682
2683 #[test]
2687 fn an_argument_that_did_not_parse_takes_the_miss_back() {
2688 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2689
2690 r.engine_mut()
2691 .feed(writer, &wire(&[b"GETRANGE", b"nk", b"x", b"-1"]));
2692 r.engine_mut()
2693 .feed(writer, &wire(&[b"LPOS", b"nk", b"a", b"RANK", b"0"]));
2694 pump(&mut r, &mut batch);
2695 assert_eq!(fired(&r, sub), []);
2696
2697 r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2701 pump(&mut r, &mut batch);
2702 r.engine_mut().sink_mut().clear();
2703
2704 r.engine_mut()
2705 .feed(writer, &wire(&[b"SINTER", b"nk", b"s"]));
2706 pump(&mut r, &mut batch);
2707 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2708 }
2709
2710 #[test]
2714 fn a_read_stops_missing_where_it_stops_looking() {
2715 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2716
2717 r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2718 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"x"]));
2719 pump(&mut r, &mut batch);
2720 r.engine_mut().sink_mut().clear();
2721
2722 r.engine_mut()
2723 .feed(writer, &wire(&[b"SINTER", b"s", b"nk"]));
2724 pump(&mut r, &mut batch);
2725 assert_eq!(fired(&r, sub), []);
2726
2727 r.engine_mut().feed(writer, &wire(&[b"MGET", b"l", b"nk"]));
2730 pump(&mut r, &mut batch);
2731 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2732 }
2733
2734 #[test]
2738 fn the_keys_a_sort_pattern_names_say_it_as_they_are_read() {
2739 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2740
2741 r.engine_mut()
2742 .feed(writer, &wire(&[b"RPUSH", b"l", b"1", b"2"]));
2743 r.engine_mut().feed(writer, &wire(&[b"SET", b"w_1", b"5"]));
2744 pump(&mut r, &mut batch);
2745 r.engine_mut().sink_mut().clear();
2746
2747 r.engine_mut().feed(
2748 writer,
2749 &wire(&[b"SORT", b"l", b"BY", b"w_*", b"GET", b"p_*"]),
2750 );
2751 pump(&mut r, &mut batch);
2752 assert_eq!(
2753 fired(&r, sub),
2754 [("keymiss", "w_2"), ("keymiss", "p_2"), ("keymiss", "p_1")]
2755 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2756 );
2757 }
2758
2759 #[test]
2763 fn a_deadline_that_passed_is_news_before_the_miss_it_causes() {
2764 let (mut r, sub, mut batch) = timed();
2765 let writer = r.engine_mut().accept();
2766 r.engine_mut().feed(
2767 writer,
2768 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EgAm"]),
2769 );
2770 r.engine_mut()
2771 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2772 r.engine_mut()
2773 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
2774 pump(&mut r, &mut batch);
2775 r.engine_mut().sink_mut().clear();
2776
2777 r.engine().server().advance_clock_ms(50);
2778 r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
2779 pump(&mut r, &mut batch);
2780 assert_eq!(
2781 fired(&r, sub),
2782 [("expired", "k"), ("keymiss", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2783 );
2784 }
2785
2786 #[test]
2789 fn a_module_read_says_it_the_way_a_core_read_does() {
2790 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2791
2792 r.engine_mut().feed(writer, &wire(&[b"JSON.GET", b"nk"]));
2793 r.engine_mut().feed(writer, &wire(&[b"TS.GET", b"nj"]));
2794 r.engine_mut()
2795 .feed(writer, &wire(&[b"BF.EXISTS", b"nl", b"x"]));
2796 r.engine_mut().feed(writer, &wire(&[b"TDIGEST.MIN", b"nm"]));
2797 r.engine_mut().feed(writer, &wire(&[b"TOPK.LIST", b"nn"]));
2798 r.engine_mut().feed(writer, &wire(&[b"CMS.INFO", b"no"]));
2799 r.engine_mut().feed(writer, &wire(&[b"VCARD", b"np"]));
2800 pump(&mut r, &mut batch);
2801 assert_eq!(
2802 fired(&r, sub),
2803 [
2804 ("keymiss", "nk"),
2805 ("keymiss", "nj"),
2806 ("keymiss", "nl"),
2807 ("keymiss", "nm"),
2808 ("keymiss", "nn"),
2809 ("keymiss", "no"),
2810 ("keymiss", "np")
2811 ]
2812 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2813 );
2814
2815 r.engine_mut().sink_mut().clear();
2818 r.engine_mut()
2819 .feed(writer, &wire(&[b"JSON.MGET", b"nk", b"nj", b"$"]));
2820 pump(&mut r, &mut batch);
2821 assert_eq!(
2822 fired(&r, sub),
2823 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2824 );
2825 }
2826
2827 #[test]
2831 fn the_quiet_module_commands_stay_quiet() {
2832 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2833
2834 r.engine_mut()
2835 .feed(writer, &wire(&[b"JSON.SET", b"nk", b"$", b"1"]));
2836 r.engine_mut()
2837 .feed(writer, &wire(&[b"BF.ADD", b"nj", b"x"]));
2838 r.engine_mut()
2839 .feed(writer, &wire(&[b"TS.ADD", b"nl", b"1000", b"1"]));
2840 r.engine_mut().feed(writer, &wire(&[b"TS.INFO", b"nm"]));
2841 r.engine_mut().feed(writer, &wire(&[b"CF.COMPACT", b"nn"]));
2842 r.engine_mut()
2843 .feed(writer, &wire(&[b"JSON.DEBUG", b"HELP"]));
2844 r.engine_mut()
2845 .feed(writer, &wire(&[b"FT.GET", b"ni", b"no"]));
2846 r.engine_mut()
2847 .feed(writer, &wire(&[b"FT.SEARCH", b"ni", b"*"]));
2848 pump(&mut r, &mut batch);
2849 assert_eq!(fired(&r, sub), []);
2850
2851 r.engine_mut()
2853 .feed(writer, &wire(&[b"JSON.DEBUG", b"MEMORY", b"np"]));
2854 r.engine_mut()
2855 .feed(writer, &wire(&[b"FT.SUGGET", b"nq", b"x"]));
2856 r.engine_mut().feed(writer, &wire(&[b"FT.SUGLEN", b"nr"]));
2857 pump(&mut r, &mut batch);
2858 assert_eq!(
2859 fired(&r, sub),
2860 [("keymiss", "np"), ("keymiss", "nq"), ("keymiss", "nr")]
2861 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2862 );
2863 }
2864
2865 #[test]
2872 fn a_module_read_keeps_the_miss_a_later_argument_spoiled() {
2873 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2874
2875 r.engine_mut()
2876 .feed(writer, &wire(&[b"JSON.GET", b"nk", b"$..["]));
2877 r.engine_mut().feed(
2878 writer,
2879 &wire(&[b"VSIM", b"nj", b"ELE", b"e", b"COUNT", b"x"]),
2880 );
2881 pump(&mut r, &mut batch);
2882 assert_eq!(
2883 fired(&r, sub),
2884 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2885 );
2886 }
2887
2888 #[test]
2891 fn the_module_merges_stop_at_the_first_empty_source() {
2892 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2893
2894 r.engine_mut().feed(
2895 writer,
2896 &wire(&[b"TDIGEST.MERGE", b"nk", b"2", b"nj", b"nl"]),
2897 );
2898 pump(&mut r, &mut batch);
2899 assert_eq!(
2900 fired(&r, sub),
2901 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2902 );
2903
2904 r.engine_mut().sink_mut().clear();
2908 r.engine_mut()
2909 .feed(writer, &wire(&[b"CMS.MERGE", b"nk", b"1", b"nj"]));
2910 pump(&mut r, &mut batch);
2911 assert_eq!(fired(&r, sub), []);
2912
2913 r.engine_mut()
2916 .feed(writer, &wire(&[b"CMS.INITBYDIM", b"cm", b"100", b"5"]));
2917 pump(&mut r, &mut batch);
2918 r.engine_mut().sink_mut().clear();
2919
2920 r.engine_mut()
2921 .feed(writer, &wire(&[b"CMS.MERGE", b"cm", b"2", b"nj", b"nl"]));
2922 pump(&mut r, &mut batch);
2923 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nj".to_owned())]);
2924 }
2925
2926 fn watching_fields(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2932 let (mut r, sub, mut batch) = engine();
2933 let writer = r.engine_mut().accept();
2934 r.engine_mut().feed(
2935 writer,
2936 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
2937 );
2938 r.engine_mut()
2939 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__subkey*@0__:*"]));
2940 pump(&mut r, &mut batch);
2941 r.engine_mut().sink_mut().clear();
2942 (r, sub, writer, batch)
2943 }
2944
2945 fn carried(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
2951 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
2952 let mut out = Vec::new();
2953 let mut parts = sent.split("\r\n");
2954 while let Some(p) = parts.next() {
2955 if p != "pmessage" {
2956 continue;
2957 }
2958 let mut next = || {
2961 parts.next();
2962 parts.next().unwrap_or_default().to_owned()
2963 };
2964 next();
2965 let channel = next();
2966 out.push((channel, next()));
2967 }
2968 out
2969 }
2970
2971 #[test]
2975 fn the_subkey_channels_carry_the_fields_an_event_touched() {
2976 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
2977
2978 r.engine_mut()
2979 .feed(writer, &wire(&[b"HSET", b"h", b"a,b", b"1", b"c", b"2"]));
2980 pump(&mut r, &mut batch);
2981 assert_eq!(
2982 carried(&r, sub),
2983 [
2984 ("__subkeyspace@0__:h", "hset|3:a,b,1:c"),
2985 ("__subkeyevent@0__:hset", "1:h|3:a,b,1:c"),
2986 ("__subkeyspaceitem@0__:h\na,b", "hset"),
2987 ("__subkeyspaceitem@0__:h\nc", "hset"),
2988 ("__subkeyspaceevent@0__:hset|h", "3:a,b,1:c"),
2989 ]
2990 .map(|(c, p)| (c.to_owned(), p.to_owned()))
2991 );
2992 }
2993
2994 #[test]
2998 fn a_key_holding_a_newline_skips_the_per_field_channel() {
2999 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3000
3001 r.engine_mut()
3002 .feed(writer, &wire(&[b"HSET", b"h\nx", b"f", b"1"]));
3003 pump(&mut r, &mut batch);
3004 assert_eq!(
3005 carried(&r, sub),
3006 [
3007 ("__subkeyspace@0__:h\nx", "hset|1:f"),
3008 ("__subkeyevent@0__:hset", "3:h\nx|1:f"),
3009 ("__subkeyspaceevent@0__:hset|h\nx", "1:f"),
3010 ]
3011 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3012 );
3013 }
3014
3015 #[test]
3019 fn an_event_with_no_fields_stays_off_the_subkey_channels() {
3020 let (mut r, sub, writer, mut batch) = watching_fields(b"AS");
3021
3022 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3023 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
3024 r.engine_mut()
3025 .feed(writer, &wire(&[b"HSET", b"h", b"f", b"1"]));
3026 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"f"]));
3027 pump(&mut r, &mut batch);
3028 assert_eq!(
3029 carried(&r, sub),
3030 [
3031 ("__subkeyspace@0__:h", "hset|1:f"),
3032 ("__subkeyspace@0__:h", "hdel|1:f"),
3033 ]
3034 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3035 );
3036 }
3037
3038 fn watching_clock() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3044 let (mut r, sub, mut batch) = timed();
3045 let writer = r.engine_mut().accept();
3046 r.engine_mut().feed(
3047 writer,
3048 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3049 );
3050 r.engine_mut()
3051 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3052 pump(&mut r, &mut batch);
3053 r.engine_mut().sink_mut().clear();
3054 (r, sub, writer, batch)
3055 }
3056
3057 #[test]
3061 fn a_deadline_that_passed_is_news_when_a_reader_finds_it() {
3062 let (mut r, sub, writer, mut batch) = watching_clock();
3063
3064 r.engine_mut()
3065 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3066 pump(&mut r, &mut batch);
3067 r.engine_mut().sink_mut().clear();
3068
3069 r.engine().server().advance_clock_ms(50);
3070 r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
3071 pump(&mut r, &mut batch);
3072 assert_eq!(
3073 fired(&r, sub),
3074 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned())),
3075 "and not a del alongside it, which is a different piece of news"
3076 );
3077 }
3078
3079 #[test]
3087 fn a_deadline_that_passed_is_news_with_nobody_reading() {
3088 let (mut r, sub, writer, mut batch) = watching_clock();
3089
3090 r.engine_mut()
3091 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3092 pump(&mut r, &mut batch);
3093 r.engine_mut().sink_mut().clear();
3094
3095 r.engine().server().advance_clock_ms(50);
3096 pump(&mut r, &mut batch);
3098 assert_eq!(
3099 fired(&r, sub),
3100 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3101 );
3102
3103 r.engine_mut().sink_mut().clear();
3104 pump(&mut r, &mut batch);
3105 assert!(fired(&r, sub).is_empty(), "and it only goes once");
3106 }
3107
3108 #[test]
3112 fn a_key_a_limit_took_says_it_was_evicted() {
3113 let (mut r, sub, writer, mut batch) = watching();
3114
3115 let val = vec![b'v'; 256];
3116 for i in 0..2000u32 {
3117 let k = format!("key:{i:08}");
3118 r.engine_mut()
3119 .feed(writer, &wire(&[b"SET", k.as_bytes(), &val]));
3120 }
3121 pump(&mut r, &mut batch);
3122 r.engine().server().refresh_memory();
3123 let full = r.engine().server().memory_bytes();
3124 r.engine_mut().sink_mut().clear();
3125
3126 let limit = (full / 2).to_string();
3129 r.engine_mut().feed(
3130 writer,
3131 &wire(&[b"CONFIG", b"SET", b"maxmemory-policy", b"allkeys-random"]),
3132 );
3133 r.engine_mut().feed(
3134 writer,
3135 &wire(&[b"CONFIG", b"SET", b"maxmemory", limit.as_bytes()]),
3136 );
3137 r.engine_mut()
3138 .feed(writer, &wire(&[b"SET", b"newcomer", &val]));
3139 pump(&mut r, &mut batch);
3140
3141 let events = fired(&r, sub);
3142 assert!(
3143 events.iter().any(|(e, _)| e == "evicted"),
3144 "the write made room and never said so: {events:?}"
3145 );
3146 assert!(
3147 events
3148 .iter()
3149 .all(|(e, k)| e != "evicted" || k != "newcomer"),
3150 "the key the write was for is the one key it cannot have taken"
3151 );
3152 }
3153
3154 #[test]
3157 fn a_transaction_publishes_between_its_commands_and_not_after_them() {
3158 let (mut r, sub, mut batch) = engine();
3159 let writer = r.engine_mut().accept();
3160
3161 r.engine_mut().feed(
3162 writer,
3163 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3164 );
3165 r.engine_mut()
3166 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3167 pump(&mut r, &mut batch);
3168 r.engine_mut().sink_mut().clear();
3169
3170 r.engine_mut().feed(writer, &wire(&[b"MULTI"]));
3171 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3172 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
3173 r.engine_mut().feed(writer, &wire(&[b"EXEC"]));
3174 pump(&mut r, &mut batch);
3175 assert_eq!(
3176 r.engine().sink().sent(sub),
3177 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3178 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
3179 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3180 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
3181 );
3182 }
3183
3184 #[test]
3185 fn a_reply_the_socket_would_not_take_is_offered_again() {
3186 let mut r = Reactor::inline(Wire::new(Trickle::default()));
3187 let conn = r.engine_mut().accept();
3188 let mut batch = Vec::new();
3189
3190 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3191 pump(&mut r, &mut batch);
3192 assert_eq!(r.engine().sink().sent, b"+PONG\r\n");
3194 assert_eq!(r.engine().sink().writes, 2);
3195 }
3196}