1use std::sync::Arc;
75
76use yo_reactor::{BATCH_MAX, Engine, Reactor};
77
78use crate::dispatch::table;
79use crate::dispatch::{self, Flow, Parked, Reply, 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 held: Vec<(ConnId, u64)>,
201}
202
203impl<S: Sink> Wire<S> {
204 #[must_use]
206 pub fn new(sink: S) -> Wire<S> {
207 Wire::with_server(Server::new(), sink)
208 }
209
210 #[must_use]
213 pub fn with_server(server: Server, sink: S) -> Wire<S> {
214 Wire::over(Arc::new(server), sink)
215 }
216
217 #[must_use]
226 pub fn over(server: Arc<Server>, sink: S) -> Wire<S> {
227 Wire {
228 front: Front::new(sink),
229 parked: Vec::new(),
230 post: Vec::new(),
231 held: Vec::new(),
232 server,
233 }
234 }
235
236 #[must_use]
238 pub fn server(&self) -> &Server {
239 &self.server
240 }
241
242 #[must_use]
245 pub fn shared(&self) -> Arc<Server> {
246 Arc::clone(&self.server)
247 }
248
249 pub fn server_mut(&mut self) -> &mut Server {
264 Arc::get_mut(&mut self.server)
265 .expect("the server is set up before the threads that share it are started")
266 }
267
268 #[must_use]
270 pub const fn sink(&self) -> &S {
271 self.front.sink()
272 }
273
274 pub const fn sink_mut(&mut self) -> &mut S {
276 self.front.sink_mut()
277 }
278
279 pub fn set_limits(&mut self, limits: Limits) {
281 self.front.set_limits(limits);
282 }
283
284 pub fn accept(&mut self) -> ConnId {
286 self.server.counted().opened();
287 let at = self.front.open(self.server.next_client());
288 let now = self.server.now_ms();
289 let guarded = self.server.guarded();
294 let row = if let Some(session) = self.front.session_mut(at) {
295 session.opened(now);
296 session.admit(!guarded);
297 Some(session.row().clone())
298 } else {
299 None
300 };
301 if let Some(row) = row {
306 self.server.register_client(&row);
307 }
308 self.note_buffers();
309 at
310 }
311
312 pub fn accept_from(&mut self, peer: &str, local: &str, fd: i32, unix: bool) -> ConnId {
320 let at = self.accept();
321 if let Some(session) = self.front.session_mut(at) {
322 session.set_socket(peer, local, fd, unix);
323 }
324 at
325 }
326
327 fn note_buffers(&mut self) {
332 let delta = self.front.buffer_delta();
333 if delta != 0 {
334 self.server.note_conn_bytes(delta);
335 }
336 }
337
338 pub fn hangup(&mut self, conn: ConnId) {
344 if !self.front.live(conn) {
345 return;
346 }
347 self.front.mark_gone(conn);
348 if self.front.blocked(conn) {
353 self.front.unpark(conn);
354 }
355 if self.front.pending(conn) == 0 {
356 self.release(conn);
357 }
358 self.note_buffers();
359 }
360
361 fn serve_waiters(&mut self) {
374 let now = self.server.now_ms();
375 let mine = self.server.my_slot();
376 self.server.waiters().mine(mine, &mut self.parked);
377 for at in 0..self.parked.len() {
378 let p = self.parked[at];
379 if !self.front.answers(p.conn, p.client) {
384 self.server.forget_waiters(p.client);
385 continue;
386 }
387 let served = {
391 let Wire { server, front, .. } = self;
392 server.serve_waiter(p.client, now, front.out(p.conn))
393 };
394 if served {
395 self.server.forget_waiters(p.client);
396 self.front.unpark(p.conn);
397 self.front.soil(p.conn);
398 }
399 }
400 self.parked.clear();
401 }
402
403 fn deliver(&mut self) {
412 let mut post = core::mem::take(&mut self.post);
415 self.server.take_mail(&mut post);
416 for env in post.drain(..) {
417 let conn = env.conn();
418 if !self.front.answers(conn, env.client()) {
419 continue;
420 }
421 env.write(self.front.out(conn));
422 self.front.soil(conn);
423 }
424 self.post = post;
425 }
426
427 #[must_use]
429 pub fn clients(&self) -> usize {
430 self.front.clients()
431 }
432
433 #[must_use]
435 pub fn ready(&self) -> usize {
436 self.front.ready()
437 }
438
439 #[must_use]
445 pub fn owed(&self) -> usize {
446 self.front.owed()
447 }
448
449 #[must_use]
460 pub fn waiting(&self) -> usize {
461 self.server.parked_here() + self.held.len()
462 }
463
464 #[must_use]
473 pub fn posted(&self) -> usize {
474 self.server.posted()
475 }
476
477 #[must_use]
484 pub fn stopping(&self) -> bool {
485 self.server.stopping()
486 }
487
488 #[must_use]
490 pub fn decoders(&self) -> usize {
491 self.front.decoders()
492 }
493
494 #[must_use]
496 pub fn buffer_bytes(&self) -> usize {
497 self.front.buffer_bytes()
498 }
499
500 pub fn feed(&mut self, conn: ConnId, bytes: &[u8]) {
506 self.front.feed(conn, bytes);
507 self.note_buffers();
508 }
509
510 fn release(&mut self, conn: ConnId) {
512 if let Some(session) = self.front.session_mut(conn) {
516 dispatch::forget_session(&self.server, session);
517 }
518 let Some(client) = self.front.close(conn) else {
519 return;
520 };
521 self.forget(client);
522 }
523
524 fn forget(&mut self, client: u64) {
531 self.server.forget_waiters(client);
532 self.server.forget_client(client);
533 self.server.counted().closed();
534 }
535
536 fn resume(&mut self) {
550 let mut held = core::mem::take(&mut self.held);
553 for &(conn, client) in &held {
554 if self.front.answers(conn, client) && self.front.blocked(conn) {
559 self.front.unpark(conn);
560 }
561 }
562 held.clear();
563 self.held = held;
564 }
565
566 fn reap(&mut self) {
567 for (conn, client) in self.server.my_kills() {
568 self.server.kill_done();
569 if self.front.answers(conn, client) {
570 self.hangup(conn);
571 }
572 }
573 }
574
575 pub fn take_ready(&mut self, into: &mut Vec<Cmd>, max: usize) -> usize {
580 self.front.take_ready(into, max)
581 }
582
583 pub fn tick(&mut self) {
589 self.server.refresh_clock();
590 }
591
592 pub fn maintain(&mut self) -> Option<usize> {
610 if !self.server.cron_running() {
616 return None;
617 }
618 self.server.refresh_memory();
624 self.server.backup_expire();
628 self.server.expire_slice(SWEEP_LOOKS);
633 self.server.compact_step()
634 }
635}
636
637impl<S: Sink> Engine for Wire<S> {
638 type Work = Cmd;
639
640 fn key_hash(&self, cmd: &Cmd) -> Option<u64> {
641 let spec = table::at(cmd.spec)?;
646 if spec.first_key <= 0 {
647 return None;
648 }
649 let args = self.front.args(cmd);
650 let key = args.opt(spec.first_key as usize)?;
655 Some(Keyspace::hash_of(key))
656 }
657
658 fn prefetch(&self, cmd: &Cmd, hash: u64) {
659 let db = self.front.db(cmd.conn());
660 self.server.striped_ref(db).prefetch_hashed(hash);
665 }
666
667 fn run(&mut self, cmd: Cmd, _hash: Option<u64>) -> yo_reactor::Flow {
668 let conn = cmd.conn();
669 if self.front.blocked(conn) {
674 self.front.park(conn, cmd);
675 return yo_reactor::Flow::Next;
676 }
677
678 let flow = if self.front.start(&cmd) {
682 let Wire { front, server, .. } = self;
683 let (args, session, out) = front.parts(&cmd);
684 let spec = table::at(cmd.spec);
685 let mark = out.len();
686 let flow = dispatch::resolved(server, session, spec, args, out);
687 if flow != Flow::Hold {
692 session.finished();
699 session.note_proto(out.proto().version());
700 let mode = session.reply_mode();
701 session.step_reply();
702 if mode != Reply::On {
703 out.truncate(mark);
704 }
705 }
706 flow
707 } else {
708 Flow::Continue
712 };
713
714 if flow == Flow::Hold {
721 self.front.hold(conn, cmd);
722 let client = self.front.client(conn);
723 yo_alloc::allow(|| self.held.push((conn, client)));
724 return yo_reactor::Flow::Next;
725 }
726
727 self.front.done(&cmd);
728 if self.front.gone(conn) {
729 if self.front.pending(conn) == 0 {
730 self.release(conn);
731 }
732 } else {
733 match flow {
734 Flow::Close => {
735 self.front.quit(conn);
736 self.front.soil(conn);
737 }
738 Flow::Block => {
743 self.front.block(conn);
744 let client = self.front.client(conn);
745 self.server.bind_waiter(client, conn);
746 }
747 Flow::Hold => {}
750 Flow::Continue => self.front.soil(conn),
751 }
752 }
753
754 if self.server.parked_here() != 0 {
759 self.serve_waiters();
760 }
761 yo_reactor::Flow::Next
762 }
763
764 fn flush(&mut self) {
765 if self.server.parked_here() != 0 {
776 self.server.refresh_clock();
777 self.serve_waiters();
778 }
779
780 if !self.held.is_empty() {
786 self.server.refresh_clock();
787 if self.server.paused(self.server.now_ms()).is_none() {
788 self.resume();
789 }
790 }
791
792 if self.server.kills() != 0 {
797 self.reap();
798 }
799
800 if self.server.mail_here() != 0 {
805 self.deliver();
806 }
807
808 let mut dirty = self.front.take_dirty();
812 let mut at = 0;
813 while at < dirty.len() {
814 let conn = dirty[at];
815 match self.front.write_out(conn) {
816 Wrote::Owed => at += 1,
820 Wrote::Done => {
821 dirty.swap_remove(at);
822 }
823 Wrote::Ended(client) => {
824 self.forget(client);
825 dirty.swap_remove(at);
826 }
827 }
828 }
829 self.front.give_dirty(dirty);
830 self.note_buffers();
831 }
832
833 fn maintain(&mut self, budget: &mut yo_reactor::Budget) {
834 if !budget.spend(1) {
837 return;
838 }
839 self.tick();
840 let looks = budget.left() as usize;
846 let spent = self.server.expire_slice(looks);
847 budget.spend(u32::try_from(spent).unwrap_or(u32::MAX));
848 }
849}
850
851pub fn pump<S: Sink>(reactor: &mut Reactor<Wire<S>>, batch: &mut Vec<Cmd>) -> usize {
858 let mut ran = 0;
859 reactor.engine_mut().tick();
860 loop {
866 loop {
867 batch.clear();
868 if reactor.engine_mut().take_ready(batch, BATCH_MAX) == 0 {
869 break;
870 }
871 let armed = yo_alloc::guard();
881 ran += reactor.execute_all(batch.drain(..));
882 drop(armed);
883 reactor.engine_mut().flush();
884 reactor.engine_mut().maintain();
887 }
888 reactor.engine_mut().maintain();
891 reactor.engine_mut().flush();
899 if reactor.engine().ready() == 0 {
900 break;
901 }
902 }
903 ran
904}
905
906#[cfg(test)]
907mod tests {
908 use super::*;
909
910 fn wire(args: &[&[u8]]) -> Vec<u8> {
912 let mut b = format!("*{}\r\n", args.len()).into_bytes();
913 for a in args {
914 b.extend_from_slice(format!("${}\r\n", a.len()).as_bytes());
915 b.extend_from_slice(a);
916 b.extend_from_slice(b"\r\n");
917 }
918 b
919 }
920
921 fn engine() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
922 let mut r = Reactor::inline(Wire::new(Recorder::new()));
923 let conn = r.engine_mut().accept();
924 (r, conn, Vec::new())
925 }
926
927 const START_MS: u64 = 1_000_000;
929
930 fn timed() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
936 let server = crate::dispatch::Server::with_clock(yo_kv::Clock::fixed(START_MS));
937 let mut r = Reactor::inline(Wire::with_server(server, Recorder::new()));
938 let conn = r.engine_mut().accept();
939 (r, conn, Vec::new())
940 }
941
942 #[test]
943 fn a_pipelined_batch_comes_back_in_order_and_in_one_write() {
944 let (mut r, conn, mut batch) = engine();
945 let mut stream = wire(&[b"SET", b"k", b"v"]);
946 stream.extend(wire(&[b"GET", b"k"]));
947 stream.extend(wire(&[b"INCR", b"n"]));
948
949 r.engine_mut().feed(conn, &stream);
950 assert_eq!(r.engine().ready(), 3);
951 assert_eq!(pump(&mut r, &mut batch), 3);
952
953 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$1\r\nv\r\n:1\r\n");
954 assert_eq!(r.engine().ready(), 0);
955 }
956
957 #[test]
960 fn a_command_split_across_reads_resumes_rather_than_restarts() {
961 let (mut r, conn, mut batch) = engine();
962 let bytes = wire(&[b"SET", b"key", b"value"]);
963
964 for at in 1..bytes.len() {
965 r.engine_mut().feed(conn, &bytes[at - 1..at]);
966 assert_eq!(r.engine().ready(), 0, "not a command yet at {at}");
967 }
968 r.engine_mut().feed(conn, &bytes[bytes.len() - 1..]);
969 assert_eq!(r.engine().ready(), 1);
970 assert_eq!(pump(&mut r, &mut batch), 1);
971 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
972
973 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
976 pump(&mut r, &mut batch);
977 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$5\r\nvalue\r\n");
978 }
979
980 #[test]
981 fn two_connections_are_two_sessions_over_one_server() {
982 let (mut r, a, mut batch) = engine();
983 let b = r.engine_mut().accept();
984
985 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
986 r.engine_mut().feed(a, &wire(&[b"SET", b"k", b"a"]));
987 r.engine_mut().feed(b, &wire(&[b"SET", b"k", b"b"]));
988 r.engine_mut().feed(a, &wire(&[b"GET", b"k"]));
989 r.engine_mut().feed(b, &wire(&[b"GET", b"k"]));
990 pump(&mut r, &mut batch);
991
992 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n+OK\r\n$1\r\na\r\n");
993 assert_eq!(r.engine().sink().sent(b), b"+OK\r\n$1\r\nb\r\n");
994 assert_eq!(r.engine().clients(), 2);
995 }
996
997 #[test]
1009 fn two_threads_write_into_one_server() {
1010 const EACH: usize = 200;
1011
1012 let mut server = Server::new();
1013 server.set_threads(2);
1014 let first = Wire::with_server(server, Recorder::new());
1015 let second = Wire::over(first.shared(), Recorder::new());
1016 let server = first.shared();
1017
1018 std::thread::scope(|s| {
1019 for (at, engine) in [first, second].into_iter().enumerate() {
1020 s.spawn(move || {
1021 let mut r = Reactor::inline(engine);
1022 let mut batch = Vec::new();
1023 let conn = r.engine_mut().accept();
1024 for i in 0..EACH {
1025 let key = format!("t{at}:{i}");
1026 r.engine_mut()
1027 .feed(conn, &wire(&[b"SET", key.as_bytes(), b"v"]));
1028 pump(&mut r, &mut batch);
1029 }
1030 });
1031 }
1032 });
1033
1034 assert_eq!(server.striped_ref(0).len(), 2 * EACH);
1037 assert_eq!(server.totals().connections, 2);
1040 }
1041
1042 #[test]
1045 fn a_waiter_belongs_to_the_thread_that_parked_it() {
1046 let mut server = Server::new();
1047 server.set_threads(2);
1048 let first = Wire::with_server(server, Recorder::new());
1049 let second = Wire::over(first.shared(), Recorder::new());
1050 let server = first.shared();
1051
1052 let parked = std::sync::Barrier::new(2);
1053 let swept = std::sync::Barrier::new(2);
1054
1055 std::thread::scope(|s| {
1056 let (parked, swept) = (&parked, &swept);
1057 s.spawn(move || {
1058 let mut r = Reactor::inline(first);
1059 let mut batch = Vec::new();
1060 let conn = r.engine_mut().accept();
1061 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
1062 pump(&mut r, &mut batch);
1063 parked.wait();
1064
1065 for _ in 0..50 {
1068 pump(&mut r, &mut batch);
1069 }
1070 swept.wait();
1071 assert!(r.engine().sink().sent(conn).is_empty(), "nothing to say");
1072 });
1073 s.spawn(move || {
1074 let mut r = Reactor::inline(second);
1075 let mut batch = Vec::new();
1076 let conn = r.engine_mut().accept();
1077 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"b", b"0"]));
1078 pump(&mut r, &mut batch);
1079 parked.wait();
1080 swept.wait();
1081
1082 let pusher = r.engine_mut().accept();
1085 r.engine_mut().feed(pusher, &wire(&[b"RPUSH", b"b", b"v"]));
1086 pump(&mut r, &mut batch);
1087 assert_eq!(
1088 r.engine().sink().sent(conn),
1089 b"*2\r\n$1\r\nb\r\n$1\r\nv\r\n",
1090 "served by the thread that parked it"
1091 );
1092 });
1093 });
1094
1095 assert_eq!(server.parked(), 1, "and the other one is still waiting");
1096 }
1097
1098 #[test]
1104 fn a_thread_counts_the_clients_it_blocked_and_nobody_else_s() {
1105 let mut server = Server::new();
1106 server.set_threads(2);
1107 let first = Wire::with_server(server, Recorder::new());
1108 let second = Wire::over(first.shared(), Recorder::new());
1109 let server = first.shared();
1110
1111 let parked = std::sync::Barrier::new(2);
1112 let looked = std::sync::Barrier::new(2);
1113
1114 std::thread::scope(|s| {
1115 let (parked, looked) = (&parked, &looked);
1116 s.spawn(move || {
1117 let mut r = Reactor::inline(first);
1118 let mut batch = Vec::new();
1119 let conn = r.engine_mut().accept();
1120 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
1121 pump(&mut r, &mut batch);
1122 assert_eq!(r.engine().waiting(), 1, "the one this thread blocked");
1123 parked.wait();
1124 looked.wait();
1125
1126 let other = r.engine_mut().accept();
1130 r.engine_mut().feed(other, &wire(&[b"PING"]));
1131 pump(&mut r, &mut batch);
1132 r.engine_mut().hangup(other);
1133 pump(&mut r, &mut batch);
1134 assert_eq!(r.engine().waiting(), 1, "still just the blocked one");
1135 });
1136 s.spawn(move || {
1137 let mut r = Reactor::inline(second);
1138 let mut batch = Vec::new();
1139 parked.wait();
1140
1141 pump(&mut r, &mut batch);
1144 assert_eq!(r.engine().waiting(), 0, "none of them are this one's");
1145 assert_eq!(r.engine().server().parked(), 1, "one on the server");
1146 looked.wait();
1147 });
1148 });
1149
1150 assert_eq!(server.parked(), 1);
1151 }
1152
1153 #[test]
1156 fn client_ids_are_the_server_s_to_hand_out() {
1157 let first = Wire::new(Recorder::new());
1158 let second = Wire::over(first.shared(), Recorder::new());
1159 let mut a = Reactor::inline(first);
1160 let mut b = Reactor::inline(second);
1161
1162 let (one, two) = (a.engine_mut().accept(), b.engine_mut().accept());
1163 assert_eq!(one, two, "the same slot on each front");
1164
1165 let mut batch = Vec::new();
1170 a.engine_mut().feed(one, &wire(&[b"HELLO", b"3"]));
1171 b.engine_mut().feed(two, &wire(&[b"HELLO", b"3"]));
1172 pump(&mut a, &mut batch);
1173 pump(&mut b, &mut batch);
1174
1175 let first = String::from_utf8_lossy(a.engine().sink().sent(one)).into_owned();
1176 let second = String::from_utf8_lossy(b.engine().sink().sent(two)).into_owned();
1177 assert!(first.contains(":1\r\n"), "{first}");
1178 assert!(second.contains(":2\r\n"), "{second}");
1179 }
1180
1181 #[test]
1182 fn quit_is_answered_and_then_the_connection_goes() {
1183 let (mut r, conn, mut batch) = engine();
1184 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1185 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1186 pump(&mut r, &mut batch);
1187
1188 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1189 assert!(r.engine().sink().was_closed(conn));
1190 assert_eq!(r.engine().clients(), 0);
1191
1192 let again = r.engine_mut().accept();
1194 assert_eq!(again, conn);
1195 assert_eq!(r.engine().clients(), 1);
1196 }
1197
1198 #[test]
1201 fn what_a_client_pipelined_behind_quit_is_never_run() {
1202 let (mut r, conn, mut batch) = engine();
1203 let mut stream = wire(&[b"QUIT"]);
1204 stream.extend(wire(&[b"SET", b"foo", b"bar"]));
1205 r.engine_mut().feed(conn, &stream);
1206 assert_eq!(r.engine().ready(), 2);
1208 pump(&mut r, &mut batch);
1209
1210 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
1212 assert!(r.engine().sink().was_closed(conn));
1213
1214 r.engine_mut().sink_mut().clear();
1219 let next = r.engine_mut().accept();
1220 r.engine_mut().feed(next, &wire(&[b"GET", b"foo"]));
1221 pump(&mut r, &mut batch);
1222 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1223 }
1224
1225 #[test]
1235 fn a_slot_that_last_spoke_resp3_answers_the_next_client_in_resp2() {
1236 let (mut r, conn, mut batch) = engine();
1237 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1238 r.engine_mut().feed(conn, &wire(&[b"GET", b"nothing"]));
1239 pump(&mut r, &mut batch);
1240 assert!(r.engine().sink().sent(conn).ends_with(b"_\r\n"));
1241 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1242 pump(&mut r, &mut batch);
1243
1244 r.engine_mut().sink_mut().clear();
1245 let next = r.engine_mut().accept();
1246 assert_eq!(next, conn, "the same slot, which is what this is about");
1247 r.engine_mut().feed(next, &wire(&[b"GET", b"nothing"]));
1248 pump(&mut r, &mut batch);
1249 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1250 }
1251
1252 #[test]
1254 fn commands_that_arrived_before_a_protocol_error_are_still_answered() {
1255 let (mut r, conn, mut batch) = engine();
1256 let mut stream = wire(&[b"SET", b"k", b"v"]);
1257 stream.extend(wire(&[b"GET", b"k"]));
1258 stream.extend_from_slice(b"*1\r\n+notabulk\r\n");
1259 r.engine_mut().feed(conn, &stream);
1260 pump(&mut r, &mut batch);
1261
1262 let sent = r.engine().sink().sent(conn);
1265 assert!(
1266 sent.starts_with(b"+OK\r\n$1\r\nv\r\n-ERR Protocol error: "),
1267 "{sent:?}"
1268 );
1269 assert!(r.engine().sink().was_closed(conn));
1270 }
1271
1272 #[test]
1273 fn a_protocol_error_is_written_and_closes_the_connection() {
1274 let (mut r, conn, mut batch) = engine();
1275 r.engine_mut().feed(conn, b"*1\r\n+notabulk\r\n");
1277 pump(&mut r, &mut batch);
1278
1279 let sent = r.engine().sink().sent(conn);
1280 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1281 assert!(r.engine().sink().was_closed(conn));
1282 assert_eq!(r.engine().clients(), 0);
1283 }
1284
1285 #[test]
1289 fn a_decoder_that_came_back_mid_command_starts_the_next_one_clean() {
1290 let (mut r, conn, mut batch) = engine();
1291 r.engine_mut()
1293 .feed(conn, b"*3\r\n$3\r\nSET\r\n$1\r\nx\r\n$blabla\r\n");
1294 pump(&mut r, &mut batch);
1295 let sent = r.engine().sink().sent(conn);
1296 assert!(
1297 sent.starts_with(b"-ERR Protocol error: invalid bulk length"),
1298 "{sent:?}"
1299 );
1300
1301 r.engine_mut().sink_mut().clear();
1305 let next = r.engine_mut().accept();
1306 r.engine_mut().feed(next, &wire(&[b"GET", b"k"]));
1307 pump(&mut r, &mut batch);
1308 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1309
1310 r.engine_mut().sink_mut().clear();
1311 let third = r.engine_mut().accept();
1312 r.engine_mut().feed(third, b"*1\r\n+notabulk\r\n");
1313 pump(&mut r, &mut batch);
1314 let sent = r.engine().sink().sent(third);
1315 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1316 }
1317
1318 #[test]
1321 fn a_hangup_with_commands_in_flight_waits_for_them() {
1322 let (mut r, conn, mut batch) = engine();
1323 r.engine_mut().feed(conn, &wire(&[b"SET", b"k", b"v"]));
1324 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1325
1326 batch.clear();
1327 r.engine_mut().take_ready(&mut batch, BATCH_MAX);
1328 r.engine_mut().hangup(conn);
1329 assert_eq!(r.engine().clients(), 1, "still holding the buffer");
1330
1331 r.execute_all(batch.drain(..));
1332 r.engine_mut().flush();
1333 assert_eq!(r.engine().clients(), 0);
1334 assert!(r.engine().sink().sent(conn).is_empty(), "nobody to answer");
1335
1336 let decoders = r.engine().decoders();
1339 let again = r.engine_mut().accept();
1340 assert_eq!(again, conn);
1341 r.engine_mut().feed(again, &wire(&[b"PING"]));
1342 pump(&mut r, &mut batch);
1343 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1344 assert_eq!(r.engine().decoders(), decoders);
1345 }
1346
1347 #[test]
1350 fn the_buffers_and_the_decoder_pool_stop_growing() {
1351 let (mut r, conn, mut batch) = engine();
1352 let mut stream = Vec::new();
1353 for i in 0..32 {
1354 stream.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1355 }
1356
1357 r.engine_mut().feed(conn, &stream);
1358 pump(&mut r, &mut batch);
1359 let decoders = r.engine().decoders();
1360 let batch_cap = batch.capacity();
1361
1362 for _ in 0..10 {
1363 r.engine_mut().feed(conn, &stream);
1364 pump(&mut r, &mut batch);
1365 }
1366 assert_eq!(r.engine().decoders(), decoders, "the pool is reused");
1367 assert_eq!(batch.capacity(), batch_cap, "the batch buffer is reused");
1368 assert!(
1369 decoders <= BATCH_MAX + 1,
1370 "{decoders} decoders for 32 commands"
1371 );
1372 }
1373
1374 #[test]
1383 fn a_pipelining_client_does_not_grow_the_read_buffer() {
1384 let (mut r, conn, mut batch) = engine();
1385 let mut round = Vec::new();
1386 for i in 0..16 {
1387 round.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1388 }
1389
1390 r.engine_mut().feed(conn, &round);
1391 pump(&mut r, &mut batch);
1392 r.engine_mut().sink_mut().clear();
1393 let after_one = r.engine().buffer_bytes();
1394
1395 let rounds = if cfg!(miri) { 50 } else { 1000 };
1404 for _ in 0..rounds {
1405 r.engine_mut().feed(conn, &round);
1406 pump(&mut r, &mut batch);
1407 r.engine_mut().sink_mut().clear();
1408 }
1409
1410 assert_eq!(
1411 r.engine().buffer_bytes(),
1412 after_one,
1413 "the buffers grew over {rounds} rounds of the same sixteen commands"
1414 );
1415 assert!(
1416 r.engine().server().memory_bytes() >= after_one,
1417 "the buffers are counted in what the server reports"
1418 );
1419 }
1420
1421 #[test]
1424 fn a_command_split_across_reads_survives_compaction() {
1425 let (mut r, conn, mut batch) = engine();
1426 let cmd = wire(&[b"SET", b"key", b"value"]);
1427 let (head, tail) = cmd.split_at(cmd.len() - 4);
1428
1429 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1432 r.engine_mut().feed(conn, head);
1433 pump(&mut r, &mut batch);
1434 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n");
1435
1436 r.engine_mut().feed(conn, tail);
1438 pump(&mut r, &mut batch);
1439 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1440
1441 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
1442 pump(&mut r, &mut batch);
1443 assert!(r.engine().sink().sent(conn).ends_with(b"$5\r\nvalue\r\n"));
1444 }
1445
1446 #[test]
1449 fn the_batch_goes_through_the_reactors_two_walks() {
1450 let (mut r, conn, mut batch) = engine();
1451 for i in 0..100 {
1452 r.engine_mut()
1453 .feed(conn, &wire(&[b"INCR", format!("k{}", i % 7).as_bytes()]));
1454 }
1455 let ran = pump(&mut r, &mut batch);
1456
1457 assert_eq!(ran, 100);
1458 assert_eq!(r.commands(), 100);
1459 assert_eq!(r.turns(), 2);
1461 assert!(r.engine().sink().sent(conn).ends_with(b":15\r\n"));
1463 }
1464
1465 #[derive(Default)]
1468 struct Trickle {
1469 sent: Vec<u8>,
1470 writes: usize,
1471 }
1472
1473 impl Sink for Trickle {
1474 fn write(&mut self, _conn: ConnId, bytes: &[u8]) -> usize {
1475 self.writes += 1;
1476 let n = bytes.len().min(4);
1477 self.sent.extend_from_slice(&bytes[..n]);
1478 n
1479 }
1480 }
1481
1482 #[test]
1485 fn a_blpop_on_a_list_with_something_in_it_never_waits() {
1486 let (mut r, conn, mut batch) = engine();
1487 r.engine_mut().feed(conn, &wire(&[b"RPUSH", b"q", b"a"]));
1488 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"0"]));
1489 pump(&mut r, &mut batch);
1490
1491 assert_eq!(
1492 r.engine().sink().sent(conn),
1493 b":1\r\n*2\r\n$1\r\nq\r\n$1\r\na\r\n"
1494 );
1495 assert_eq!(r.engine().server().parked(), 0);
1496 }
1497
1498 #[test]
1501 fn a_parked_client_is_answered_by_another_connections_push() {
1502 let (mut r, a, mut batch) = engine();
1503 let b = r.engine_mut().accept();
1504
1505 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1506 pump(&mut r, &mut batch);
1507 assert!(r.engine().sink().sent(a).is_empty(), "nothing to say yet");
1508 assert_eq!(r.engine().server().parked(), 1);
1509
1510 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"one"]));
1511 pump(&mut r, &mut batch);
1512
1513 assert_eq!(r.engine().sink().sent(a), b"*2\r\n$1\r\nq\r\n$3\r\none\r\n");
1514 assert_eq!(r.engine().sink().sent(b), b":1\r\n");
1517 assert_eq!(r.engine().server().parked(), 0);
1518 }
1519
1520 #[test]
1523 fn only_a_list_arriving_under_a_named_key_wakes_a_waiter() {
1524 let (mut r, a, mut batch) = engine();
1525 let b = r.engine_mut().accept();
1526 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1527 pump(&mut r, &mut batch);
1528
1529 r.engine_mut()
1530 .feed(b, &wire(&[b"RPUSH", b"elsewhere", b"x"]));
1531 r.engine_mut().feed(b, &wire(&[b"SADD", b"q", b"x"]));
1532 pump(&mut r, &mut batch);
1533
1534 assert!(r.engine().sink().sent(a).is_empty());
1535 assert_eq!(r.engine().server().parked(), 1, "still waiting");
1536 assert_eq!(r.engine().sink().sent(b), b":1\r\n:1\r\n");
1539 }
1540
1541 #[test]
1544 fn two_parked_clients_are_served_in_the_order_they_arrived() {
1545 let (mut r, a, mut batch) = engine();
1546 let b = r.engine_mut().accept();
1547 let c = r.engine_mut().accept();
1548
1549 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1550 pump(&mut r, &mut batch);
1551 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"q", b"0"]));
1552 pump(&mut r, &mut batch);
1553 assert_eq!(r.engine().server().parked(), 2);
1554
1555 r.engine_mut()
1556 .feed(c, &wire(&[b"RPUSH", b"q", b"first", b"second"]));
1557 pump(&mut r, &mut batch);
1558
1559 assert_eq!(
1560 r.engine().sink().sent(a),
1561 b"*2\r\n$1\r\nq\r\n$5\r\nfirst\r\n"
1562 );
1563 assert_eq!(
1564 r.engine().sink().sent(b),
1565 b"*2\r\n$1\r\nq\r\n$6\r\nsecond\r\n"
1566 );
1567 assert_eq!(r.engine().server().parked(), 0);
1568 }
1569
1570 #[test]
1573 fn what_a_client_pipelined_behind_a_block_waits_for_the_block() {
1574 let (mut r, a, mut batch) = engine();
1575 let b = r.engine_mut().accept();
1576
1577 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1580 stream.extend(wire(&[b"PING"]));
1581 r.engine_mut().feed(a, &stream);
1582 pump(&mut r, &mut batch);
1583 assert!(
1584 r.engine().sink().sent(a).is_empty(),
1585 "the PING went out in front of the answer it was sent behind"
1586 );
1587
1588 r.engine_mut().feed(a, &wire(&[b"ECHO", b"after"]));
1590 pump(&mut r, &mut batch);
1591 assert!(r.engine().sink().sent(a).is_empty());
1592
1593 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1594 pump(&mut r, &mut batch);
1595 assert_eq!(
1596 r.engine().sink().sent(a),
1597 b"*2\r\n$1\r\nq\r\n$1\r\nx\r\n+PONG\r\n$5\r\nafter\r\n"
1598 );
1599 }
1600
1601 #[test]
1606 fn a_waiter_is_served_between_two_pipelined_pushes() {
1607 let (mut r, a, mut batch) = engine();
1608 let b = r.engine_mut().accept();
1609 r.engine_mut()
1610 .feed(a, &wire(&[b"BLPOP", b"p1", b"p2", b"0"]));
1611 pump(&mut r, &mut batch);
1612
1613 let mut stream = wire(&[b"RPUSH", b"p2", b"second"]);
1614 stream.extend(wire(&[b"RPUSH", b"p1", b"first"]));
1615 r.engine_mut().feed(b, &stream);
1616 pump(&mut r, &mut batch);
1617
1618 assert_eq!(
1619 r.engine().sink().sent(a),
1620 b"*2\r\n$2\r\np2\r\n$6\r\nsecond\r\n"
1621 );
1622 r.engine_mut()
1624 .feed(b, &wire(&[b"LRANGE", b"p1", b"0", b"-1"]));
1625 pump(&mut r, &mut batch);
1626 assert!(
1627 r.engine()
1628 .sink()
1629 .sent(b)
1630 .ends_with(b"*1\r\n$5\r\nfirst\r\n")
1631 );
1632 }
1633
1634 #[test]
1638 fn a_waiter_woken_by_another_waiter() {
1639 let (mut r, a, mut batch) = engine();
1640 let b = r.engine_mut().accept();
1641 let c = r.engine_mut().accept();
1642
1643 r.engine_mut()
1644 .feed(a, &wire(&[b"BLMOVE", b"x", b"y", b"LEFT", b"RIGHT", b"0"]));
1645 pump(&mut r, &mut batch);
1646 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"y", b"0"]));
1647 pump(&mut r, &mut batch);
1648 assert_eq!(r.engine().server().parked(), 2);
1649
1650 r.engine_mut().feed(c, &wire(&[b"RPUSH", b"x", b"chain"]));
1651 pump(&mut r, &mut batch);
1652
1653 assert_eq!(r.engine().sink().sent(a), b"$5\r\nchain\r\n");
1654 assert_eq!(
1655 r.engine().sink().sent(b),
1656 b"*2\r\n$1\r\ny\r\n$5\r\nchain\r\n"
1657 );
1658 assert_eq!(r.engine().server().parked(), 0);
1659 }
1660
1661 #[test]
1664 fn a_waiter_is_only_woken_on_the_database_it_blocked_on() {
1665 let (mut r, a, mut batch) = engine();
1666 let b = r.engine_mut().accept();
1667 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
1668 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1669 pump(&mut r, &mut batch);
1670 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n");
1671
1672 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"wrongdb"]));
1673 pump(&mut r, &mut batch);
1674 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n", "still waiting");
1675
1676 r.engine_mut().feed(b, &wire(&[b"SELECT", b"3"]));
1677 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"rightdb"]));
1678 pump(&mut r, &mut batch);
1679 assert!(r.engine().sink().sent(a).ends_with(b"$7\r\nrightdb\r\n"));
1680 }
1681
1682 #[test]
1684 fn a_client_that_waited_long_enough_gets_a_null_array() {
1685 let (mut r, conn, mut batch) = timed();
1686 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"30"]));
1687 pump(&mut r, &mut batch);
1688 assert!(r.engine().sink().sent(conn).is_empty());
1689
1690 r.engine_mut().server_mut().set_clock_ms(START_MS + 29_999);
1691 pump(&mut r, &mut batch);
1692 assert!(
1693 r.engine().sink().sent(conn).is_empty(),
1694 "a millisecond short"
1695 );
1696
1697 r.engine_mut().server_mut().set_clock_ms(START_MS + 30_000);
1698 pump(&mut r, &mut batch);
1699 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n");
1701 assert_eq!(r.engine().server().parked(), 0);
1702 }
1703
1704 #[test]
1708 fn every_blocking_command_times_out_with_the_same_null_array() {
1709 for cmd in [
1710 &[b"BLPOP".as_slice(), b"q", b"0.001"][..],
1711 &[b"BRPOP", b"q", b"0.001"],
1712 &[b"BLMOVE", b"q", b"d", b"LEFT", b"RIGHT", b"0.001"],
1713 &[b"BRPOPLPUSH", b"q", b"d", b"0.001"],
1714 &[b"BLMPOP", b"0.001", b"1", b"q", b"LEFT"],
1715 ] {
1716 let (mut r, conn, mut batch) = timed();
1717 r.engine_mut().feed(conn, &wire(cmd));
1718 pump(&mut r, &mut batch);
1719 r.engine_mut().server_mut().set_clock_ms(START_MS + 1);
1720 pump(&mut r, &mut batch);
1721 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n", "for {cmd:?}");
1722 }
1723 }
1724
1725 #[test]
1728 fn a_waiter_that_timed_out_does_not_eat_a_later_push() {
1729 let (mut r, a, mut batch) = timed();
1730 let b = r.engine_mut().accept();
1731 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"1"]));
1732 pump(&mut r, &mut batch);
1733 r.engine_mut().server_mut().set_clock_ms(START_MS + 1000);
1734 pump(&mut r, &mut batch);
1735 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n");
1736
1737 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"late"]));
1738 r.engine_mut()
1739 .feed(b, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1740 pump(&mut r, &mut batch);
1741 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n", "nothing more");
1742 assert!(r.engine().sink().sent(b).ends_with(b"*1\r\n$4\r\nlate\r\n"));
1743 }
1744
1745 #[test]
1750 fn a_client_that_goes_away_while_it_waits_takes_its_waiter_with_it() {
1751 let (mut r, a, mut batch) = engine();
1752 let b = r.engine_mut().accept();
1753 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1754 pump(&mut r, &mut batch);
1755 assert_eq!(r.engine().server().parked(), 1);
1756
1757 r.engine_mut().hangup(a);
1758 pump(&mut r, &mut batch);
1759 assert_eq!(r.engine().server().parked(), 0);
1760 assert_eq!(r.engine().clients(), 1);
1761
1762 let again = r.engine_mut().accept();
1765 assert_eq!(again, a);
1766 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1767 r.engine_mut()
1768 .feed(again, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1769 pump(&mut r, &mut batch);
1770 assert_eq!(r.engine().sink().sent(again), b"*1\r\n$1\r\nx\r\n");
1771 }
1772
1773 #[test]
1777 fn a_hangup_while_parked_gives_back_the_slot_and_the_decoders() {
1778 let (mut r, a, mut batch) = engine();
1779 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1780 stream.extend(wire(&[b"PING"]));
1781 stream.extend(wire(&[b"PING"]));
1782 r.engine_mut().feed(a, &stream);
1783 pump(&mut r, &mut batch);
1784
1785 let decoders = r.engine().decoders();
1786 r.engine_mut().hangup(a);
1787 pump(&mut r, &mut batch);
1788
1789 assert_eq!(r.engine().clients(), 0);
1790 assert!(r.engine().sink().was_closed(a));
1791 assert_eq!(r.engine().decoders(), decoders, "the pool came back whole");
1792 let again = r.engine_mut().accept();
1793 assert_eq!(again, a);
1794 r.engine_mut().feed(again, &wire(&[b"PING"]));
1795 pump(&mut r, &mut batch);
1796 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1797 }
1798
1799 #[test]
1802 fn a_published_message_lands_on_the_subscriber() {
1803 let (mut r, sub, mut batch) = engine();
1804 let pubr = r.engine_mut().accept();
1805
1806 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1807 pump(&mut r, &mut batch);
1808 assert_eq!(
1809 r.engine().sink().sent(sub),
1810 b"*3\r\n$9\r\nsubscribe\r\n$4\r\nnews\r\n:1\r\n"
1811 );
1812 r.engine_mut().sink_mut().clear();
1813
1814 r.engine_mut()
1815 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1816 pump(&mut r, &mut batch);
1817 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1818 assert_eq!(
1819 r.engine().sink().sent(sub),
1820 b"*3\r\n$7\r\nmessage\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1821 );
1822 }
1823
1824 #[test]
1827 fn a_pattern_subscriber_is_told_the_pattern_and_the_channel() {
1828 let (mut r, sub, mut batch) = engine();
1829 let pubr = r.engine_mut().accept();
1830
1831 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"ne*"]));
1832 pump(&mut r, &mut batch);
1833 r.engine_mut().sink_mut().clear();
1834
1835 r.engine_mut()
1836 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1837 pump(&mut r, &mut batch);
1838 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1839 assert_eq!(
1840 r.engine().sink().sent(sub),
1841 b"*4\r\n$8\r\npmessage\r\n$3\r\nne*\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1842 );
1843 }
1844
1845 #[test]
1850 fn resp2_takes_almost_nothing_from_a_subscriber() {
1851 let (mut r, conn, mut batch) = engine();
1852
1853 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1854 pump(&mut r, &mut batch);
1855 r.engine_mut().sink_mut().clear();
1856
1857 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1858 pump(&mut r, &mut batch);
1859 assert_eq!(
1860 r.engine().sink().sent(conn),
1861 b"-ERR Can't execute 'get': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context\r\n"
1862 );
1863 r.engine_mut().sink_mut().clear();
1864
1865 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1867 pump(&mut r, &mut batch);
1868 assert_eq!(
1869 r.engine().sink().sent(conn),
1870 b"*2\r\n$4\r\npong\r\n$0\r\n\r\n"
1871 );
1872 r.engine_mut().sink_mut().clear();
1873
1874 r.engine_mut().feed(conn, &wire(&[b"UNSUBSCRIBE", b"a"]));
1876 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1877 pump(&mut r, &mut batch);
1878 assert_eq!(
1879 r.engine().sink().sent(conn),
1880 b"*3\r\n$11\r\nunsubscribe\r\n$1\r\na\r\n:0\r\n$-1\r\n"
1881 );
1882 }
1883
1884 #[test]
1888 fn a_shard_channel_and_a_pattern_do_not_hear_each_other() {
1889 let (mut r, sub, mut batch) = engine();
1890 let pubr = r.engine_mut().accept();
1891
1892 r.engine_mut().feed(sub, &wire(&[b"SSUBSCRIBE", b"sx"]));
1893 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"s*"]));
1894 pump(&mut r, &mut batch);
1895 r.engine_mut().sink_mut().clear();
1896
1897 r.engine_mut()
1898 .feed(pubr, &wire(&[b"SPUBLISH", b"sx", b"one"]));
1899 pump(&mut r, &mut batch);
1900 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1901 assert_eq!(
1902 r.engine().sink().sent(sub),
1903 b"*3\r\n$8\r\nsmessage\r\n$2\r\nsx\r\n$3\r\none\r\n"
1904 );
1905 r.engine_mut().sink_mut().clear();
1906
1907 r.engine_mut()
1908 .feed(pubr, &wire(&[b"PUBLISH", b"sx", b"two"]));
1909 pump(&mut r, &mut batch);
1910 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1911 assert_eq!(
1912 r.engine().sink().sent(sub),
1913 b"*4\r\n$8\r\npmessage\r\n$2\r\ns*\r\n$2\r\nsx\r\n$3\r\ntwo\r\n"
1914 );
1915 }
1916
1917 #[test]
1921 fn a_subscriber_that_goes_away_leaves_the_registry() {
1922 let (mut r, sub, mut batch) = engine();
1923 let pubr = r.engine_mut().accept();
1924
1925 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1926 pump(&mut r, &mut batch);
1927 r.engine_mut().hangup(sub);
1928 pump(&mut r, &mut batch);
1929 r.engine_mut().sink_mut().clear();
1930
1931 r.engine_mut()
1932 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1933 pump(&mut r, &mut batch);
1934 assert_eq!(r.engine().sink().sent(pubr), b":0\r\n");
1935
1936 let next = r.engine_mut().accept();
1938 assert_eq!(next, sub);
1939 r.engine_mut()
1940 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1941 pump(&mut r, &mut batch);
1942 assert_eq!(r.engine().sink().sent(next), b"");
1943 }
1944
1945 #[test]
1954 fn resp3_delivers_a_message_as_a_push() {
1955 let (mut r, conn, mut batch) = engine();
1956
1957 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1958 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1959 pump(&mut r, &mut batch);
1960 r.engine_mut().sink_mut().clear();
1961
1962 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1963 r.engine_mut().feed(conn, &wire(&[b"PUBLISH", b"a", b"w"]));
1964 pump(&mut r, &mut batch);
1965 assert_eq!(
1966 r.engine().sink().sent(conn),
1967 b"_\r\n:1\r\n>3\r\n$7\r\nmessage\r\n$1\r\na\r\n$1\r\nw\r\n"
1968 );
1969 }
1970
1971 #[test]
1974 fn a_write_reaches_a_keyspace_subscriber() {
1975 let (mut r, sub, mut batch) = engine();
1976 let writer = r.engine_mut().accept();
1977
1978 r.engine_mut().feed(
1979 writer,
1980 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"KEA"]),
1981 );
1982 r.engine_mut()
1983 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1984 pump(&mut r, &mut batch);
1985 r.engine_mut().sink_mut().clear();
1986
1987 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1988 pump(&mut r, &mut batch);
1989 assert_eq!(r.engine().sink().sent(writer), b"+OK\r\n");
1990 assert_eq!(
1991 r.engine().sink().sent(sub),
1992 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1993 $16\r\n__keyspace@0__:k\r\n$3\r\nset\r\n\
1994 *4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1995 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n"
1996 );
1997 }
1998
1999 #[test]
2002 fn a_write_says_nothing_until_the_setting_turns_it_on() {
2003 let (mut r, sub, mut batch) = engine();
2004 let writer = r.engine_mut().accept();
2005
2006 r.engine_mut()
2007 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
2008 pump(&mut r, &mut batch);
2009 r.engine_mut().sink_mut().clear();
2010
2011 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2012 pump(&mut r, &mut batch);
2013 assert_eq!(r.engine().sink().sent(sub), b"");
2014 }
2015
2016 #[test]
2019 fn only_the_classes_that_were_asked_for_are_published() {
2020 let (mut r, sub, mut batch) = engine();
2021 let writer = r.engine_mut().accept();
2022
2023 r.engine_mut().feed(
2024 writer,
2025 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"Eg"]),
2026 );
2027 r.engine_mut()
2028 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
2029 pump(&mut r, &mut batch);
2030 r.engine_mut().sink_mut().clear();
2031
2032 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2033 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
2034 pump(&mut r, &mut batch);
2035 assert_eq!(
2036 r.engine().sink().sent(sub),
2037 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
2038 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
2039 );
2040 }
2041
2042 #[test]
2045 fn a_write_with_a_deadline_on_it_says_two_things() {
2046 let (mut r, sub, mut batch) = engine();
2047 let writer = r.engine_mut().accept();
2048
2049 r.engine_mut().feed(
2050 writer,
2051 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
2052 );
2053 r.engine_mut()
2054 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2055 pump(&mut r, &mut batch);
2056 r.engine_mut().sink_mut().clear();
2057
2058 r.engine_mut()
2059 .feed(writer, &wire(&[b"SETEX", b"k", b"100", b"v"]));
2060 pump(&mut r, &mut batch);
2061 assert_eq!(
2062 r.engine().sink().sent(sub),
2063 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2064 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
2065 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2066 $21\r\n__keyevent@0__:expire\r\n$1\r\nk\r\n"
2067 );
2068 }
2069
2070 fn watching() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2076 watching_flags(b"EA")
2077 }
2078
2079 fn watching_flags(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2081 let (mut r, sub, mut batch) = engine();
2082 let writer = r.engine_mut().accept();
2083 r.engine_mut().feed(
2084 writer,
2085 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
2086 );
2087 r.engine_mut()
2088 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2089 pump(&mut r, &mut batch);
2090 r.engine_mut().sink_mut().clear();
2091 (r, sub, writer, batch)
2092 }
2093
2094 fn fired(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
2100 fired_on(r, sub, 0)
2101 }
2102
2103 fn fired_on(r: &Reactor<Wire<Recorder>>, sub: ConnId, db: usize) -> Vec<(String, String)> {
2106 let head = format!("__keyevent@{db}__:");
2107 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
2108 let mut out = Vec::new();
2109 let mut parts = sent.split("\r\n");
2110 while let Some(p) = parts.next() {
2111 let Some(event) = p.strip_prefix(head.as_str()) else {
2112 continue;
2113 };
2114 if event == "*" {
2117 continue;
2118 }
2119 parts.next();
2120 let key = parts.next().unwrap_or_default();
2121 out.push((event.to_owned(), key.to_owned()));
2122 }
2123 out
2124 }
2125
2126 #[test]
2129 fn taking_the_last_of_a_collection_says_the_key_went_with_it() {
2130 let (mut r, sub, writer, mut batch) = watching();
2131
2132 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"k", b"a"]));
2133 r.engine_mut().feed(writer, &wire(&[b"LPOP", b"k"]));
2134 pump(&mut r, &mut batch);
2135 assert_eq!(
2136 fired(&r, sub),
2137 [("rpush", "k"), ("lpop", "k"), ("del", "k")]
2138 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2139 );
2140 }
2141
2142 #[test]
2145 fn a_move_onto_a_member_already_there_says_only_the_removal() {
2146 let (mut r, sub, writer, mut batch) = watching();
2147
2148 r.engine_mut().feed(writer, &wire(&[b"SADD", b"a", b"m"]));
2149 r.engine_mut()
2150 .feed(writer, &wire(&[b"SADD", b"b", b"m", b"n"]));
2151 pump(&mut r, &mut batch);
2152 r.engine_mut().sink_mut().clear();
2153
2154 r.engine_mut()
2155 .feed(writer, &wire(&[b"SMOVE", b"a", b"b", b"m"]));
2156 pump(&mut r, &mut batch);
2157 assert_eq!(
2158 fired(&r, sub),
2159 [("srem", "a"), ("del", "a")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2160 );
2161 }
2162
2163 #[test]
2166 fn a_score_that_did_not_move_says_nothing() {
2167 let (mut r, sub, writer, mut batch) = watching();
2168
2169 r.engine_mut()
2170 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2171 pump(&mut r, &mut batch);
2172 r.engine_mut().sink_mut().clear();
2173
2174 r.engine_mut()
2175 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2176 r.engine_mut()
2177 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"0", b"m"]));
2178 pump(&mut r, &mut batch);
2179 assert_eq!(fired(&r, sub), []);
2180
2181 r.engine_mut()
2184 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"1", b"m"]));
2185 pump(&mut r, &mut batch);
2186 assert_eq!(fired(&r, sub), [("zincr".to_owned(), "z".to_owned())]);
2187 }
2188
2189 #[test]
2192 fn a_stream_write_says_what_the_trim_behind_it_took() {
2193 let (mut r, sub, writer, mut batch) = watching();
2194
2195 r.engine_mut()
2196 .feed(writer, &wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]));
2197 r.engine_mut().feed(
2198 writer,
2199 &wire(&[b"XADD", b"s", b"MAXLEN", b"9", b"2-1", b"f", b"v"]),
2200 );
2201 r.engine_mut().feed(
2202 writer,
2203 &wire(&[b"XADD", b"s", b"MAXLEN", b"1", b"3-1", b"f", b"v"]),
2204 );
2205 pump(&mut r, &mut batch);
2206 assert_eq!(
2207 fired(&r, sub),
2208 [("xadd", "s"), ("xadd", "s"), ("xadd", "s"), ("xtrim", "s")]
2209 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2210 );
2211 }
2212
2213 #[test]
2217 fn acknowledging_an_entry_that_is_already_gone_says_nothing() {
2218 let (mut r, sub, writer, mut batch) = watching();
2219
2220 for cmd in [
2221 wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]),
2222 wire(&[b"XGROUP", b"CREATE", b"s", b"g", b"0"]),
2223 wire(&[b"XREADGROUP", b"GROUP", b"g", b"c", b"STREAMS", b"s", b">"]),
2224 wire(&[b"XDEL", b"s", b"1-1"]),
2225 ] {
2226 r.engine_mut().feed(writer, &cmd);
2227 }
2228 pump(&mut r, &mut batch);
2229 r.engine_mut().sink_mut().clear();
2230
2231 r.engine_mut().feed(
2232 writer,
2233 &wire(&[b"XACKDEL", b"s", b"g", b"IDS", b"1", b"1-1"]),
2234 );
2235 pump(&mut r, &mut batch);
2236 assert_eq!(fired(&r, sub), []);
2237 }
2238
2239 #[test]
2242 fn emptying_a_hash_says_the_key_went_with_the_last_field() {
2243 let (mut r, sub, writer, mut batch) = watching();
2244
2245 r.engine_mut()
2246 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2247 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"a"]));
2248 r.engine_mut()
2251 .feed(writer, &wire(&[b"HDEL", b"h", b"b", b"a"]));
2252 pump(&mut r, &mut batch);
2253 assert_eq!(
2254 fired(&r, sub),
2255 [("hset", "h"), ("hdel", "h"), ("hdel", "h"), ("del", "h")]
2256 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2257 );
2258 }
2259
2260 #[test]
2263 fn a_field_deadline_already_past_reads_as_a_removal() {
2264 let (mut r, sub, writer, mut batch) = watching();
2265
2266 r.engine_mut()
2267 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2268 pump(&mut r, &mut batch);
2269 r.engine_mut().sink_mut().clear();
2270
2271 r.engine_mut().feed(
2272 writer,
2273 &wire(&[b"HEXPIRE", b"h", b"0", b"FIELDS", b"1", b"a"]),
2274 );
2275 r.engine_mut().feed(
2276 writer,
2277 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"b"]),
2278 );
2279 pump(&mut r, &mut batch);
2280 assert_eq!(
2281 fired(&r, sub),
2282 [("hdel", "h"), ("hexpire", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2283 );
2284 }
2285
2286 #[test]
2289 fn a_write_under_a_deadline_already_gone_says_the_write_first() {
2290 let (mut r, sub, writer, mut batch) = watching();
2291
2292 r.engine_mut().feed(
2293 writer,
2294 &wire(&[b"HSETEX", b"h", b"EXAT", b"1", b"FIELDS", b"1", b"a", b"1"]),
2295 );
2296 pump(&mut r, &mut batch);
2297 assert_eq!(
2298 fired(&r, sub),
2299 [("hset", "h"), ("hdel", "h"), ("del", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2300 );
2301 }
2302
2303 #[test]
2306 fn clearing_a_deadline_that_was_never_set_says_nothing() {
2307 let (mut r, sub, writer, mut batch) = watching();
2308
2309 r.engine_mut()
2310 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2311 r.engine_mut().feed(
2312 writer,
2313 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"a"]),
2314 );
2315 pump(&mut r, &mut batch);
2316 r.engine_mut().sink_mut().clear();
2317
2318 r.engine_mut()
2319 .feed(writer, &wire(&[b"HPERSIST", b"h", b"FIELDS", b"1", b"b"]));
2320 r.engine_mut().feed(
2321 writer,
2322 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"1", b"b"]),
2323 );
2324 pump(&mut r, &mut batch);
2325 assert_eq!(fired(&r, sub), []);
2326
2327 r.engine_mut().feed(
2330 writer,
2331 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"2", b"a", b"b"]),
2332 );
2333 pump(&mut r, &mut batch);
2334 assert_eq!(fired(&r, sub), [("hpersist".to_owned(), "h".to_owned())]);
2335 }
2336
2337 #[test]
2340 fn a_key_that_was_not_there_before_says_so() {
2341 let (mut r, sub, writer, mut batch) = watching_flags(b"En");
2342
2343 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2344 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2345 r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"x"]));
2346 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2347 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2348 pump(&mut r, &mut batch);
2349 assert_eq!(
2350 fired(&r, sub),
2351 [("new", "k"), ("new", "l")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2352 );
2353 }
2354
2355 #[test]
2358 fn the_news_of_a_new_key_comes_before_the_write_that_made_it() {
2359 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2360
2361 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2362 r.engine_mut().feed(writer, &wire(&[b"SET", b"b", b"2"]));
2363 pump(&mut r, &mut batch);
2364 r.engine_mut().sink_mut().clear();
2365
2366 r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2370 pump(&mut r, &mut batch);
2371 assert_eq!(
2372 fired(&r, sub),
2373 [("new", "b"), ("rename_from", "a"), ("rename_to", "b")]
2374 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2375 );
2376 }
2377
2378 #[test]
2382 fn writing_over_a_destination_is_not_a_key_arriving() {
2383 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2384
2385 r.engine_mut()
2386 .feed(writer, &wire(&[b"RPUSH", b"l", b"c", b"a", b"b"]));
2387 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"d", b"x"]));
2388 pump(&mut r, &mut batch);
2389 r.engine_mut().sink_mut().clear();
2390
2391 r.engine_mut()
2392 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2393 pump(&mut r, &mut batch);
2394 assert_eq!(fired(&r, sub), [("sortstore".to_owned(), "d".to_owned())]);
2395 r.engine_mut().sink_mut().clear();
2396
2397 r.engine_mut().feed(writer, &wire(&[b"DEL", b"d"]));
2400 r.engine_mut()
2401 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2402 pump(&mut r, &mut batch);
2403 assert_eq!(
2404 fired(&r, sub),
2405 [("del", "d"), ("new", "d"), ("sortstore", "d")]
2406 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2407 );
2408 }
2409
2410 #[test]
2413 fn replacing_a_value_says_what_went_and_whether_the_kind_changed() {
2414 let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2415
2416 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2417 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2418 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2419 r.engine_mut().feed(writer, &wire(&[b"SET", b"l", b"v"]));
2420 pump(&mut r, &mut batch);
2421 assert_eq!(
2422 fired(&r, sub),
2423 [
2424 ("overwritten", "k"),
2425 ("overwritten", "l"),
2426 ("type_changed", "l")
2427 ]
2428 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2429 );
2430 }
2431
2432 #[test]
2435 fn a_write_that_changes_part_of_a_value_has_not_replaced_it() {
2436 let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2437
2438 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"1"]));
2439 r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"2"]));
2440 r.engine_mut().feed(writer, &wire(&[b"INCR", b"k"]));
2441 r.engine_mut()
2442 .feed(writer, &wire(&[b"SETRANGE", b"k", b"0", b"9"]));
2443 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2444 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2445 pump(&mut r, &mut batch);
2446 assert_eq!(fired(&r, sub), []);
2447 }
2448
2449 #[test]
2453 fn a_rename_says_what_it_replaced_after_saying_what_it_did() {
2454 let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2455
2456 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2457 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"b", b"x"]));
2458 pump(&mut r, &mut batch);
2459 r.engine_mut().sink_mut().clear();
2460
2461 r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2462 pump(&mut r, &mut batch);
2463 assert_eq!(
2464 fired(&r, sub),
2465 [
2466 ("new", "b"),
2467 ("rename_from", "a"),
2468 ("rename_to", "b"),
2469 ("overwritten", "b"),
2470 ("type_changed", "b")
2471 ]
2472 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2473 );
2474 }
2475
2476 #[test]
2479 fn a_store_form_says_what_it_replaced_before_saying_what_it_did() {
2480 let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2481
2482 r.engine_mut().feed(writer, &wire(&[b"SADD", b"s", b"m"]));
2483 r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"q"]));
2484 pump(&mut r, &mut batch);
2485 r.engine_mut().sink_mut().clear();
2486
2487 r.engine_mut()
2488 .feed(writer, &wire(&[b"SINTERSTORE", b"d", b"s"]));
2489 pump(&mut r, &mut batch);
2490 assert_eq!(
2491 fired(&r, sub),
2492 [
2493 ("overwritten", "d"),
2494 ("type_changed", "d"),
2495 ("sinterstore", "d")
2496 ]
2497 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2498 );
2499 }
2500
2501 #[test]
2504 fn a_bit_write_that_left_the_value_alone_says_nothing() {
2505 let (mut r, sub, writer, mut batch) = watching();
2506
2507 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2511 pump(&mut r, &mut batch);
2512 r.engine_mut().sink_mut().clear();
2513
2514 r.engine_mut()
2515 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"1"]));
2516 r.engine_mut()
2517 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2518 r.engine_mut()
2519 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2520 r.engine_mut()
2524 .feed(writer, &wire(&[b"SETBIT", b"k", b"100", b"0"]));
2525 pump(&mut r, &mut batch);
2526 assert_eq!(
2527 fired(&r, sub),
2528 [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2529 );
2530 }
2531
2532 #[test]
2535 fn a_bitfield_that_wrote_the_same_values_back_says_nothing() {
2536 let (mut r, sub, writer, mut batch) = watching();
2537
2538 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2539 pump(&mut r, &mut batch);
2540 r.engine_mut().sink_mut().clear();
2541
2542 r.engine_mut().feed(
2544 writer,
2545 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"97"]),
2546 );
2547 r.engine_mut()
2548 .feed(writer, &wire(&[b"BITFIELD", b"k", b"GET", b"u8", b"0"]));
2549 r.engine_mut().feed(
2550 writer,
2551 &wire(&[b"BITFIELD", b"k", b"INCRBY", b"u8", b"0", b"0"]),
2552 );
2553 pump(&mut r, &mut batch);
2554 assert_eq!(fired(&r, sub), []);
2555
2556 r.engine_mut().feed(
2559 writer,
2560 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"98"]),
2561 );
2562 r.engine_mut().feed(
2563 writer,
2564 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"800", b"0"]),
2565 );
2566 pump(&mut r, &mut batch);
2567 assert_eq!(
2568 fired(&r, sub),
2569 [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2570 );
2571 }
2572
2573 #[test]
2576 fn the_sketch_commands_say_what_a_mass_add_says() {
2577 let (mut r, sub, writer, mut batch) = watching();
2578
2579 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2580 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2582 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h"]));
2584 r.engine_mut().feed(writer, &wire(&[b"PFMERGE", b"d"]));
2586 r.engine_mut()
2587 .feed(writer, &wire(&[b"PFMERGE", b"d", b"h"]));
2588 pump(&mut r, &mut batch);
2589 assert_eq!(
2590 fired(&r, sub),
2591 [("pfadd", "h"), ("pfadd", "d"), ("pfadd", "d")]
2592 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2593 );
2594 }
2595
2596 #[test]
2599 fn the_geo_commands_say_what_the_sorted_set_under_them_did() {
2600 let (mut r, sub, writer, mut batch) = watching();
2601
2602 let point: &[&[u8]] = &[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"];
2603 r.engine_mut().feed(writer, &wire(point));
2604 r.engine_mut().feed(writer, &wire(point));
2606 r.engine_mut().feed(
2608 writer,
2609 &wire(&[b"GEOADD", b"g", b"14.0", b"38.115556", b"P"]),
2610 );
2611 r.engine_mut().feed(
2612 writer,
2613 &wire(&[
2614 b"GEORADIUS",
2615 b"g",
2616 b"14.0",
2617 b"38.0",
2618 b"200",
2619 b"km",
2620 b"STORE",
2621 b"d",
2622 ]),
2623 );
2624 r.engine_mut().feed(
2625 writer,
2626 &wire(&[
2627 b"GEOSEARCHSTORE",
2628 b"e",
2629 b"g",
2630 b"FROMLONLAT",
2631 b"14.0",
2632 b"38.0",
2633 b"BYRADIUS",
2634 b"200",
2635 b"km",
2636 ]),
2637 );
2638 pump(&mut r, &mut batch);
2639 assert_eq!(
2640 fired(&r, sub),
2641 [
2642 ("zadd", "g"),
2643 ("zadd", "g"),
2644 ("georadiusstore", "d"),
2645 ("geosearchstore", "e")
2646 ]
2647 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2648 );
2649 }
2650
2651 #[test]
2654 fn a_geo_store_that_found_nothing_takes_the_destination_with_it() {
2655 let (mut r, sub, writer, mut batch) = watching();
2656
2657 r.engine_mut().feed(
2658 writer,
2659 &wire(&[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"]),
2660 );
2661 r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"x"]));
2662 pump(&mut r, &mut batch);
2663 r.engine_mut().sink_mut().clear();
2664
2665 r.engine_mut().feed(
2666 writer,
2667 &wire(&[
2668 b"GEORADIUS",
2669 b"g",
2670 b"1.0",
2671 b"1.0",
2672 b"1",
2673 b"km",
2674 b"STORE",
2675 b"d",
2676 ]),
2677 );
2678 r.engine_mut().feed(
2681 writer,
2682 &wire(&[
2683 b"GEORADIUS",
2684 b"g",
2685 b"1.0",
2686 b"1.0",
2687 b"1",
2688 b"km",
2689 b"STORE",
2690 b"d",
2691 ]),
2692 );
2693 pump(&mut r, &mut batch);
2694 assert_eq!(
2695 fired(&r, sub),
2696 [("del", "d")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2697 );
2698 }
2699
2700 #[test]
2704 fn a_key_that_lands_on_another_database_is_new_over_there() {
2705 let (mut r, sub, mut batch) = engine();
2706 let writer = r.engine_mut().accept();
2707 r.engine_mut().feed(
2708 writer,
2709 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EAnoc"]),
2710 );
2711 r.engine_mut().feed(
2712 sub,
2713 &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*", b"__keyevent@1__:*"]),
2714 );
2715 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2716 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2717 pump(&mut r, &mut batch);
2718 r.engine_mut().sink_mut().clear();
2719
2720 r.engine_mut()
2721 .feed(writer, &wire(&[b"COPY", b"a", b"b", b"DB", b"1"]));
2722 r.engine_mut().feed(writer, &wire(&[b"MOVE", b"k", b"1"]));
2723 pump(&mut r, &mut batch);
2724 assert_eq!(
2725 fired_on(&r, sub, 1),
2726 [
2727 ("new", "b"),
2728 ("copy_to", "b"),
2729 ("new", "k"),
2730 ("move_to", "k")
2731 ]
2732 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2733 );
2734 assert_eq!(
2737 fired_on(&r, sub, 0),
2738 [("move_from", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2739 );
2740 }
2741
2742 #[test]
2748 fn a_read_that_found_nothing_says_which_key_it_was() {
2749 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2750
2751 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2752 r.engine_mut()
2753 .feed(writer, &wire(&[b"MGET", b"a", b"nk", b"nk"]));
2754 r.engine_mut()
2755 .feed(writer, &wire(&[b"EXISTS", b"nj", b"a"]));
2756 pump(&mut r, &mut batch);
2757 assert_eq!(
2758 fired(&r, sub),
2759 [("keymiss", "nk"), ("keymiss", "nk"), ("keymiss", "nj")]
2760 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2761 );
2762 }
2763
2764 #[test]
2767 fn only_the_shape_of_a_write_that_reads_says_it() {
2768 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2769
2770 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2773 r.engine_mut().feed(
2774 writer,
2775 &wire(&[b"BITFIELD", b"nk", b"SET", b"u8", b"0", b"1"]),
2776 );
2777 r.engine_mut().feed(writer, &wire(&[b"LPOP", b"nk"]));
2778 pump(&mut r, &mut batch);
2779 assert_eq!(fired(&r, sub), []);
2780
2781 r.engine_mut()
2783 .feed(writer, &wire(&[b"SET", b"nj", b"v", b"GET"]));
2784 r.engine_mut()
2785 .feed(writer, &wire(&[b"BITFIELD", b"nl", b"GET", b"u8", b"0"]));
2786 r.engine_mut().feed(writer, &wire(&[b"GETDEL", b"nm"]));
2787 pump(&mut r, &mut batch);
2788 assert_eq!(
2789 fired(&r, sub),
2790 [("keymiss", "nj"), ("keymiss", "nl"), ("keymiss", "nm")]
2791 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2792 );
2793 }
2794
2795 #[test]
2798 fn a_store_form_says_it_only_for_its_sources() {
2799 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2800
2801 r.engine_mut()
2802 .feed(writer, &wire(&[b"SINTERSTORE", b"dst", b"nk", b"nj"]));
2803 r.engine_mut()
2804 .feed(writer, &wire(&[b"ZUNIONSTORE", b"dst", b"1", b"nz"]));
2805 r.engine_mut()
2806 .feed(writer, &wire(&[b"ZRANGESTORE", b"dst", b"nz", b"0", b"-1"]));
2807 pump(&mut r, &mut batch);
2808 assert_eq!(
2809 fired(&r, sub),
2810 [
2811 ("keymiss", "nk"),
2812 ("keymiss", "nj"),
2813 ("keymiss", "nz"),
2814 ("keymiss", "nz")
2815 ]
2816 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2817 );
2818 }
2819
2820 #[test]
2824 fn the_stream_reads_say_it_for_the_keys_behind_the_keyword() {
2825 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2826
2827 r.engine_mut().feed(
2828 writer,
2829 &wire(&[b"XREAD", b"STREAMS", b"nk", b"nj", b"0", b"0"]),
2830 );
2831 pump(&mut r, &mut batch);
2832 assert_eq!(
2833 fired(&r, sub),
2834 [
2835 ("keymiss", "nk"),
2836 ("keymiss", "nj"),
2837 ("keymiss", "nk"),
2838 ("keymiss", "nj")
2839 ]
2840 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2841 );
2842 }
2843
2844 #[test]
2848 fn an_argument_that_did_not_parse_takes_the_miss_back() {
2849 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2850
2851 r.engine_mut()
2852 .feed(writer, &wire(&[b"GETRANGE", b"nk", b"x", b"-1"]));
2853 r.engine_mut()
2854 .feed(writer, &wire(&[b"LPOS", b"nk", b"a", b"RANK", b"0"]));
2855 pump(&mut r, &mut batch);
2856 assert_eq!(fired(&r, sub), []);
2857
2858 r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2862 pump(&mut r, &mut batch);
2863 r.engine_mut().sink_mut().clear();
2864
2865 r.engine_mut()
2866 .feed(writer, &wire(&[b"SINTER", b"nk", b"s"]));
2867 pump(&mut r, &mut batch);
2868 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2869 }
2870
2871 #[test]
2875 fn a_read_stops_missing_where_it_stops_looking() {
2876 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2877
2878 r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2879 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"x"]));
2880 pump(&mut r, &mut batch);
2881 r.engine_mut().sink_mut().clear();
2882
2883 r.engine_mut()
2884 .feed(writer, &wire(&[b"SINTER", b"s", b"nk"]));
2885 pump(&mut r, &mut batch);
2886 assert_eq!(fired(&r, sub), []);
2887
2888 r.engine_mut().feed(writer, &wire(&[b"MGET", b"l", b"nk"]));
2891 pump(&mut r, &mut batch);
2892 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2893 }
2894
2895 #[test]
2899 fn the_keys_a_sort_pattern_names_say_it_as_they_are_read() {
2900 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2901
2902 r.engine_mut()
2903 .feed(writer, &wire(&[b"RPUSH", b"l", b"1", b"2"]));
2904 r.engine_mut().feed(writer, &wire(&[b"SET", b"w_1", b"5"]));
2905 pump(&mut r, &mut batch);
2906 r.engine_mut().sink_mut().clear();
2907
2908 r.engine_mut().feed(
2909 writer,
2910 &wire(&[b"SORT", b"l", b"BY", b"w_*", b"GET", b"p_*"]),
2911 );
2912 pump(&mut r, &mut batch);
2913 assert_eq!(
2914 fired(&r, sub),
2915 [("keymiss", "w_2"), ("keymiss", "p_2"), ("keymiss", "p_1")]
2916 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2917 );
2918 }
2919
2920 #[test]
2924 fn a_deadline_that_passed_is_news_before_the_miss_it_causes() {
2925 let (mut r, sub, mut batch) = timed();
2926 let writer = r.engine_mut().accept();
2927 r.engine_mut().feed(
2928 writer,
2929 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EgAm"]),
2930 );
2931 r.engine_mut()
2932 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2933 r.engine_mut()
2934 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
2935 pump(&mut r, &mut batch);
2936 r.engine_mut().sink_mut().clear();
2937
2938 r.engine().server().advance_clock_ms(50);
2939 r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
2940 pump(&mut r, &mut batch);
2941 assert_eq!(
2942 fired(&r, sub),
2943 [("expired", "k"), ("keymiss", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2944 );
2945 }
2946
2947 #[test]
2950 fn a_module_read_says_it_the_way_a_core_read_does() {
2951 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2952
2953 r.engine_mut().feed(writer, &wire(&[b"JSON.GET", b"nk"]));
2954 r.engine_mut().feed(writer, &wire(&[b"TS.GET", b"nj"]));
2955 r.engine_mut()
2956 .feed(writer, &wire(&[b"BF.EXISTS", b"nl", b"x"]));
2957 r.engine_mut().feed(writer, &wire(&[b"TDIGEST.MIN", b"nm"]));
2958 r.engine_mut().feed(writer, &wire(&[b"TOPK.LIST", b"nn"]));
2959 r.engine_mut().feed(writer, &wire(&[b"CMS.INFO", b"no"]));
2960 r.engine_mut().feed(writer, &wire(&[b"VCARD", b"np"]));
2961 pump(&mut r, &mut batch);
2962 assert_eq!(
2963 fired(&r, sub),
2964 [
2965 ("keymiss", "nk"),
2966 ("keymiss", "nj"),
2967 ("keymiss", "nl"),
2968 ("keymiss", "nm"),
2969 ("keymiss", "nn"),
2970 ("keymiss", "no"),
2971 ("keymiss", "np")
2972 ]
2973 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2974 );
2975
2976 r.engine_mut().sink_mut().clear();
2979 r.engine_mut()
2980 .feed(writer, &wire(&[b"JSON.MGET", b"nk", b"nj", b"$"]));
2981 pump(&mut r, &mut batch);
2982 assert_eq!(
2983 fired(&r, sub),
2984 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2985 );
2986 }
2987
2988 #[test]
2992 fn the_quiet_module_commands_stay_quiet() {
2993 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2994
2995 r.engine_mut()
2996 .feed(writer, &wire(&[b"JSON.SET", b"nk", b"$", b"1"]));
2997 r.engine_mut()
2998 .feed(writer, &wire(&[b"BF.ADD", b"nj", b"x"]));
2999 r.engine_mut()
3000 .feed(writer, &wire(&[b"TS.ADD", b"nl", b"1000", b"1"]));
3001 r.engine_mut().feed(writer, &wire(&[b"TS.INFO", b"nm"]));
3002 r.engine_mut().feed(writer, &wire(&[b"CF.COMPACT", b"nn"]));
3003 r.engine_mut()
3004 .feed(writer, &wire(&[b"JSON.DEBUG", b"HELP"]));
3005 r.engine_mut()
3006 .feed(writer, &wire(&[b"FT.GET", b"ni", b"no"]));
3007 r.engine_mut()
3008 .feed(writer, &wire(&[b"FT.SEARCH", b"ni", b"*"]));
3009 pump(&mut r, &mut batch);
3010 assert_eq!(fired(&r, sub), []);
3011
3012 r.engine_mut()
3014 .feed(writer, &wire(&[b"JSON.DEBUG", b"MEMORY", b"np"]));
3015 r.engine_mut()
3016 .feed(writer, &wire(&[b"FT.SUGGET", b"nq", b"x"]));
3017 r.engine_mut().feed(writer, &wire(&[b"FT.SUGLEN", b"nr"]));
3018 pump(&mut r, &mut batch);
3019 assert_eq!(
3020 fired(&r, sub),
3021 [("keymiss", "np"), ("keymiss", "nq"), ("keymiss", "nr")]
3022 .map(|(e, k)| (e.to_owned(), k.to_owned()))
3023 );
3024 }
3025
3026 #[test]
3033 fn a_module_read_keeps_the_miss_a_later_argument_spoiled() {
3034 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
3035
3036 r.engine_mut()
3037 .feed(writer, &wire(&[b"JSON.GET", b"nk", b"$..["]));
3038 r.engine_mut().feed(
3039 writer,
3040 &wire(&[b"VSIM", b"nj", b"ELE", b"e", b"COUNT", b"x"]),
3041 );
3042 pump(&mut r, &mut batch);
3043 assert_eq!(
3044 fired(&r, sub),
3045 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3046 );
3047 }
3048
3049 #[test]
3052 fn the_module_merges_stop_at_the_first_empty_source() {
3053 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
3054
3055 r.engine_mut().feed(
3056 writer,
3057 &wire(&[b"TDIGEST.MERGE", b"nk", b"2", b"nj", b"nl"]),
3058 );
3059 pump(&mut r, &mut batch);
3060 assert_eq!(
3061 fired(&r, sub),
3062 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3063 );
3064
3065 r.engine_mut().sink_mut().clear();
3069 r.engine_mut()
3070 .feed(writer, &wire(&[b"CMS.MERGE", b"nk", b"1", b"nj"]));
3071 pump(&mut r, &mut batch);
3072 assert_eq!(fired(&r, sub), []);
3073
3074 r.engine_mut()
3077 .feed(writer, &wire(&[b"CMS.INITBYDIM", b"cm", b"100", b"5"]));
3078 pump(&mut r, &mut batch);
3079 r.engine_mut().sink_mut().clear();
3080
3081 r.engine_mut()
3082 .feed(writer, &wire(&[b"CMS.MERGE", b"cm", b"2", b"nj", b"nl"]));
3083 pump(&mut r, &mut batch);
3084 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nj".to_owned())]);
3085 }
3086
3087 fn watching_fields(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3093 let (mut r, sub, mut batch) = engine();
3094 let writer = r.engine_mut().accept();
3095 r.engine_mut().feed(
3096 writer,
3097 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
3098 );
3099 r.engine_mut()
3100 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__subkey*@0__:*"]));
3101 pump(&mut r, &mut batch);
3102 r.engine_mut().sink_mut().clear();
3103 (r, sub, writer, batch)
3104 }
3105
3106 fn carried(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
3112 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
3113 let mut out = Vec::new();
3114 let mut parts = sent.split("\r\n");
3115 while let Some(p) = parts.next() {
3116 if p != "pmessage" {
3117 continue;
3118 }
3119 let mut next = || {
3122 parts.next();
3123 parts.next().unwrap_or_default().to_owned()
3124 };
3125 next();
3126 let channel = next();
3127 out.push((channel, next()));
3128 }
3129 out
3130 }
3131
3132 #[test]
3136 fn the_subkey_channels_carry_the_fields_an_event_touched() {
3137 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3138
3139 r.engine_mut()
3140 .feed(writer, &wire(&[b"HSET", b"h", b"a,b", b"1", b"c", b"2"]));
3141 pump(&mut r, &mut batch);
3142 assert_eq!(
3143 carried(&r, sub),
3144 [
3145 ("__subkeyspace@0__:h", "hset|3:a,b,1:c"),
3146 ("__subkeyevent@0__:hset", "1:h|3:a,b,1:c"),
3147 ("__subkeyspaceitem@0__:h\na,b", "hset"),
3148 ("__subkeyspaceitem@0__:h\nc", "hset"),
3149 ("__subkeyspaceevent@0__:hset|h", "3:a,b,1:c"),
3150 ]
3151 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3152 );
3153 }
3154
3155 #[test]
3159 fn a_key_holding_a_newline_skips_the_per_field_channel() {
3160 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3161
3162 r.engine_mut()
3163 .feed(writer, &wire(&[b"HSET", b"h\nx", b"f", b"1"]));
3164 pump(&mut r, &mut batch);
3165 assert_eq!(
3166 carried(&r, sub),
3167 [
3168 ("__subkeyspace@0__:h\nx", "hset|1:f"),
3169 ("__subkeyevent@0__:hset", "3:h\nx|1:f"),
3170 ("__subkeyspaceevent@0__:hset|h\nx", "1:f"),
3171 ]
3172 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3173 );
3174 }
3175
3176 #[test]
3180 fn an_event_with_no_fields_stays_off_the_subkey_channels() {
3181 let (mut r, sub, writer, mut batch) = watching_fields(b"AS");
3182
3183 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3184 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
3185 r.engine_mut()
3186 .feed(writer, &wire(&[b"HSET", b"h", b"f", b"1"]));
3187 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"f"]));
3188 pump(&mut r, &mut batch);
3189 assert_eq!(
3190 carried(&r, sub),
3191 [
3192 ("__subkeyspace@0__:h", "hset|1:f"),
3193 ("__subkeyspace@0__:h", "hdel|1:f"),
3194 ]
3195 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3196 );
3197 }
3198
3199 fn watching_clock() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3205 let (mut r, sub, mut batch) = timed();
3206 let writer = r.engine_mut().accept();
3207 r.engine_mut().feed(
3208 writer,
3209 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3210 );
3211 r.engine_mut()
3212 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3213 pump(&mut r, &mut batch);
3214 r.engine_mut().sink_mut().clear();
3215 (r, sub, writer, batch)
3216 }
3217
3218 #[test]
3222 fn a_deadline_that_passed_is_news_when_a_reader_finds_it() {
3223 let (mut r, sub, writer, mut batch) = watching_clock();
3224
3225 r.engine_mut()
3226 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3227 pump(&mut r, &mut batch);
3228 r.engine_mut().sink_mut().clear();
3229
3230 r.engine().server().advance_clock_ms(50);
3231 r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
3232 pump(&mut r, &mut batch);
3233 assert_eq!(
3234 fired(&r, sub),
3235 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned())),
3236 "and not a del alongside it, which is a different piece of news"
3237 );
3238 }
3239
3240 #[test]
3248 fn a_deadline_that_passed_is_news_with_nobody_reading() {
3249 let (mut r, sub, writer, mut batch) = watching_clock();
3250
3251 r.engine_mut()
3252 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3253 pump(&mut r, &mut batch);
3254 r.engine_mut().sink_mut().clear();
3255
3256 r.engine().server().advance_clock_ms(50);
3257 pump(&mut r, &mut batch);
3259 assert_eq!(
3260 fired(&r, sub),
3261 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3262 );
3263
3264 r.engine_mut().sink_mut().clear();
3265 pump(&mut r, &mut batch);
3266 assert!(fired(&r, sub).is_empty(), "and it only goes once");
3267 }
3268
3269 #[test]
3273 fn a_key_a_limit_took_says_it_was_evicted() {
3274 let (mut r, sub, writer, mut batch) = watching();
3275
3276 let val = vec![b'v'; 256];
3277 for i in 0..2000u32 {
3278 let k = format!("key:{i:08}");
3279 r.engine_mut()
3280 .feed(writer, &wire(&[b"SET", k.as_bytes(), &val]));
3281 }
3282 pump(&mut r, &mut batch);
3283 r.engine().server().refresh_memory();
3284 let full = r.engine().server().memory_bytes();
3285 r.engine_mut().sink_mut().clear();
3286
3287 let limit = (full / 2).to_string();
3290 r.engine_mut().feed(
3291 writer,
3292 &wire(&[b"CONFIG", b"SET", b"maxmemory-policy", b"allkeys-random"]),
3293 );
3294 r.engine_mut().feed(
3295 writer,
3296 &wire(&[b"CONFIG", b"SET", b"maxmemory", limit.as_bytes()]),
3297 );
3298 r.engine_mut()
3299 .feed(writer, &wire(&[b"SET", b"newcomer", &val]));
3300 pump(&mut r, &mut batch);
3301
3302 let events = fired(&r, sub);
3303 assert!(
3304 events.iter().any(|(e, _)| e == "evicted"),
3305 "the write made room and never said so: {events:?}"
3306 );
3307 assert!(
3308 events
3309 .iter()
3310 .all(|(e, k)| e != "evicted" || k != "newcomer"),
3311 "the key the write was for is the one key it cannot have taken"
3312 );
3313 }
3314
3315 #[test]
3318 fn a_transaction_publishes_between_its_commands_and_not_after_them() {
3319 let (mut r, sub, mut batch) = engine();
3320 let writer = r.engine_mut().accept();
3321
3322 r.engine_mut().feed(
3323 writer,
3324 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3325 );
3326 r.engine_mut()
3327 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3328 pump(&mut r, &mut batch);
3329 r.engine_mut().sink_mut().clear();
3330
3331 r.engine_mut().feed(writer, &wire(&[b"MULTI"]));
3332 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3333 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
3334 r.engine_mut().feed(writer, &wire(&[b"EXEC"]));
3335 pump(&mut r, &mut batch);
3336 assert_eq!(
3337 r.engine().sink().sent(sub),
3338 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3339 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
3340 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3341 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
3342 );
3343 }
3344
3345 #[test]
3346 fn a_reply_the_socket_would_not_take_is_offered_again() {
3347 let mut r = Reactor::inline(Wire::new(Trickle::default()));
3348 let conn = r.engine_mut().accept();
3349 let mut batch = Vec::new();
3350
3351 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3352 pump(&mut r, &mut batch);
3353 assert_eq!(r.engine().sink().sent, b"+PONG\r\n");
3355 assert_eq!(r.engine().sink().writes, 2);
3356 }
3357 #[test]
3361 fn client_reply_skip_covers_the_command_after_it_and_nothing_else() {
3362 let (mut r, conn, mut batch) = engine();
3363
3364 r.engine_mut()
3365 .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"SKIP"]));
3366 r.engine_mut().feed(conn, &wire(&[b"SET", b"a", b"1"]));
3367 r.engine_mut().feed(conn, &wire(&[b"SET", b"b", b"2"]));
3368 pump(&mut r, &mut batch);
3369 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
3372 }
3373
3374 #[test]
3375 fn client_reply_off_stays_off_until_it_is_turned_back_on() {
3376 let (mut r, conn, mut batch) = engine();
3377
3378 r.engine_mut()
3379 .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"OFF"]));
3380 r.engine_mut().feed(conn, &wire(&[b"SET", b"c", b"3"]));
3381 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3382 r.engine_mut()
3383 .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"ON"]));
3384 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3385 pump(&mut r, &mut batch);
3386 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n+PONG\r\n");
3389
3390 r.engine_mut().sink_mut().clear();
3392 r.engine_mut().feed(conn, &wire(&[b"GET", b"c"]));
3393 pump(&mut r, &mut batch);
3394 assert_eq!(r.engine().sink().sent(conn), b"$1\r\n3\r\n");
3395 }
3396
3397 #[test]
3400 fn a_connection_reports_the_socket_it_was_opened_on() {
3401 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3402 let conn = r
3403 .engine_mut()
3404 .accept_from("10.0.0.7:54321", "10.0.0.1:6379", 11, false);
3405 let mut batch = Vec::new();
3406
3407 r.engine_mut().feed(conn, &wire(&[b"CLIENT", b"INFO"]));
3408 pump(&mut r, &mut batch);
3409 let sent = String::from_utf8_lossy(r.engine().sink().sent(conn)).into_owned();
3410 assert!(sent.contains("addr=10.0.0.7:54321"), "{sent}");
3411 assert!(sent.contains("laddr=10.0.0.1:6379"), "{sent}");
3412 assert!(sent.contains("fd=11"), "{sent}");
3413 }
3414
3415 #[test]
3418 fn a_connection_counts_the_bytes_and_the_commands_that_went_over_it() {
3419 let (mut r, conn, mut batch) = engine();
3420 let mut stream = wire(&[b"PING"]);
3421 stream.extend(wire(&[b"PING"]));
3422 let sent_in = stream.len();
3423
3424 r.engine_mut().feed(conn, &stream);
3425 pump(&mut r, &mut batch);
3426 r.engine_mut().sink_mut().clear();
3427
3428 r.engine_mut().feed(conn, &wire(&[b"CLIENT", b"INFO"]));
3429 pump(&mut r, &mut batch);
3430 let sent = String::from_utf8_lossy(r.engine().sink().sent(conn)).into_owned();
3431 assert!(sent.contains("tot-cmds=2"), "{sent}");
3435 assert!(sent.contains("read-events=2"), "{sent}");
3436 assert!(
3437 sent.contains(&format!("tot-net-in={}", sent_in + 26)),
3438 "{sent}"
3439 );
3440 assert!(sent.contains("tot-net-out=14"), "{sent}");
3441 }
3442
3443 #[test]
3447 fn client_list_reports_every_connection_and_not_just_the_one_asking() {
3448 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3449 let one = r
3450 .engine_mut()
3451 .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3452 let two = r
3453 .engine_mut()
3454 .accept_from("10.0.0.8:2222", "10.0.0.1:6379", 12, false);
3455 let mut batch = Vec::new();
3456
3457 r.engine_mut()
3458 .feed(two, &wire(&[b"CLIENT", b"SETNAME", b"worker"]));
3459 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3460 pump(&mut r, &mut batch);
3461
3462 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3463 let lines: Vec<&str> = sent.lines().filter(|l| l.starts_with("id=")).collect();
3464 assert_eq!(lines.len(), 2, "{sent}");
3465 assert!(lines[0].contains("addr=10.0.0.7:1111"), "{sent}");
3466 assert!(lines[0].contains("cmd=client|list"), "{sent}");
3467 assert!(lines[1].contains("addr=10.0.0.8:2222"), "{sent}");
3468 assert!(lines[1].contains("name=worker"), "{sent}");
3469 assert!(lines[1].contains("cmd=client|setname"), "{sent}");
3470 }
3471
3472 #[test]
3475 fn client_list_keeps_the_order_the_connections_were_opened_in() {
3476 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3477 let one = r.engine_mut().accept();
3478 let two = r.engine_mut().accept();
3479 let three = r.engine_mut().accept();
3480 let mut batch = Vec::new();
3481
3482 r.engine_mut().hangup(two);
3483 r.engine_mut().feed(three, &wire(&[b"CLIENT", b"LIST"]));
3484 pump(&mut r, &mut batch);
3485
3486 let sent = String::from_utf8_lossy(r.engine().sink().sent(three)).into_owned();
3487 let ids: Vec<&str> = sent
3488 .lines()
3489 .filter(|l| l.starts_with("id="))
3490 .map(|l| l.split(' ').next().unwrap_or(""))
3491 .collect();
3492 assert_eq!(ids, vec!["id=1", "id=3"], "{sent}");
3493 let _ = one;
3494 }
3495
3496 #[test]
3500 fn client_kill_closes_the_connection_it_names_and_answers_a_count() {
3501 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3502 let one = r
3503 .engine_mut()
3504 .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3505 let two = r
3506 .engine_mut()
3507 .accept_from("10.0.0.8:2222", "10.0.0.1:6379", 12, false);
3508 let mut batch = Vec::new();
3509
3510 r.engine_mut()
3511 .feed(one, &wire(&[b"CLIENT", b"KILL", b"ADDR", b"10.0.0.8:2222"]));
3512 pump(&mut r, &mut batch);
3513
3514 assert_eq!(r.engine().sink().sent(one), b":1\r\n");
3515 assert!(r.engine().sink().was_closed(two), "the named one went away");
3516 assert!(!r.engine().sink().was_closed(one), "the caller did not");
3517 }
3518
3519 #[test]
3522 fn the_old_kill_takes_one_address_and_will_take_the_caller() {
3523 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3524 let one = r
3525 .engine_mut()
3526 .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3527 let mut batch = Vec::new();
3528
3529 r.engine_mut()
3530 .feed(one, &wire(&[b"CLIENT", b"KILL", b"10.0.0.9:9999"]));
3531 pump(&mut r, &mut batch);
3532 assert_eq!(r.engine().sink().sent(one), b"-ERR No such client\r\n");
3533
3534 r.engine_mut().sink_mut().clear();
3535 r.engine_mut()
3536 .feed(one, &wire(&[b"CLIENT", b"KILL", b"10.0.0.7:1111"]));
3537 pump(&mut r, &mut batch);
3538 assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
3539 assert!(r.engine().sink().was_closed(one), "it took itself");
3540 }
3541
3542 #[test]
3545 fn a_kill_spares_the_caller_unless_it_is_told_not_to() {
3546 let (mut r, conn, mut batch) = engine();
3547 r.engine_mut()
3548 .feed(conn, &wire(&[b"CLIENT", b"KILL", b"TYPE", b"normal"]));
3549 pump(&mut r, &mut batch);
3550 assert_eq!(r.engine().sink().sent(conn), b":0\r\n");
3551 assert!(!r.engine().sink().was_closed(conn));
3552
3553 r.engine_mut().sink_mut().clear();
3554 r.engine_mut().feed(
3555 conn,
3556 &wire(&[b"CLIENT", b"KILL", b"TYPE", b"normal", b"SKIPME", b"no"]),
3557 );
3558 pump(&mut r, &mut batch);
3559 assert_eq!(r.engine().sink().sent(conn), b":1\r\n");
3560 assert!(r.engine().sink().was_closed(conn));
3561 }
3562
3563 #[test]
3566 fn a_connection_that_went_away_is_off_the_list() {
3567 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3568 let one = r.engine_mut().accept();
3569 let two = r.engine_mut().accept();
3570 let mut batch = Vec::new();
3571 assert_eq!(r.engine().server().client_count(), 2);
3572
3573 r.engine_mut().hangup(two);
3574 assert_eq!(r.engine().server().client_count(), 1);
3575
3576 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3577 pump(&mut r, &mut batch);
3578 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3579 assert_eq!(sent.lines().filter(|l| l.starts_with("id=")).count(), 1);
3580 }
3581
3582 #[test]
3585 fn a_write_pause_holds_the_writes_and_lets_the_reads_through() {
3586 let (mut r, one, mut batch) = timed();
3587 let two = r.engine_mut().accept();
3588
3589 r.engine_mut()
3590 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3591 pump(&mut r, &mut batch);
3592 assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
3593
3594 r.engine_mut().sink_mut().clear();
3595 r.engine_mut().feed(two, &wire(&[b"GET", b"k"]));
3596 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3597 pump(&mut r, &mut batch);
3598 assert_eq!(
3599 r.engine().sink().sent(two),
3600 b"$-1\r\n",
3601 "the read answered and the write is being held"
3602 );
3603 assert_eq!(r.engine().waiting(), 1, "the held connection");
3604
3605 r.engine_mut().sink_mut().clear();
3606 r.engine().server().advance_clock_ms(500);
3607 pump(&mut r, &mut batch);
3608 assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3609 assert_eq!(r.engine().waiting(), 0);
3610 }
3611
3612 #[test]
3614 fn an_all_pause_holds_every_command_and_cannot_be_called_off() {
3615 let (mut r, one, mut batch) = timed();
3616 let two = r.engine_mut().accept();
3617
3618 r.engine_mut()
3619 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3620 pump(&mut r, &mut batch);
3621
3622 r.engine_mut().sink_mut().clear();
3623 r.engine_mut().feed(two, &wire(&[b"PING"]));
3624 r.engine_mut().feed(two, &wire(&[b"CLIENT", b"UNPAUSE"]));
3625 pump(&mut r, &mut batch);
3626 assert_eq!(r.engine().sink().sent(two), b"", "not even the ping");
3627
3628 r.engine().server().advance_clock_ms(499);
3629 pump(&mut r, &mut batch);
3630 assert_eq!(r.engine().sink().sent(two), b"", "still inside the pause");
3631
3632 r.engine().server().advance_clock_ms(1);
3633 pump(&mut r, &mut batch);
3634 assert_eq!(
3635 r.engine().sink().sent(two),
3636 b"+PONG\r\n+OK\r\n",
3637 "both, in the order they were sent"
3638 );
3639 }
3640
3641 #[test]
3643 fn a_shorter_pause_does_not_shorten_the_one_already_running() {
3644 let (mut r, one, mut batch) = timed();
3645 let two = r.engine_mut().accept();
3646
3647 r.engine_mut()
3648 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3649 r.engine_mut()
3650 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"10", b"WRITE"]));
3651 pump(&mut r, &mut batch);
3652 assert_eq!(r.engine().server().pause_ends(), START_MS + 500);
3653
3654 r.engine_mut().sink_mut().clear();
3655 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3656 r.engine().server().advance_clock_ms(100);
3657 pump(&mut r, &mut batch);
3658 assert_eq!(r.engine().sink().sent(two), b"", "the longer end holds");
3659
3660 r.engine().server().advance_clock_ms(400);
3661 pump(&mut r, &mut batch);
3662 assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3663 }
3664
3665 #[test]
3667 fn a_write_pause_on_top_of_an_all_pause_still_holds_the_reads() {
3668 let (mut r, one, mut batch) = timed();
3669 let two = r.engine_mut().accept();
3670
3671 r.engine_mut()
3672 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3673 pump(&mut r, &mut batch);
3674 r.engine_mut()
3677 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3678
3679 r.engine_mut().sink_mut().clear();
3680 r.engine_mut().feed(two, &wire(&[b"GET", b"k"]));
3681 r.engine().server().advance_clock_ms(200);
3682 pump(&mut r, &mut batch);
3683 assert_eq!(r.engine().sink().sent(two), b"", "still everything");
3684 }
3685
3686 #[test]
3688 fn unpause_lets_go_of_a_write_pause_at_once() {
3689 let (mut r, one, mut batch) = timed();
3690 let two = r.engine_mut().accept();
3691
3692 r.engine_mut()
3693 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"5000", b"WRITE"]));
3694 pump(&mut r, &mut batch);
3695 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3696 pump(&mut r, &mut batch);
3697 assert_eq!(r.engine().sink().sent(two), b"");
3698
3699 r.engine_mut().sink_mut().clear();
3700 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"UNPAUSE"]));
3701 pump(&mut r, &mut batch);
3702 assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3703 }
3704
3705 #[test]
3708 fn a_write_pause_holds_an_exec_only_when_the_transaction_writes() {
3709 let (mut r, one, mut batch) = timed();
3710 let two = r.engine_mut().accept();
3711 let three = r.engine_mut().accept();
3712
3713 for conn in [two, three] {
3714 r.engine_mut().feed(conn, &wire(&[b"MULTI"]));
3715 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
3716 }
3717 r.engine_mut().feed(three, &wire(&[b"SET", b"k", b"v"]));
3718 pump(&mut r, &mut batch);
3719
3720 r.engine_mut()
3721 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3722 pump(&mut r, &mut batch);
3723
3724 r.engine_mut().sink_mut().clear();
3725 r.engine_mut().feed(two, &wire(&[b"EXEC"]));
3726 r.engine_mut().feed(three, &wire(&[b"EXEC"]));
3727 pump(&mut r, &mut batch);
3728 assert_eq!(r.engine().sink().sent(two), b"*1\r\n$-1\r\n", "reads only");
3729 assert_eq!(r.engine().sink().sent(three), b"", "one write in it");
3730
3731 r.engine_mut().sink_mut().clear();
3732 r.engine().server().advance_clock_ms(500);
3733 pump(&mut r, &mut batch);
3734 assert_eq!(r.engine().sink().sent(three), b"*2\r\n$-1\r\n+OK\r\n");
3735 }
3736
3737 #[test]
3740 fn a_held_connection_that_hangs_up_lets_go_of_its_slot() {
3741 let (mut r, one, mut batch) = timed();
3742 let two = r.engine_mut().accept();
3743
3744 r.engine_mut()
3745 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3746 pump(&mut r, &mut batch);
3747 r.engine_mut().feed(two, &wire(&[b"PING"]));
3748 pump(&mut r, &mut batch);
3749 assert_eq!(r.engine().waiting(), 1);
3750
3751 r.engine_mut().hangup(two);
3752 pump(&mut r, &mut batch);
3753 assert_eq!(r.engine().server().client_count(), 1);
3754
3755 r.engine().server().advance_clock_ms(500);
3756 pump(&mut r, &mut batch);
3757 assert_eq!(r.engine().waiting(), 0, "nothing left holding a slot");
3758 }
3759
3760 #[test]
3763 fn a_held_connection_names_the_command_it_is_waiting_to_run() {
3764 let (mut r, one, mut batch) = timed();
3765 let two = r.engine_mut().accept();
3766
3767 r.engine_mut()
3768 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3769 pump(&mut r, &mut batch);
3770 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3771 pump(&mut r, &mut batch);
3772
3773 r.engine_mut().sink_mut().clear();
3774 r.engine().server().advance_clock_ms(0);
3775 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3776 r.engine().server().advance_clock_ms(500);
3780 pump(&mut r, &mut batch);
3781 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3782 assert!(sent.contains("cmd=set"), "{sent}");
3783 }
3784
3785 fn watched() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3790 let (mut r, eye, mut batch) = timed();
3791 let one = r.engine_mut().accept();
3792 r.engine_mut().feed(eye, &wire(&[b"MONITOR"]));
3793 pump(&mut r, &mut batch);
3794 assert_eq!(r.engine().sink().sent(eye), b"+OK\r\n");
3795 r.engine_mut().sink_mut().clear();
3796 (r, eye, one, batch)
3797 }
3798
3799 const STAMP: &str = "1000.000000";
3801
3802 fn fed(r: &Reactor<Wire<Recorder>>, eye: ConnId) -> String {
3804 String::from_utf8_lossy(r.engine().sink().sent(eye)).into_owned()
3805 }
3806
3807 #[test]
3808 fn a_monitor_is_fed_a_command_another_connection_ran() {
3809 let (mut r, eye, one, mut batch) = watched();
3810
3811 r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
3812 pump(&mut r, &mut batch);
3813
3814 assert_eq!(
3815 fed(&r, eye),
3816 format!("+{STAMP} [0 ?:0] \"SET\" \"k\" \"v\"\r\n")
3817 );
3818 }
3819
3820 #[test]
3823 fn a_select_is_reported_on_the_database_it_moved_to() {
3824 let (mut r, eye, one, mut batch) = watched();
3825
3826 r.engine_mut().feed(one, &wire(&[b"SELECT", b"3"]));
3827 r.engine_mut().feed(one, &wire(&[b"GET", b"k"]));
3828 r.engine_mut().feed(one, &wire(&[b"SELECT", b"0"]));
3829 pump(&mut r, &mut batch);
3830
3831 assert_eq!(
3832 fed(&r, eye),
3833 format!(
3834 "+{STAMP} [3 ?:0] \"SELECT\" \"3\"\r\n\
3835 +{STAMP} [3 ?:0] \"GET\" \"k\"\r\n\
3836 +{STAMP} [0 ?:0] \"SELECT\" \"0\"\r\n"
3837 )
3838 );
3839 }
3840
3841 #[test]
3844 fn an_argument_is_quoted_the_way_a_real_server_quotes_it() {
3845 let (mut r, eye, one, mut batch) = watched();
3846
3847 r.engine_mut()
3848 .feed(one, &wire(&[b"SET", b"a b", b"q\"s\\n\nt\tz\x01\xff"]));
3849 pump(&mut r, &mut batch);
3850
3851 assert_eq!(
3852 fed(&r, eye),
3853 format!("+{STAMP} [0 ?:0] \"SET\" \"a b\" \"q\\\"s\\\\n\\nt\\tz\\x01\\xff\"\r\n")
3854 );
3855 }
3856
3857 #[test]
3860 fn only_a_command_that_ran_is_reported() {
3861 let (mut r, eye, one, mut batch) = watched();
3862
3863 r.engine_mut().feed(one, &wire(&[b"NOSUCHCOMMAND", b"a"]));
3864 r.engine_mut().feed(one, &wire(&[b"GET"]));
3865 r.engine_mut().feed(one, &wire(&[b"LPUSH", b"l", b"x"]));
3866 r.engine_mut().feed(one, &wire(&[b"GET", b"l"]));
3867 pump(&mut r, &mut batch);
3868
3869 assert_eq!(
3870 fed(&r, eye),
3871 format!(
3872 "+{STAMP} [0 ?:0] \"LPUSH\" \"l\" \"x\"\r\n\
3873 +{STAMP} [0 ?:0] \"GET\" \"l\"\r\n"
3874 ),
3875 "the unknown command and the wrong arity are not commands that ran"
3876 );
3877 }
3878
3879 #[test]
3883 fn a_transaction_is_reported_at_exec_and_in_order() {
3884 let (mut r, eye, one, mut batch) = watched();
3885
3886 r.engine_mut().feed(one, &wire(&[b"MULTI"]));
3887 r.engine_mut().feed(one, &wire(&[b"SET", b"t", b"1"]));
3888 r.engine_mut().feed(one, &wire(&[b"INCR", b"t"]));
3889 r.engine_mut().feed(one, &wire(&[b"EXEC"]));
3890 pump(&mut r, &mut batch);
3891
3892 assert_eq!(
3893 fed(&r, eye),
3894 format!(
3895 "+{STAMP} [0 ?:0] \"MULTI\"\r\n\
3896 +{STAMP} [0 ?:0] \"SET\" \"t\" \"1\"\r\n\
3897 +{STAMP} [0 ?:0] \"INCR\" \"t\"\r\n\
3898 +{STAMP} [0 ?:0] \"EXEC\"\r\n"
3899 )
3900 );
3901 }
3902
3903 #[test]
3906 fn a_script_is_reported_in_front_of_its_own_effects() {
3907 let (mut r, eye, one, mut batch) = watched();
3908
3909 r.engine_mut().feed(
3910 one,
3911 &wire(&[
3912 b"EVAL",
3913 b"redis.call('set', KEYS[1], 'z') return 1",
3914 b"1",
3915 b"sk",
3916 ]),
3917 );
3918 pump(&mut r, &mut batch);
3919
3920 assert_eq!(
3921 fed(&r, eye),
3922 format!(
3923 "+{STAMP} [0 ?:0] \"EVAL\" \"redis.call('set', KEYS[1], 'z') return 1\" \"1\" \"sk\"\r\n\
3924 +{STAMP} [0 lua] \"set\" \"sk\" \"z\"\r\n"
3925 )
3926 );
3927 }
3928
3929 #[test]
3932 fn an_administrative_command_is_not_reported() {
3933 let (mut r, eye, one, mut batch) = watched();
3934
3935 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3936 r.engine_mut()
3937 .feed(one, &wire(&[b"CONFIG", b"GET", b"maxmemory"]));
3938 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"ID"]));
3939 r.engine_mut().feed(one, &wire(&[b"CONFIG", b"HELP"]));
3940 pump(&mut r, &mut batch);
3941
3942 assert_eq!(
3943 fed(&r, eye),
3944 format!(
3945 "+{STAMP} [0 ?:0] \"CLIENT\" \"ID\"\r\n\
3946 +{STAMP} [0 ?:0] \"CONFIG\" \"HELP\"\r\n"
3947 )
3948 );
3949 }
3950
3951 #[test]
3954 fn a_password_is_not_echoed_to_a_monitor() {
3955 let (mut r, eye, one, mut batch) = watched();
3956
3957 r.engine_mut().feed(
3958 one,
3959 &wire(&[b"HELLO", b"3", b"AUTH", b"default", b"hunter2"]),
3960 );
3961 pump(&mut r, &mut batch);
3962
3963 let sent = fed(&r, eye);
3964 assert!(
3965 sent.contains("\"HELLO\" \"3\" \"AUTH\" \"(redacted)\" \"(redacted)\""),
3966 "{sent}"
3967 );
3968 assert!(!sent.contains("hunter2"), "{sent}");
3969 }
3970
3971 #[test]
3974 fn a_monitor_may_not_touch_the_keyspace() {
3975 let (mut r, eye, _one, mut batch) = watched();
3976
3977 r.engine_mut().feed(eye, &wire(&[b"PING"]));
3982 pump(&mut r, &mut batch);
3983 r.engine_mut().feed(eye, &wire(&[b"GET", b"k"]));
3984 pump(&mut r, &mut batch);
3985
3986 assert_eq!(
3987 fed(&r, eye),
3988 format!(
3989 "+PONG\r\n\
3990 +{STAMP} [0 ?:0] \"PING\"\r\n\
3991 -ERR Replica can't interact with the keyspace\r\n"
3992 )
3993 );
3994 }
3995
3996 #[test]
3999 fn a_monitor_is_refused_the_keyspace_at_queue_time() {
4000 let (mut r, eye, _one, mut batch) = watched();
4001
4002 r.engine_mut().feed(eye, &wire(&[b"MULTI"]));
4003 r.engine_mut().feed(eye, &wire(&[b"GET", b"k"]));
4004 r.engine_mut().feed(eye, &wire(&[b"EXEC"]));
4005 pump(&mut r, &mut batch);
4006
4007 let sent = fed(&r, eye);
4008 assert!(
4009 sent.contains("-ERR Replica can't interact with the keyspace"),
4010 "{sent}"
4011 );
4012 assert!(sent.contains("-EXECABORT"), "{sent}");
4013 }
4014
4015 #[test]
4018 fn a_monitor_runs_through_a_pause() {
4019 let (mut r, eye, one, mut batch) = watched();
4020
4021 r.engine_mut()
4022 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"5000", b"ALL"]));
4023 pump(&mut r, &mut batch);
4024 r.engine_mut().sink_mut().clear();
4025
4026 r.engine_mut().feed(eye, &wire(&[b"PING"]));
4027 r.engine_mut().feed(one, &wire(&[b"PING"]));
4028 pump(&mut r, &mut batch);
4029
4030 assert!(
4031 fed(&r, eye).starts_with("+PONG\r\n"),
4032 "the monitor is let through"
4033 );
4034 assert_eq!(r.engine().sink().sent(one), b"", "and the client is not");
4035 }
4036
4037 #[test]
4040 fn monitor_sent_twice_answers_nothing_the_second_time() {
4041 let (mut r, eye, _one, mut batch) = watched();
4042
4043 r.engine_mut().feed(eye, &wire(&[b"MONITOR"]));
4044 pump(&mut r, &mut batch);
4045
4046 assert_eq!(fed(&r, eye), "", "no reply and no line either");
4047 }
4048
4049 #[test]
4051 fn reset_takes_a_connection_out_of_monitor_mode() {
4052 let (mut r, eye, one, mut batch) = watched();
4053
4054 r.engine_mut().feed(eye, &wire(&[b"RESET"]));
4055 pump(&mut r, &mut batch);
4056 r.engine_mut().sink_mut().clear();
4057
4058 r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
4059 r.engine_mut().feed(eye, &wire(&[b"GET", b"k"]));
4060 pump(&mut r, &mut batch);
4061
4062 assert_eq!(fed(&r, eye), "$1\r\nv\r\n", "not watching and not refused");
4063 }
4064
4065 #[test]
4068 fn a_monitor_that_closes_stops_being_one() {
4069 let (mut r, eye, one, mut batch) = watched();
4070
4071 r.engine_mut().hangup(eye);
4072 pump(&mut r, &mut batch);
4073 assert!(!r.engine().server().monitored());
4074
4075 r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
4076 pump(&mut r, &mut batch);
4077 assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
4078 }
4079
4080 #[test]
4082 fn two_monitors_are_fed_the_same_bytes() {
4083 let (mut r, eye, one, mut batch) = watched();
4084 let other = r.engine_mut().accept();
4085 r.engine_mut().feed(other, &wire(&[b"MONITOR"]));
4086 pump(&mut r, &mut batch);
4087 r.engine_mut().sink_mut().clear();
4088
4089 r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
4090 pump(&mut r, &mut batch);
4091
4092 assert_eq!(fed(&r, eye), fed(&r, other));
4093 assert_eq!(
4094 fed(&r, eye),
4095 format!("+{STAMP} [0 ?:0] \"SET\" \"k\" \"v\"\r\n")
4096 );
4097 }
4098
4099 #[test]
4101 fn a_monitor_is_reported_as_one_in_client_list() {
4102 let (mut r, _eye, one, mut batch) = watched();
4103
4104 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
4105 pump(&mut r, &mut batch);
4106
4107 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
4108 assert!(sent.contains("flags=O"), "{sent}");
4109 assert!(sent.contains("flags=N"), "and the other one is not: {sent}");
4110 }
4111}