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 server.is_behind();
231 Wire {
232 front: Front::new(sink),
233 parked: Vec::new(),
234 post: Vec::new(),
235 held: Vec::new(),
236 server,
237 }
238 }
239
240 #[must_use]
242 pub fn server(&self) -> &Server {
243 &self.server
244 }
245
246 #[must_use]
249 pub fn shared(&self) -> Arc<Server> {
250 Arc::clone(&self.server)
251 }
252
253 pub fn server_mut(&mut self) -> &mut Server {
268 self.server.forget_behind();
272 Arc::get_mut(&mut self.server)
273 .expect("the server is set up before the threads that share it are started")
274 }
275
276 #[must_use]
278 pub const fn sink(&self) -> &S {
279 self.front.sink()
280 }
281
282 pub const fn sink_mut(&mut self) -> &mut S {
284 self.front.sink_mut()
285 }
286
287 pub fn set_limits(&mut self, limits: Limits) {
289 self.front.set_limits(limits);
290 }
291
292 pub fn accept(&mut self) -> ConnId {
294 self.server.counted().opened();
295 let at = self.front.open(self.server.next_client());
296 let now = self.server.now_ms();
297 let guarded = self.server.guarded();
302 let row = if let Some(session) = self.front.session_mut(at) {
303 session.opened(now);
304 session.admit(!guarded);
305 Some(session.row().clone())
306 } else {
307 None
308 };
309 if let Some(row) = row {
314 self.server.register_client(&row);
315 }
316 self.note_buffers();
317 at
318 }
319
320 pub fn accept_from(&mut self, peer: &str, local: &str, fd: i32, unix: bool) -> ConnId {
328 let at = self.accept();
329 if let Some(session) = self.front.session_mut(at) {
330 session.set_socket(peer, local, fd, unix);
331 }
332 at
333 }
334
335 fn note_buffers(&mut self) {
340 let delta = self.front.buffer_delta();
341 if delta != 0 {
342 self.server.note_conn_bytes(delta);
343 }
344 }
345
346 pub fn hangup(&mut self, conn: ConnId) {
352 if !self.front.live(conn) {
353 return;
354 }
355 self.front.mark_gone(conn);
356 if self.front.blocked(conn) {
361 self.front.unpark(conn);
362 }
363 if self.front.pending(conn) == 0 {
364 self.release(conn);
365 }
366 self.note_buffers();
367 }
368
369 fn serve_waiters(&mut self) {
382 let now = self.server.now_ms();
383 let mine = self.server.my_slot();
384 self.server.waiters().mine(mine, &mut self.parked);
385 for at in 0..self.parked.len() {
386 let p = self.parked[at];
387 if !self.front.answers(p.conn, p.client) {
392 self.server.forget_waiters(p.client);
393 continue;
394 }
395 let served = {
399 let Wire { server, front, .. } = self;
400 server.serve_waiter(p.client, now, front.out(p.conn))
401 };
402 if served {
403 self.server.forget_waiters(p.client);
404 self.front.unpark(p.conn);
405 self.front.soil(p.conn);
406 }
407 }
408 self.parked.clear();
409 }
410
411 fn deliver(&mut self) {
420 let mut post = core::mem::take(&mut self.post);
423 self.server.take_mail(&mut post);
424 for env in post.drain(..) {
425 let conn = env.conn();
426 if !self.front.answers(conn, env.client()) {
427 continue;
428 }
429 env.write(self.front.out(conn));
430 self.front.soil(conn);
431 }
432 self.post = post;
433 }
434
435 #[must_use]
437 pub fn clients(&self) -> usize {
438 self.front.clients()
439 }
440
441 #[must_use]
443 pub fn ready(&self) -> usize {
444 self.front.ready()
445 }
446
447 #[must_use]
453 pub fn owed(&self) -> usize {
454 self.front.owed()
455 }
456
457 #[must_use]
468 pub fn waiting(&self) -> usize {
469 self.server.parked_here() + self.held.len()
470 }
471
472 #[must_use]
481 pub fn posted(&self) -> usize {
482 self.server.posted()
483 }
484
485 #[must_use]
492 pub fn stopping(&self) -> bool {
493 self.server.stopping()
494 }
495
496 #[must_use]
498 pub fn decoders(&self) -> usize {
499 self.front.decoders()
500 }
501
502 #[must_use]
504 pub fn buffer_bytes(&self) -> usize {
505 self.front.buffer_bytes()
506 }
507
508 pub fn feed(&mut self, conn: ConnId, bytes: &[u8]) {
514 self.front.feed(conn, bytes);
515 self.note_buffers();
516 }
517
518 fn release(&mut self, conn: ConnId) {
520 if let Some(session) = self.front.session_mut(conn) {
524 dispatch::forget_session(&self.server, session);
525 }
526 let Some(client) = self.front.close(conn) else {
527 return;
528 };
529 self.forget(client);
530 }
531
532 fn forget(&mut self, client: u64) {
539 self.server.forget_waiters(client);
540 self.server.forget_client(client);
541 self.server.counted().closed();
542 }
543
544 fn resume(&mut self) {
558 let mut held = core::mem::take(&mut self.held);
561 for &(conn, client) in &held {
562 if self.front.answers(conn, client) && self.front.blocked(conn) {
567 self.front.unpark(conn);
568 }
569 }
570 held.clear();
571 self.held = held;
572 }
573
574 fn reap(&mut self) {
575 for (conn, client) in self.server.my_kills() {
576 self.server.kill_done();
577 if self.front.answers(conn, client) {
578 self.hangup(conn);
579 }
580 }
581 }
582
583 pub fn take_ready(&mut self, into: &mut Vec<Cmd>, max: usize) -> usize {
588 self.front.take_ready(into, max)
589 }
590
591 pub fn tick(&mut self) {
597 self.server.refresh_clock();
598 }
599
600 pub fn maintain(&mut self) -> Option<usize> {
618 if !self.server.cron_running() {
624 return None;
625 }
626 self.server.refresh_memory();
632 self.server.backup_expire();
636 self.server.expire_slice(SWEEP_LOOKS);
641 self.server.compact_step()
642 }
643}
644
645impl<S: Sink> Engine for Wire<S> {
646 type Work = Cmd;
647
648 fn key_hash(&self, cmd: &Cmd) -> Option<u64> {
649 let spec = table::at(cmd.spec)?;
654 if spec.first_key <= 0 {
655 return None;
656 }
657 let args = self.front.args(cmd);
658 let key = args.opt(spec.first_key as usize)?;
663 Some(Keyspace::hash_of(key))
664 }
665
666 fn prefetch(&self, cmd: &Cmd, hash: u64) {
667 let db = self.front.db(cmd.conn());
668 self.server.striped_ref(db).prefetch_hashed(hash);
673 }
674
675 fn run(&mut self, cmd: Cmd, _hash: Option<u64>) -> yo_reactor::Flow {
676 let conn = cmd.conn();
677 if self.front.blocked(conn) {
682 self.front.park(conn, cmd);
683 return yo_reactor::Flow::Next;
684 }
685
686 let flow = if self.front.start(&cmd) {
690 let Wire { front, server, .. } = self;
691 let (args, session, out) = front.parts(&cmd);
692 let spec = table::at(cmd.spec);
693 let mark = out.len();
694 let flow = dispatch::resolved(server, session, spec, args, out);
695 if flow != Flow::Hold {
700 session.finished();
707 session.note_proto(out.proto().version());
708 let mode = session.reply_mode();
709 session.step_reply();
710 if mode != Reply::On {
711 out.truncate(mark);
712 }
713 }
714 flow
715 } else {
716 Flow::Continue
720 };
721
722 if flow == Flow::Hold {
729 self.front.hold(conn, cmd);
730 let client = self.front.client(conn);
731 yo_alloc::allow(|| self.held.push((conn, client)));
732 return yo_reactor::Flow::Next;
733 }
734
735 self.front.done(&cmd);
736 if self.front.gone(conn) {
737 if self.front.pending(conn) == 0 {
738 self.release(conn);
739 }
740 } else {
741 match flow {
742 Flow::Close => {
743 self.front.quit(conn);
744 self.front.soil(conn);
745 }
746 Flow::Block => {
751 self.front.block(conn);
752 let client = self.front.client(conn);
753 self.server.bind_waiter(client, conn);
754 }
755 Flow::Hold => {}
758 Flow::Continue => self.front.soil(conn),
759 }
760 }
761
762 if self.server.parked_here() != 0 {
767 self.serve_waiters();
768 }
769 yo_reactor::Flow::Next
770 }
771
772 fn flush(&mut self) {
773 if self.server.parked_here() != 0 {
784 self.server.refresh_clock();
785 self.serve_waiters();
786 }
787
788 if !self.held.is_empty() {
794 self.server.refresh_clock();
795 if self.server.paused(self.server.now_ms()).is_none() {
796 self.resume();
797 }
798 }
799
800 if self.server.kills() != 0 {
805 self.reap();
806 }
807
808 if self.server.mail_here() != 0 {
813 self.deliver();
814 }
815
816 let mut dirty = self.front.take_dirty();
820 let mut at = 0;
821 while at < dirty.len() {
822 let conn = dirty[at];
823 match self.front.write_out(conn) {
824 Wrote::Owed => at += 1,
828 Wrote::Done => {
829 dirty.swap_remove(at);
830 }
831 Wrote::Ended(client) => {
832 self.forget(client);
833 dirty.swap_remove(at);
834 }
835 }
836 }
837 self.front.give_dirty(dirty);
838 self.note_buffers();
839 }
840
841 fn maintain(&mut self, budget: &mut yo_reactor::Budget) {
842 if !budget.spend(1) {
845 return;
846 }
847 self.tick();
848 let looks = budget.left() as usize;
854 let spent = self.server.expire_slice(looks);
855 budget.spend(u32::try_from(spent).unwrap_or(u32::MAX));
856 }
857}
858
859pub fn pump<S: Sink>(reactor: &mut Reactor<Wire<S>>, batch: &mut Vec<Cmd>) -> usize {
866 let mut ran = 0;
867 reactor.engine_mut().tick();
868 loop {
874 loop {
875 batch.clear();
876 if reactor.engine_mut().take_ready(batch, BATCH_MAX) == 0 {
877 break;
878 }
879 let armed = yo_alloc::guard();
889 ran += reactor.execute_all(batch.drain(..));
890 drop(armed);
891 reactor.engine_mut().flush();
892 reactor.engine_mut().maintain();
895 }
896 reactor.engine_mut().maintain();
899 reactor.engine_mut().flush();
907 if reactor.engine().ready() == 0 {
908 break;
909 }
910 }
911 ran
912}
913
914#[cfg(test)]
915mod tests {
916 use super::*;
917
918 fn wire(args: &[&[u8]]) -> Vec<u8> {
920 let mut b = format!("*{}\r\n", args.len()).into_bytes();
921 for a in args {
922 b.extend_from_slice(format!("${}\r\n", a.len()).as_bytes());
923 b.extend_from_slice(a);
924 b.extend_from_slice(b"\r\n");
925 }
926 b
927 }
928
929 fn engine() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
930 let mut r = Reactor::inline(Wire::new(Recorder::new()));
931 let conn = r.engine_mut().accept();
932 (r, conn, Vec::new())
933 }
934
935 const START_MS: u64 = 1_000_000;
937
938 fn timed() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
944 let server = crate::dispatch::Server::with_clock(yo_kv::Clock::fixed(START_MS));
945 let mut r = Reactor::inline(Wire::with_server(server, Recorder::new()));
946 let conn = r.engine_mut().accept();
947 (r, conn, Vec::new())
948 }
949
950 #[test]
951 fn a_pipelined_batch_comes_back_in_order_and_in_one_write() {
952 let (mut r, conn, mut batch) = engine();
953 let mut stream = wire(&[b"SET", b"k", b"v"]);
954 stream.extend(wire(&[b"GET", b"k"]));
955 stream.extend(wire(&[b"INCR", b"n"]));
956
957 r.engine_mut().feed(conn, &stream);
958 assert_eq!(r.engine().ready(), 3);
959 assert_eq!(pump(&mut r, &mut batch), 3);
960
961 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$1\r\nv\r\n:1\r\n");
962 assert_eq!(r.engine().ready(), 0);
963 }
964
965 #[test]
968 fn a_command_split_across_reads_resumes_rather_than_restarts() {
969 let (mut r, conn, mut batch) = engine();
970 let bytes = wire(&[b"SET", b"key", b"value"]);
971
972 for at in 1..bytes.len() {
973 r.engine_mut().feed(conn, &bytes[at - 1..at]);
974 assert_eq!(r.engine().ready(), 0, "not a command yet at {at}");
975 }
976 r.engine_mut().feed(conn, &bytes[bytes.len() - 1..]);
977 assert_eq!(r.engine().ready(), 1);
978 assert_eq!(pump(&mut r, &mut batch), 1);
979 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
980
981 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
984 pump(&mut r, &mut batch);
985 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$5\r\nvalue\r\n");
986 }
987
988 #[test]
989 fn two_connections_are_two_sessions_over_one_server() {
990 let (mut r, a, mut batch) = engine();
991 let b = r.engine_mut().accept();
992
993 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
994 r.engine_mut().feed(a, &wire(&[b"SET", b"k", b"a"]));
995 r.engine_mut().feed(b, &wire(&[b"SET", b"k", b"b"]));
996 r.engine_mut().feed(a, &wire(&[b"GET", b"k"]));
997 r.engine_mut().feed(b, &wire(&[b"GET", b"k"]));
998 pump(&mut r, &mut batch);
999
1000 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n+OK\r\n$1\r\na\r\n");
1001 assert_eq!(r.engine().sink().sent(b), b"+OK\r\n$1\r\nb\r\n");
1002 assert_eq!(r.engine().clients(), 2);
1003 }
1004
1005 #[test]
1017 fn two_threads_write_into_one_server() {
1018 const EACH: usize = 200;
1019
1020 let mut server = Server::new();
1021 server.set_threads(2);
1022 let first = Wire::with_server(server, Recorder::new());
1023 let second = Wire::over(first.shared(), Recorder::new());
1024 let server = first.shared();
1025
1026 std::thread::scope(|s| {
1027 for (at, engine) in [first, second].into_iter().enumerate() {
1028 s.spawn(move || {
1029 let mut r = Reactor::inline(engine);
1030 let mut batch = Vec::new();
1031 let conn = r.engine_mut().accept();
1032 for i in 0..EACH {
1033 let key = format!("t{at}:{i}");
1034 r.engine_mut()
1035 .feed(conn, &wire(&[b"SET", key.as_bytes(), b"v"]));
1036 pump(&mut r, &mut batch);
1037 }
1038 });
1039 }
1040 });
1041
1042 assert_eq!(server.striped_ref(0).len(), 2 * EACH);
1045 assert_eq!(server.totals().connections, 2);
1048 }
1049
1050 #[test]
1053 fn a_waiter_belongs_to_the_thread_that_parked_it() {
1054 let mut server = Server::new();
1055 server.set_threads(2);
1056 let first = Wire::with_server(server, Recorder::new());
1057 let second = Wire::over(first.shared(), Recorder::new());
1058 let server = first.shared();
1059
1060 let parked = std::sync::Barrier::new(2);
1061 let swept = std::sync::Barrier::new(2);
1062
1063 std::thread::scope(|s| {
1064 let (parked, swept) = (&parked, &swept);
1065 s.spawn(move || {
1066 let mut r = Reactor::inline(first);
1067 let mut batch = Vec::new();
1068 let conn = r.engine_mut().accept();
1069 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
1070 pump(&mut r, &mut batch);
1071 parked.wait();
1072
1073 for _ in 0..50 {
1076 pump(&mut r, &mut batch);
1077 }
1078 swept.wait();
1079 assert!(r.engine().sink().sent(conn).is_empty(), "nothing to say");
1080 });
1081 s.spawn(move || {
1082 let mut r = Reactor::inline(second);
1083 let mut batch = Vec::new();
1084 let conn = r.engine_mut().accept();
1085 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"b", b"0"]));
1086 pump(&mut r, &mut batch);
1087 parked.wait();
1088 swept.wait();
1089
1090 let pusher = r.engine_mut().accept();
1093 r.engine_mut().feed(pusher, &wire(&[b"RPUSH", b"b", b"v"]));
1094 pump(&mut r, &mut batch);
1095 assert_eq!(
1096 r.engine().sink().sent(conn),
1097 b"*2\r\n$1\r\nb\r\n$1\r\nv\r\n",
1098 "served by the thread that parked it"
1099 );
1100 });
1101 });
1102
1103 assert_eq!(server.parked(), 1, "and the other one is still waiting");
1104 }
1105
1106 #[test]
1112 fn a_thread_counts_the_clients_it_blocked_and_nobody_else_s() {
1113 let mut server = Server::new();
1114 server.set_threads(2);
1115 let first = Wire::with_server(server, Recorder::new());
1116 let second = Wire::over(first.shared(), Recorder::new());
1117 let server = first.shared();
1118
1119 let parked = std::sync::Barrier::new(2);
1120 let looked = std::sync::Barrier::new(2);
1121
1122 std::thread::scope(|s| {
1123 let (parked, looked) = (&parked, &looked);
1124 s.spawn(move || {
1125 let mut r = Reactor::inline(first);
1126 let mut batch = Vec::new();
1127 let conn = r.engine_mut().accept();
1128 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
1129 pump(&mut r, &mut batch);
1130 assert_eq!(r.engine().waiting(), 1, "the one this thread blocked");
1131 parked.wait();
1132 looked.wait();
1133
1134 let other = r.engine_mut().accept();
1138 r.engine_mut().feed(other, &wire(&[b"PING"]));
1139 pump(&mut r, &mut batch);
1140 r.engine_mut().hangup(other);
1141 pump(&mut r, &mut batch);
1142 assert_eq!(r.engine().waiting(), 1, "still just the blocked one");
1143 });
1144 s.spawn(move || {
1145 let mut r = Reactor::inline(second);
1146 let mut batch = Vec::new();
1147 parked.wait();
1148
1149 pump(&mut r, &mut batch);
1152 assert_eq!(r.engine().waiting(), 0, "none of them are this one's");
1153 assert_eq!(r.engine().server().parked(), 1, "one on the server");
1154 looked.wait();
1155 });
1156 });
1157
1158 assert_eq!(server.parked(), 1);
1159 }
1160
1161 #[test]
1164 fn client_ids_are_the_server_s_to_hand_out() {
1165 let first = Wire::new(Recorder::new());
1166 let second = Wire::over(first.shared(), Recorder::new());
1167 let mut a = Reactor::inline(first);
1168 let mut b = Reactor::inline(second);
1169
1170 let (one, two) = (a.engine_mut().accept(), b.engine_mut().accept());
1171 assert_eq!(one, two, "the same slot on each front");
1172
1173 let mut batch = Vec::new();
1178 a.engine_mut().feed(one, &wire(&[b"HELLO", b"3"]));
1179 b.engine_mut().feed(two, &wire(&[b"HELLO", b"3"]));
1180 pump(&mut a, &mut batch);
1181 pump(&mut b, &mut batch);
1182
1183 let first = String::from_utf8_lossy(a.engine().sink().sent(one)).into_owned();
1184 let second = String::from_utf8_lossy(b.engine().sink().sent(two)).into_owned();
1185 assert!(first.contains(":1\r\n"), "{first}");
1186 assert!(second.contains(":2\r\n"), "{second}");
1187 }
1188
1189 #[test]
1190 fn quit_is_answered_and_then_the_connection_goes() {
1191 let (mut r, conn, mut batch) = engine();
1192 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1193 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1194 pump(&mut r, &mut batch);
1195
1196 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1197 assert!(r.engine().sink().was_closed(conn));
1198 assert_eq!(r.engine().clients(), 0);
1199
1200 let again = r.engine_mut().accept();
1202 assert_eq!(again, conn);
1203 assert_eq!(r.engine().clients(), 1);
1204 }
1205
1206 #[test]
1209 fn what_a_client_pipelined_behind_quit_is_never_run() {
1210 let (mut r, conn, mut batch) = engine();
1211 let mut stream = wire(&[b"QUIT"]);
1212 stream.extend(wire(&[b"SET", b"foo", b"bar"]));
1213 r.engine_mut().feed(conn, &stream);
1214 assert_eq!(r.engine().ready(), 2);
1216 pump(&mut r, &mut batch);
1217
1218 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
1220 assert!(r.engine().sink().was_closed(conn));
1221
1222 r.engine_mut().sink_mut().clear();
1227 let next = r.engine_mut().accept();
1228 r.engine_mut().feed(next, &wire(&[b"GET", b"foo"]));
1229 pump(&mut r, &mut batch);
1230 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1231 }
1232
1233 #[test]
1243 fn a_slot_that_last_spoke_resp3_answers_the_next_client_in_resp2() {
1244 let (mut r, conn, mut batch) = engine();
1245 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1246 r.engine_mut().feed(conn, &wire(&[b"GET", b"nothing"]));
1247 pump(&mut r, &mut batch);
1248 assert!(r.engine().sink().sent(conn).ends_with(b"_\r\n"));
1249 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1250 pump(&mut r, &mut batch);
1251
1252 r.engine_mut().sink_mut().clear();
1253 let next = r.engine_mut().accept();
1254 assert_eq!(next, conn, "the same slot, which is what this is about");
1255 r.engine_mut().feed(next, &wire(&[b"GET", b"nothing"]));
1256 pump(&mut r, &mut batch);
1257 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1258 }
1259
1260 #[test]
1262 fn commands_that_arrived_before_a_protocol_error_are_still_answered() {
1263 let (mut r, conn, mut batch) = engine();
1264 let mut stream = wire(&[b"SET", b"k", b"v"]);
1265 stream.extend(wire(&[b"GET", b"k"]));
1266 stream.extend_from_slice(b"*1\r\n+notabulk\r\n");
1267 r.engine_mut().feed(conn, &stream);
1268 pump(&mut r, &mut batch);
1269
1270 let sent = r.engine().sink().sent(conn);
1273 assert!(
1274 sent.starts_with(b"+OK\r\n$1\r\nv\r\n-ERR Protocol error: "),
1275 "{sent:?}"
1276 );
1277 assert!(r.engine().sink().was_closed(conn));
1278 }
1279
1280 #[test]
1281 fn a_protocol_error_is_written_and_closes_the_connection() {
1282 let (mut r, conn, mut batch) = engine();
1283 r.engine_mut().feed(conn, b"*1\r\n+notabulk\r\n");
1285 pump(&mut r, &mut batch);
1286
1287 let sent = r.engine().sink().sent(conn);
1288 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1289 assert!(r.engine().sink().was_closed(conn));
1290 assert_eq!(r.engine().clients(), 0);
1291 }
1292
1293 #[test]
1297 fn a_decoder_that_came_back_mid_command_starts_the_next_one_clean() {
1298 let (mut r, conn, mut batch) = engine();
1299 r.engine_mut()
1301 .feed(conn, b"*3\r\n$3\r\nSET\r\n$1\r\nx\r\n$blabla\r\n");
1302 pump(&mut r, &mut batch);
1303 let sent = r.engine().sink().sent(conn);
1304 assert!(
1305 sent.starts_with(b"-ERR Protocol error: invalid bulk length"),
1306 "{sent:?}"
1307 );
1308
1309 r.engine_mut().sink_mut().clear();
1313 let next = r.engine_mut().accept();
1314 r.engine_mut().feed(next, &wire(&[b"GET", b"k"]));
1315 pump(&mut r, &mut batch);
1316 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1317
1318 r.engine_mut().sink_mut().clear();
1319 let third = r.engine_mut().accept();
1320 r.engine_mut().feed(third, b"*1\r\n+notabulk\r\n");
1321 pump(&mut r, &mut batch);
1322 let sent = r.engine().sink().sent(third);
1323 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1324 }
1325
1326 #[test]
1329 fn a_hangup_with_commands_in_flight_waits_for_them() {
1330 let (mut r, conn, mut batch) = engine();
1331 r.engine_mut().feed(conn, &wire(&[b"SET", b"k", b"v"]));
1332 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1333
1334 batch.clear();
1335 r.engine_mut().take_ready(&mut batch, BATCH_MAX);
1336 r.engine_mut().hangup(conn);
1337 assert_eq!(r.engine().clients(), 1, "still holding the buffer");
1338
1339 r.execute_all(batch.drain(..));
1340 r.engine_mut().flush();
1341 assert_eq!(r.engine().clients(), 0);
1342 assert!(r.engine().sink().sent(conn).is_empty(), "nobody to answer");
1343
1344 let decoders = r.engine().decoders();
1347 let again = r.engine_mut().accept();
1348 assert_eq!(again, conn);
1349 r.engine_mut().feed(again, &wire(&[b"PING"]));
1350 pump(&mut r, &mut batch);
1351 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1352 assert_eq!(r.engine().decoders(), decoders);
1353 }
1354
1355 #[test]
1358 fn the_buffers_and_the_decoder_pool_stop_growing() {
1359 let (mut r, conn, mut batch) = engine();
1360 let mut stream = Vec::new();
1361 for i in 0..32 {
1362 stream.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1363 }
1364
1365 r.engine_mut().feed(conn, &stream);
1366 pump(&mut r, &mut batch);
1367 let decoders = r.engine().decoders();
1368 let batch_cap = batch.capacity();
1369
1370 for _ in 0..10 {
1371 r.engine_mut().feed(conn, &stream);
1372 pump(&mut r, &mut batch);
1373 }
1374 assert_eq!(r.engine().decoders(), decoders, "the pool is reused");
1375 assert_eq!(batch.capacity(), batch_cap, "the batch buffer is reused");
1376 assert!(
1377 decoders <= BATCH_MAX + 1,
1378 "{decoders} decoders for 32 commands"
1379 );
1380 }
1381
1382 #[test]
1391 fn a_pipelining_client_does_not_grow_the_read_buffer() {
1392 let (mut r, conn, mut batch) = engine();
1393 let mut round = Vec::new();
1394 for i in 0..16 {
1395 round.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1396 }
1397
1398 r.engine_mut().feed(conn, &round);
1399 pump(&mut r, &mut batch);
1400 r.engine_mut().sink_mut().clear();
1401 let after_one = r.engine().buffer_bytes();
1402
1403 let rounds = if cfg!(miri) { 50 } else { 1000 };
1412 for _ in 0..rounds {
1413 r.engine_mut().feed(conn, &round);
1414 pump(&mut r, &mut batch);
1415 r.engine_mut().sink_mut().clear();
1416 }
1417
1418 assert_eq!(
1419 r.engine().buffer_bytes(),
1420 after_one,
1421 "the buffers grew over {rounds} rounds of the same sixteen commands"
1422 );
1423 assert!(
1424 r.engine().server().memory_bytes() >= after_one,
1425 "the buffers are counted in what the server reports"
1426 );
1427 }
1428
1429 #[test]
1432 fn a_command_split_across_reads_survives_compaction() {
1433 let (mut r, conn, mut batch) = engine();
1434 let cmd = wire(&[b"SET", b"key", b"value"]);
1435 let (head, tail) = cmd.split_at(cmd.len() - 4);
1436
1437 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1440 r.engine_mut().feed(conn, head);
1441 pump(&mut r, &mut batch);
1442 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n");
1443
1444 r.engine_mut().feed(conn, tail);
1446 pump(&mut r, &mut batch);
1447 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1448
1449 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
1450 pump(&mut r, &mut batch);
1451 assert!(r.engine().sink().sent(conn).ends_with(b"$5\r\nvalue\r\n"));
1452 }
1453
1454 #[test]
1457 fn the_batch_goes_through_the_reactors_two_walks() {
1458 let (mut r, conn, mut batch) = engine();
1459 for i in 0..100 {
1460 r.engine_mut()
1461 .feed(conn, &wire(&[b"INCR", format!("k{}", i % 7).as_bytes()]));
1462 }
1463 let ran = pump(&mut r, &mut batch);
1464
1465 assert_eq!(ran, 100);
1466 assert_eq!(r.commands(), 100);
1467 assert_eq!(r.turns(), 2);
1469 assert!(r.engine().sink().sent(conn).ends_with(b":15\r\n"));
1471 }
1472
1473 #[derive(Default)]
1476 struct Trickle {
1477 sent: Vec<u8>,
1478 writes: usize,
1479 }
1480
1481 impl Sink for Trickle {
1482 fn write(&mut self, _conn: ConnId, bytes: &[u8]) -> usize {
1483 self.writes += 1;
1484 let n = bytes.len().min(4);
1485 self.sent.extend_from_slice(&bytes[..n]);
1486 n
1487 }
1488 }
1489
1490 #[test]
1493 fn a_blpop_on_a_list_with_something_in_it_never_waits() {
1494 let (mut r, conn, mut batch) = engine();
1495 r.engine_mut().feed(conn, &wire(&[b"RPUSH", b"q", b"a"]));
1496 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"0"]));
1497 pump(&mut r, &mut batch);
1498
1499 assert_eq!(
1500 r.engine().sink().sent(conn),
1501 b":1\r\n*2\r\n$1\r\nq\r\n$1\r\na\r\n"
1502 );
1503 assert_eq!(r.engine().server().parked(), 0);
1504 }
1505
1506 #[test]
1509 fn a_parked_client_is_answered_by_another_connections_push() {
1510 let (mut r, a, mut batch) = engine();
1511 let b = r.engine_mut().accept();
1512
1513 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1514 pump(&mut r, &mut batch);
1515 assert!(r.engine().sink().sent(a).is_empty(), "nothing to say yet");
1516 assert_eq!(r.engine().server().parked(), 1);
1517
1518 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"one"]));
1519 pump(&mut r, &mut batch);
1520
1521 assert_eq!(r.engine().sink().sent(a), b"*2\r\n$1\r\nq\r\n$3\r\none\r\n");
1522 assert_eq!(r.engine().sink().sent(b), b":1\r\n");
1525 assert_eq!(r.engine().server().parked(), 0);
1526 }
1527
1528 #[test]
1531 fn only_a_list_arriving_under_a_named_key_wakes_a_waiter() {
1532 let (mut r, a, mut batch) = engine();
1533 let b = r.engine_mut().accept();
1534 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1535 pump(&mut r, &mut batch);
1536
1537 r.engine_mut()
1538 .feed(b, &wire(&[b"RPUSH", b"elsewhere", b"x"]));
1539 r.engine_mut().feed(b, &wire(&[b"SADD", b"q", b"x"]));
1540 pump(&mut r, &mut batch);
1541
1542 assert!(r.engine().sink().sent(a).is_empty());
1543 assert_eq!(r.engine().server().parked(), 1, "still waiting");
1544 assert_eq!(r.engine().sink().sent(b), b":1\r\n:1\r\n");
1547 }
1548
1549 #[test]
1552 fn two_parked_clients_are_served_in_the_order_they_arrived() {
1553 let (mut r, a, mut batch) = engine();
1554 let b = r.engine_mut().accept();
1555 let c = r.engine_mut().accept();
1556
1557 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1558 pump(&mut r, &mut batch);
1559 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"q", b"0"]));
1560 pump(&mut r, &mut batch);
1561 assert_eq!(r.engine().server().parked(), 2);
1562
1563 r.engine_mut()
1564 .feed(c, &wire(&[b"RPUSH", b"q", b"first", b"second"]));
1565 pump(&mut r, &mut batch);
1566
1567 assert_eq!(
1568 r.engine().sink().sent(a),
1569 b"*2\r\n$1\r\nq\r\n$5\r\nfirst\r\n"
1570 );
1571 assert_eq!(
1572 r.engine().sink().sent(b),
1573 b"*2\r\n$1\r\nq\r\n$6\r\nsecond\r\n"
1574 );
1575 assert_eq!(r.engine().server().parked(), 0);
1576 }
1577
1578 #[test]
1581 fn what_a_client_pipelined_behind_a_block_waits_for_the_block() {
1582 let (mut r, a, mut batch) = engine();
1583 let b = r.engine_mut().accept();
1584
1585 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1588 stream.extend(wire(&[b"PING"]));
1589 r.engine_mut().feed(a, &stream);
1590 pump(&mut r, &mut batch);
1591 assert!(
1592 r.engine().sink().sent(a).is_empty(),
1593 "the PING went out in front of the answer it was sent behind"
1594 );
1595
1596 r.engine_mut().feed(a, &wire(&[b"ECHO", b"after"]));
1598 pump(&mut r, &mut batch);
1599 assert!(r.engine().sink().sent(a).is_empty());
1600
1601 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1602 pump(&mut r, &mut batch);
1603 assert_eq!(
1604 r.engine().sink().sent(a),
1605 b"*2\r\n$1\r\nq\r\n$1\r\nx\r\n+PONG\r\n$5\r\nafter\r\n"
1606 );
1607 }
1608
1609 #[test]
1614 fn a_waiter_is_served_between_two_pipelined_pushes() {
1615 let (mut r, a, mut batch) = engine();
1616 let b = r.engine_mut().accept();
1617 r.engine_mut()
1618 .feed(a, &wire(&[b"BLPOP", b"p1", b"p2", b"0"]));
1619 pump(&mut r, &mut batch);
1620
1621 let mut stream = wire(&[b"RPUSH", b"p2", b"second"]);
1622 stream.extend(wire(&[b"RPUSH", b"p1", b"first"]));
1623 r.engine_mut().feed(b, &stream);
1624 pump(&mut r, &mut batch);
1625
1626 assert_eq!(
1627 r.engine().sink().sent(a),
1628 b"*2\r\n$2\r\np2\r\n$6\r\nsecond\r\n"
1629 );
1630 r.engine_mut()
1632 .feed(b, &wire(&[b"LRANGE", b"p1", b"0", b"-1"]));
1633 pump(&mut r, &mut batch);
1634 assert!(
1635 r.engine()
1636 .sink()
1637 .sent(b)
1638 .ends_with(b"*1\r\n$5\r\nfirst\r\n")
1639 );
1640 }
1641
1642 #[test]
1646 fn a_waiter_woken_by_another_waiter() {
1647 let (mut r, a, mut batch) = engine();
1648 let b = r.engine_mut().accept();
1649 let c = r.engine_mut().accept();
1650
1651 r.engine_mut()
1652 .feed(a, &wire(&[b"BLMOVE", b"x", b"y", b"LEFT", b"RIGHT", b"0"]));
1653 pump(&mut r, &mut batch);
1654 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"y", b"0"]));
1655 pump(&mut r, &mut batch);
1656 assert_eq!(r.engine().server().parked(), 2);
1657
1658 r.engine_mut().feed(c, &wire(&[b"RPUSH", b"x", b"chain"]));
1659 pump(&mut r, &mut batch);
1660
1661 assert_eq!(r.engine().sink().sent(a), b"$5\r\nchain\r\n");
1662 assert_eq!(
1663 r.engine().sink().sent(b),
1664 b"*2\r\n$1\r\ny\r\n$5\r\nchain\r\n"
1665 );
1666 assert_eq!(r.engine().server().parked(), 0);
1667 }
1668
1669 #[test]
1672 fn a_waiter_is_only_woken_on_the_database_it_blocked_on() {
1673 let (mut r, a, mut batch) = engine();
1674 let b = r.engine_mut().accept();
1675 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
1676 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1677 pump(&mut r, &mut batch);
1678 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n");
1679
1680 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"wrongdb"]));
1681 pump(&mut r, &mut batch);
1682 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n", "still waiting");
1683
1684 r.engine_mut().feed(b, &wire(&[b"SELECT", b"3"]));
1685 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"rightdb"]));
1686 pump(&mut r, &mut batch);
1687 assert!(r.engine().sink().sent(a).ends_with(b"$7\r\nrightdb\r\n"));
1688 }
1689
1690 #[test]
1692 fn a_client_that_waited_long_enough_gets_a_null_array() {
1693 let (mut r, conn, mut batch) = timed();
1694 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"30"]));
1695 pump(&mut r, &mut batch);
1696 assert!(r.engine().sink().sent(conn).is_empty());
1697
1698 r.engine_mut().server_mut().set_clock_ms(START_MS + 29_999);
1699 pump(&mut r, &mut batch);
1700 assert!(
1701 r.engine().sink().sent(conn).is_empty(),
1702 "a millisecond short"
1703 );
1704
1705 r.engine_mut().server_mut().set_clock_ms(START_MS + 30_000);
1706 pump(&mut r, &mut batch);
1707 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n");
1709 assert_eq!(r.engine().server().parked(), 0);
1710 }
1711
1712 #[test]
1716 fn every_blocking_command_times_out_with_the_same_null_array() {
1717 for cmd in [
1718 &[b"BLPOP".as_slice(), b"q", b"0.001"][..],
1719 &[b"BRPOP", b"q", b"0.001"],
1720 &[b"BLMOVE", b"q", b"d", b"LEFT", b"RIGHT", b"0.001"],
1721 &[b"BRPOPLPUSH", b"q", b"d", b"0.001"],
1722 &[b"BLMPOP", b"0.001", b"1", b"q", b"LEFT"],
1723 ] {
1724 let (mut r, conn, mut batch) = timed();
1725 r.engine_mut().feed(conn, &wire(cmd));
1726 pump(&mut r, &mut batch);
1727 r.engine_mut().server_mut().set_clock_ms(START_MS + 1);
1728 pump(&mut r, &mut batch);
1729 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n", "for {cmd:?}");
1730 }
1731 }
1732
1733 #[test]
1736 fn a_waiter_that_timed_out_does_not_eat_a_later_push() {
1737 let (mut r, a, mut batch) = timed();
1738 let b = r.engine_mut().accept();
1739 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"1"]));
1740 pump(&mut r, &mut batch);
1741 r.engine_mut().server_mut().set_clock_ms(START_MS + 1000);
1742 pump(&mut r, &mut batch);
1743 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n");
1744
1745 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"late"]));
1746 r.engine_mut()
1747 .feed(b, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1748 pump(&mut r, &mut batch);
1749 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n", "nothing more");
1750 assert!(r.engine().sink().sent(b).ends_with(b"*1\r\n$4\r\nlate\r\n"));
1751 }
1752
1753 #[test]
1758 fn a_client_that_goes_away_while_it_waits_takes_its_waiter_with_it() {
1759 let (mut r, a, mut batch) = engine();
1760 let b = r.engine_mut().accept();
1761 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1762 pump(&mut r, &mut batch);
1763 assert_eq!(r.engine().server().parked(), 1);
1764
1765 r.engine_mut().hangup(a);
1766 pump(&mut r, &mut batch);
1767 assert_eq!(r.engine().server().parked(), 0);
1768 assert_eq!(r.engine().clients(), 1);
1769
1770 let again = r.engine_mut().accept();
1773 assert_eq!(again, a);
1774 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1775 r.engine_mut()
1776 .feed(again, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1777 pump(&mut r, &mut batch);
1778 assert_eq!(r.engine().sink().sent(again), b"*1\r\n$1\r\nx\r\n");
1779 }
1780
1781 #[test]
1785 fn a_hangup_while_parked_gives_back_the_slot_and_the_decoders() {
1786 let (mut r, a, mut batch) = engine();
1787 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1788 stream.extend(wire(&[b"PING"]));
1789 stream.extend(wire(&[b"PING"]));
1790 r.engine_mut().feed(a, &stream);
1791 pump(&mut r, &mut batch);
1792
1793 let decoders = r.engine().decoders();
1794 r.engine_mut().hangup(a);
1795 pump(&mut r, &mut batch);
1796
1797 assert_eq!(r.engine().clients(), 0);
1798 assert!(r.engine().sink().was_closed(a));
1799 assert_eq!(r.engine().decoders(), decoders, "the pool came back whole");
1800 let again = r.engine_mut().accept();
1801 assert_eq!(again, a);
1802 r.engine_mut().feed(again, &wire(&[b"PING"]));
1803 pump(&mut r, &mut batch);
1804 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1805 }
1806
1807 #[test]
1810 fn a_published_message_lands_on_the_subscriber() {
1811 let (mut r, sub, mut batch) = engine();
1812 let pubr = r.engine_mut().accept();
1813
1814 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1815 pump(&mut r, &mut batch);
1816 assert_eq!(
1817 r.engine().sink().sent(sub),
1818 b"*3\r\n$9\r\nsubscribe\r\n$4\r\nnews\r\n:1\r\n"
1819 );
1820 r.engine_mut().sink_mut().clear();
1821
1822 r.engine_mut()
1823 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1824 pump(&mut r, &mut batch);
1825 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1826 assert_eq!(
1827 r.engine().sink().sent(sub),
1828 b"*3\r\n$7\r\nmessage\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1829 );
1830 }
1831
1832 #[test]
1835 fn a_pattern_subscriber_is_told_the_pattern_and_the_channel() {
1836 let (mut r, sub, mut batch) = engine();
1837 let pubr = r.engine_mut().accept();
1838
1839 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"ne*"]));
1840 pump(&mut r, &mut batch);
1841 r.engine_mut().sink_mut().clear();
1842
1843 r.engine_mut()
1844 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1845 pump(&mut r, &mut batch);
1846 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1847 assert_eq!(
1848 r.engine().sink().sent(sub),
1849 b"*4\r\n$8\r\npmessage\r\n$3\r\nne*\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1850 );
1851 }
1852
1853 #[test]
1858 fn resp2_takes_almost_nothing_from_a_subscriber() {
1859 let (mut r, conn, mut batch) = engine();
1860
1861 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1862 pump(&mut r, &mut batch);
1863 r.engine_mut().sink_mut().clear();
1864
1865 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1866 pump(&mut r, &mut batch);
1867 assert_eq!(
1868 r.engine().sink().sent(conn),
1869 b"-ERR Can't execute 'get': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context\r\n"
1870 );
1871 r.engine_mut().sink_mut().clear();
1872
1873 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1875 pump(&mut r, &mut batch);
1876 assert_eq!(
1877 r.engine().sink().sent(conn),
1878 b"*2\r\n$4\r\npong\r\n$0\r\n\r\n"
1879 );
1880 r.engine_mut().sink_mut().clear();
1881
1882 r.engine_mut().feed(conn, &wire(&[b"UNSUBSCRIBE", b"a"]));
1884 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1885 pump(&mut r, &mut batch);
1886 assert_eq!(
1887 r.engine().sink().sent(conn),
1888 b"*3\r\n$11\r\nunsubscribe\r\n$1\r\na\r\n:0\r\n$-1\r\n"
1889 );
1890 }
1891
1892 #[test]
1896 fn a_shard_channel_and_a_pattern_do_not_hear_each_other() {
1897 let (mut r, sub, mut batch) = engine();
1898 let pubr = r.engine_mut().accept();
1899
1900 r.engine_mut().feed(sub, &wire(&[b"SSUBSCRIBE", b"sx"]));
1901 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"s*"]));
1902 pump(&mut r, &mut batch);
1903 r.engine_mut().sink_mut().clear();
1904
1905 r.engine_mut()
1906 .feed(pubr, &wire(&[b"SPUBLISH", b"sx", b"one"]));
1907 pump(&mut r, &mut batch);
1908 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1909 assert_eq!(
1910 r.engine().sink().sent(sub),
1911 b"*3\r\n$8\r\nsmessage\r\n$2\r\nsx\r\n$3\r\none\r\n"
1912 );
1913 r.engine_mut().sink_mut().clear();
1914
1915 r.engine_mut()
1916 .feed(pubr, &wire(&[b"PUBLISH", b"sx", b"two"]));
1917 pump(&mut r, &mut batch);
1918 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1919 assert_eq!(
1920 r.engine().sink().sent(sub),
1921 b"*4\r\n$8\r\npmessage\r\n$2\r\ns*\r\n$2\r\nsx\r\n$3\r\ntwo\r\n"
1922 );
1923 }
1924
1925 #[test]
1929 fn a_subscriber_that_goes_away_leaves_the_registry() {
1930 let (mut r, sub, mut batch) = engine();
1931 let pubr = r.engine_mut().accept();
1932
1933 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1934 pump(&mut r, &mut batch);
1935 r.engine_mut().hangup(sub);
1936 pump(&mut r, &mut batch);
1937 r.engine_mut().sink_mut().clear();
1938
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(pubr), b":0\r\n");
1943
1944 let next = r.engine_mut().accept();
1946 assert_eq!(next, sub);
1947 r.engine_mut()
1948 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1949 pump(&mut r, &mut batch);
1950 assert_eq!(r.engine().sink().sent(next), b"");
1951 }
1952
1953 #[test]
1962 fn resp3_delivers_a_message_as_a_push() {
1963 let (mut r, conn, mut batch) = engine();
1964
1965 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1966 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1967 pump(&mut r, &mut batch);
1968 r.engine_mut().sink_mut().clear();
1969
1970 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1971 r.engine_mut().feed(conn, &wire(&[b"PUBLISH", b"a", b"w"]));
1972 pump(&mut r, &mut batch);
1973 assert_eq!(
1974 r.engine().sink().sent(conn),
1975 b"_\r\n:1\r\n>3\r\n$7\r\nmessage\r\n$1\r\na\r\n$1\r\nw\r\n"
1976 );
1977 }
1978
1979 #[test]
1982 fn a_write_reaches_a_keyspace_subscriber() {
1983 let (mut r, sub, mut batch) = engine();
1984 let writer = r.engine_mut().accept();
1985
1986 r.engine_mut().feed(
1987 writer,
1988 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"KEA"]),
1989 );
1990 r.engine_mut()
1991 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1992 pump(&mut r, &mut batch);
1993 r.engine_mut().sink_mut().clear();
1994
1995 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1996 pump(&mut r, &mut batch);
1997 assert_eq!(r.engine().sink().sent(writer), b"+OK\r\n");
1998 assert_eq!(
1999 r.engine().sink().sent(sub),
2000 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
2001 $16\r\n__keyspace@0__:k\r\n$3\r\nset\r\n\
2002 *4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
2003 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n"
2004 );
2005 }
2006
2007 #[test]
2010 fn a_write_says_nothing_until_the_setting_turns_it_on() {
2011 let (mut r, sub, mut batch) = engine();
2012 let writer = r.engine_mut().accept();
2013
2014 r.engine_mut()
2015 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
2016 pump(&mut r, &mut batch);
2017 r.engine_mut().sink_mut().clear();
2018
2019 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2020 pump(&mut r, &mut batch);
2021 assert_eq!(r.engine().sink().sent(sub), b"");
2022 }
2023
2024 #[test]
2027 fn only_the_classes_that_were_asked_for_are_published() {
2028 let (mut r, sub, mut batch) = engine();
2029 let writer = r.engine_mut().accept();
2030
2031 r.engine_mut().feed(
2032 writer,
2033 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"Eg"]),
2034 );
2035 r.engine_mut()
2036 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
2037 pump(&mut r, &mut batch);
2038 r.engine_mut().sink_mut().clear();
2039
2040 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2041 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
2042 pump(&mut r, &mut batch);
2043 assert_eq!(
2044 r.engine().sink().sent(sub),
2045 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
2046 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
2047 );
2048 }
2049
2050 #[test]
2053 fn a_write_with_a_deadline_on_it_says_two_things() {
2054 let (mut r, sub, mut batch) = engine();
2055 let writer = r.engine_mut().accept();
2056
2057 r.engine_mut().feed(
2058 writer,
2059 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
2060 );
2061 r.engine_mut()
2062 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2063 pump(&mut r, &mut batch);
2064 r.engine_mut().sink_mut().clear();
2065
2066 r.engine_mut()
2067 .feed(writer, &wire(&[b"SETEX", b"k", b"100", b"v"]));
2068 pump(&mut r, &mut batch);
2069 assert_eq!(
2070 r.engine().sink().sent(sub),
2071 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2072 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
2073 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2074 $21\r\n__keyevent@0__:expire\r\n$1\r\nk\r\n"
2075 );
2076 }
2077
2078 fn watching() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2084 watching_flags(b"EA")
2085 }
2086
2087 fn watching_flags(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2089 let (mut r, sub, mut batch) = engine();
2090 let writer = r.engine_mut().accept();
2091 r.engine_mut().feed(
2092 writer,
2093 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
2094 );
2095 r.engine_mut()
2096 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2097 pump(&mut r, &mut batch);
2098 r.engine_mut().sink_mut().clear();
2099 (r, sub, writer, batch)
2100 }
2101
2102 fn fired(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
2108 fired_on(r, sub, 0)
2109 }
2110
2111 fn fired_on(r: &Reactor<Wire<Recorder>>, sub: ConnId, db: usize) -> Vec<(String, String)> {
2114 let head = format!("__keyevent@{db}__:");
2115 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
2116 let mut out = Vec::new();
2117 let mut parts = sent.split("\r\n");
2118 while let Some(p) = parts.next() {
2119 let Some(event) = p.strip_prefix(head.as_str()) else {
2120 continue;
2121 };
2122 if event == "*" {
2125 continue;
2126 }
2127 parts.next();
2128 let key = parts.next().unwrap_or_default();
2129 out.push((event.to_owned(), key.to_owned()));
2130 }
2131 out
2132 }
2133
2134 #[test]
2137 fn taking_the_last_of_a_collection_says_the_key_went_with_it() {
2138 let (mut r, sub, writer, mut batch) = watching();
2139
2140 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"k", b"a"]));
2141 r.engine_mut().feed(writer, &wire(&[b"LPOP", b"k"]));
2142 pump(&mut r, &mut batch);
2143 assert_eq!(
2144 fired(&r, sub),
2145 [("rpush", "k"), ("lpop", "k"), ("del", "k")]
2146 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2147 );
2148 }
2149
2150 #[test]
2153 fn a_move_onto_a_member_already_there_says_only_the_removal() {
2154 let (mut r, sub, writer, mut batch) = watching();
2155
2156 r.engine_mut().feed(writer, &wire(&[b"SADD", b"a", b"m"]));
2157 r.engine_mut()
2158 .feed(writer, &wire(&[b"SADD", b"b", b"m", b"n"]));
2159 pump(&mut r, &mut batch);
2160 r.engine_mut().sink_mut().clear();
2161
2162 r.engine_mut()
2163 .feed(writer, &wire(&[b"SMOVE", b"a", b"b", b"m"]));
2164 pump(&mut r, &mut batch);
2165 assert_eq!(
2166 fired(&r, sub),
2167 [("srem", "a"), ("del", "a")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2168 );
2169 }
2170
2171 #[test]
2174 fn a_score_that_did_not_move_says_nothing() {
2175 let (mut r, sub, writer, mut batch) = watching();
2176
2177 r.engine_mut()
2178 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2179 pump(&mut r, &mut batch);
2180 r.engine_mut().sink_mut().clear();
2181
2182 r.engine_mut()
2183 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2184 r.engine_mut()
2185 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"0", b"m"]));
2186 pump(&mut r, &mut batch);
2187 assert_eq!(fired(&r, sub), []);
2188
2189 r.engine_mut()
2192 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"1", b"m"]));
2193 pump(&mut r, &mut batch);
2194 assert_eq!(fired(&r, sub), [("zincr".to_owned(), "z".to_owned())]);
2195 }
2196
2197 #[test]
2200 fn a_stream_write_says_what_the_trim_behind_it_took() {
2201 let (mut r, sub, writer, mut batch) = watching();
2202
2203 r.engine_mut()
2204 .feed(writer, &wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]));
2205 r.engine_mut().feed(
2206 writer,
2207 &wire(&[b"XADD", b"s", b"MAXLEN", b"9", b"2-1", b"f", b"v"]),
2208 );
2209 r.engine_mut().feed(
2210 writer,
2211 &wire(&[b"XADD", b"s", b"MAXLEN", b"1", b"3-1", b"f", b"v"]),
2212 );
2213 pump(&mut r, &mut batch);
2214 assert_eq!(
2215 fired(&r, sub),
2216 [("xadd", "s"), ("xadd", "s"), ("xadd", "s"), ("xtrim", "s")]
2217 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2218 );
2219 }
2220
2221 #[test]
2225 fn acknowledging_an_entry_that_is_already_gone_says_nothing() {
2226 let (mut r, sub, writer, mut batch) = watching();
2227
2228 for cmd in [
2229 wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]),
2230 wire(&[b"XGROUP", b"CREATE", b"s", b"g", b"0"]),
2231 wire(&[b"XREADGROUP", b"GROUP", b"g", b"c", b"STREAMS", b"s", b">"]),
2232 wire(&[b"XDEL", b"s", b"1-1"]),
2233 ] {
2234 r.engine_mut().feed(writer, &cmd);
2235 }
2236 pump(&mut r, &mut batch);
2237 r.engine_mut().sink_mut().clear();
2238
2239 r.engine_mut().feed(
2240 writer,
2241 &wire(&[b"XACKDEL", b"s", b"g", b"IDS", b"1", b"1-1"]),
2242 );
2243 pump(&mut r, &mut batch);
2244 assert_eq!(fired(&r, sub), []);
2245 }
2246
2247 #[test]
2250 fn emptying_a_hash_says_the_key_went_with_the_last_field() {
2251 let (mut r, sub, writer, mut batch) = watching();
2252
2253 r.engine_mut()
2254 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2255 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"a"]));
2256 r.engine_mut()
2259 .feed(writer, &wire(&[b"HDEL", b"h", b"b", b"a"]));
2260 pump(&mut r, &mut batch);
2261 assert_eq!(
2262 fired(&r, sub),
2263 [("hset", "h"), ("hdel", "h"), ("hdel", "h"), ("del", "h")]
2264 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2265 );
2266 }
2267
2268 #[test]
2271 fn a_field_deadline_already_past_reads_as_a_removal() {
2272 let (mut r, sub, writer, mut batch) = watching();
2273
2274 r.engine_mut()
2275 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2276 pump(&mut r, &mut batch);
2277 r.engine_mut().sink_mut().clear();
2278
2279 r.engine_mut().feed(
2280 writer,
2281 &wire(&[b"HEXPIRE", b"h", b"0", b"FIELDS", b"1", b"a"]),
2282 );
2283 r.engine_mut().feed(
2284 writer,
2285 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"b"]),
2286 );
2287 pump(&mut r, &mut batch);
2288 assert_eq!(
2289 fired(&r, sub),
2290 [("hdel", "h"), ("hexpire", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2291 );
2292 }
2293
2294 #[test]
2297 fn a_write_under_a_deadline_already_gone_says_the_write_first() {
2298 let (mut r, sub, writer, mut batch) = watching();
2299
2300 r.engine_mut().feed(
2301 writer,
2302 &wire(&[b"HSETEX", b"h", b"EXAT", b"1", b"FIELDS", b"1", b"a", b"1"]),
2303 );
2304 pump(&mut r, &mut batch);
2305 assert_eq!(
2306 fired(&r, sub),
2307 [("hset", "h"), ("hdel", "h"), ("del", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2308 );
2309 }
2310
2311 #[test]
2314 fn clearing_a_deadline_that_was_never_set_says_nothing() {
2315 let (mut r, sub, writer, mut batch) = watching();
2316
2317 r.engine_mut()
2318 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2319 r.engine_mut().feed(
2320 writer,
2321 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"a"]),
2322 );
2323 pump(&mut r, &mut batch);
2324 r.engine_mut().sink_mut().clear();
2325
2326 r.engine_mut()
2327 .feed(writer, &wire(&[b"HPERSIST", b"h", b"FIELDS", b"1", b"b"]));
2328 r.engine_mut().feed(
2329 writer,
2330 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"1", b"b"]),
2331 );
2332 pump(&mut r, &mut batch);
2333 assert_eq!(fired(&r, sub), []);
2334
2335 r.engine_mut().feed(
2338 writer,
2339 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"2", b"a", b"b"]),
2340 );
2341 pump(&mut r, &mut batch);
2342 assert_eq!(fired(&r, sub), [("hpersist".to_owned(), "h".to_owned())]);
2343 }
2344
2345 #[test]
2348 fn a_key_that_was_not_there_before_says_so() {
2349 let (mut r, sub, writer, mut batch) = watching_flags(b"En");
2350
2351 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2352 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2353 r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"x"]));
2354 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2355 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2356 pump(&mut r, &mut batch);
2357 assert_eq!(
2358 fired(&r, sub),
2359 [("new", "k"), ("new", "l")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2360 );
2361 }
2362
2363 #[test]
2366 fn the_news_of_a_new_key_comes_before_the_write_that_made_it() {
2367 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2368
2369 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2370 r.engine_mut().feed(writer, &wire(&[b"SET", b"b", b"2"]));
2371 pump(&mut r, &mut batch);
2372 r.engine_mut().sink_mut().clear();
2373
2374 r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2378 pump(&mut r, &mut batch);
2379 assert_eq!(
2380 fired(&r, sub),
2381 [("new", "b"), ("rename_from", "a"), ("rename_to", "b")]
2382 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2383 );
2384 }
2385
2386 #[test]
2390 fn writing_over_a_destination_is_not_a_key_arriving() {
2391 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2392
2393 r.engine_mut()
2394 .feed(writer, &wire(&[b"RPUSH", b"l", b"c", b"a", b"b"]));
2395 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"d", b"x"]));
2396 pump(&mut r, &mut batch);
2397 r.engine_mut().sink_mut().clear();
2398
2399 r.engine_mut()
2400 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2401 pump(&mut r, &mut batch);
2402 assert_eq!(fired(&r, sub), [("sortstore".to_owned(), "d".to_owned())]);
2403 r.engine_mut().sink_mut().clear();
2404
2405 r.engine_mut().feed(writer, &wire(&[b"DEL", b"d"]));
2408 r.engine_mut()
2409 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2410 pump(&mut r, &mut batch);
2411 assert_eq!(
2412 fired(&r, sub),
2413 [("del", "d"), ("new", "d"), ("sortstore", "d")]
2414 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2415 );
2416 }
2417
2418 #[test]
2421 fn replacing_a_value_says_what_went_and_whether_the_kind_changed() {
2422 let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2423
2424 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2425 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2426 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2427 r.engine_mut().feed(writer, &wire(&[b"SET", b"l", b"v"]));
2428 pump(&mut r, &mut batch);
2429 assert_eq!(
2430 fired(&r, sub),
2431 [
2432 ("overwritten", "k"),
2433 ("overwritten", "l"),
2434 ("type_changed", "l")
2435 ]
2436 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2437 );
2438 }
2439
2440 #[test]
2443 fn a_write_that_changes_part_of_a_value_has_not_replaced_it() {
2444 let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2445
2446 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"1"]));
2447 r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"2"]));
2448 r.engine_mut().feed(writer, &wire(&[b"INCR", b"k"]));
2449 r.engine_mut()
2450 .feed(writer, &wire(&[b"SETRANGE", b"k", b"0", b"9"]));
2451 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2452 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2453 pump(&mut r, &mut batch);
2454 assert_eq!(fired(&r, sub), []);
2455 }
2456
2457 #[test]
2461 fn a_rename_says_what_it_replaced_after_saying_what_it_did() {
2462 let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2463
2464 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2465 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"b", b"x"]));
2466 pump(&mut r, &mut batch);
2467 r.engine_mut().sink_mut().clear();
2468
2469 r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2470 pump(&mut r, &mut batch);
2471 assert_eq!(
2472 fired(&r, sub),
2473 [
2474 ("new", "b"),
2475 ("rename_from", "a"),
2476 ("rename_to", "b"),
2477 ("overwritten", "b"),
2478 ("type_changed", "b")
2479 ]
2480 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2481 );
2482 }
2483
2484 #[test]
2487 fn a_store_form_says_what_it_replaced_before_saying_what_it_did() {
2488 let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2489
2490 r.engine_mut().feed(writer, &wire(&[b"SADD", b"s", b"m"]));
2491 r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"q"]));
2492 pump(&mut r, &mut batch);
2493 r.engine_mut().sink_mut().clear();
2494
2495 r.engine_mut()
2496 .feed(writer, &wire(&[b"SINTERSTORE", b"d", b"s"]));
2497 pump(&mut r, &mut batch);
2498 assert_eq!(
2499 fired(&r, sub),
2500 [
2501 ("overwritten", "d"),
2502 ("type_changed", "d"),
2503 ("sinterstore", "d")
2504 ]
2505 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2506 );
2507 }
2508
2509 #[test]
2512 fn a_bit_write_that_left_the_value_alone_says_nothing() {
2513 let (mut r, sub, writer, mut batch) = watching();
2514
2515 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2519 pump(&mut r, &mut batch);
2520 r.engine_mut().sink_mut().clear();
2521
2522 r.engine_mut()
2523 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"1"]));
2524 r.engine_mut()
2525 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2526 r.engine_mut()
2527 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2528 r.engine_mut()
2532 .feed(writer, &wire(&[b"SETBIT", b"k", b"100", b"0"]));
2533 pump(&mut r, &mut batch);
2534 assert_eq!(
2535 fired(&r, sub),
2536 [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2537 );
2538 }
2539
2540 #[test]
2543 fn a_bitfield_that_wrote_the_same_values_back_says_nothing() {
2544 let (mut r, sub, writer, mut batch) = watching();
2545
2546 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2547 pump(&mut r, &mut batch);
2548 r.engine_mut().sink_mut().clear();
2549
2550 r.engine_mut().feed(
2552 writer,
2553 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"97"]),
2554 );
2555 r.engine_mut()
2556 .feed(writer, &wire(&[b"BITFIELD", b"k", b"GET", b"u8", b"0"]));
2557 r.engine_mut().feed(
2558 writer,
2559 &wire(&[b"BITFIELD", b"k", b"INCRBY", b"u8", b"0", b"0"]),
2560 );
2561 pump(&mut r, &mut batch);
2562 assert_eq!(fired(&r, sub), []);
2563
2564 r.engine_mut().feed(
2567 writer,
2568 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"98"]),
2569 );
2570 r.engine_mut().feed(
2571 writer,
2572 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"800", b"0"]),
2573 );
2574 pump(&mut r, &mut batch);
2575 assert_eq!(
2576 fired(&r, sub),
2577 [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2578 );
2579 }
2580
2581 #[test]
2584 fn the_sketch_commands_say_what_a_mass_add_says() {
2585 let (mut r, sub, writer, mut batch) = watching();
2586
2587 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2588 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2590 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h"]));
2592 r.engine_mut().feed(writer, &wire(&[b"PFMERGE", b"d"]));
2594 r.engine_mut()
2595 .feed(writer, &wire(&[b"PFMERGE", b"d", b"h"]));
2596 pump(&mut r, &mut batch);
2597 assert_eq!(
2598 fired(&r, sub),
2599 [("pfadd", "h"), ("pfadd", "d"), ("pfadd", "d")]
2600 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2601 );
2602 }
2603
2604 #[test]
2607 fn the_geo_commands_say_what_the_sorted_set_under_them_did() {
2608 let (mut r, sub, writer, mut batch) = watching();
2609
2610 let point: &[&[u8]] = &[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"];
2611 r.engine_mut().feed(writer, &wire(point));
2612 r.engine_mut().feed(writer, &wire(point));
2614 r.engine_mut().feed(
2616 writer,
2617 &wire(&[b"GEOADD", b"g", b"14.0", b"38.115556", b"P"]),
2618 );
2619 r.engine_mut().feed(
2620 writer,
2621 &wire(&[
2622 b"GEORADIUS",
2623 b"g",
2624 b"14.0",
2625 b"38.0",
2626 b"200",
2627 b"km",
2628 b"STORE",
2629 b"d",
2630 ]),
2631 );
2632 r.engine_mut().feed(
2633 writer,
2634 &wire(&[
2635 b"GEOSEARCHSTORE",
2636 b"e",
2637 b"g",
2638 b"FROMLONLAT",
2639 b"14.0",
2640 b"38.0",
2641 b"BYRADIUS",
2642 b"200",
2643 b"km",
2644 ]),
2645 );
2646 pump(&mut r, &mut batch);
2647 assert_eq!(
2648 fired(&r, sub),
2649 [
2650 ("zadd", "g"),
2651 ("zadd", "g"),
2652 ("georadiusstore", "d"),
2653 ("geosearchstore", "e")
2654 ]
2655 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2656 );
2657 }
2658
2659 #[test]
2662 fn a_geo_store_that_found_nothing_takes_the_destination_with_it() {
2663 let (mut r, sub, writer, mut batch) = watching();
2664
2665 r.engine_mut().feed(
2666 writer,
2667 &wire(&[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"]),
2668 );
2669 r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"x"]));
2670 pump(&mut r, &mut batch);
2671 r.engine_mut().sink_mut().clear();
2672
2673 r.engine_mut().feed(
2674 writer,
2675 &wire(&[
2676 b"GEORADIUS",
2677 b"g",
2678 b"1.0",
2679 b"1.0",
2680 b"1",
2681 b"km",
2682 b"STORE",
2683 b"d",
2684 ]),
2685 );
2686 r.engine_mut().feed(
2689 writer,
2690 &wire(&[
2691 b"GEORADIUS",
2692 b"g",
2693 b"1.0",
2694 b"1.0",
2695 b"1",
2696 b"km",
2697 b"STORE",
2698 b"d",
2699 ]),
2700 );
2701 pump(&mut r, &mut batch);
2702 assert_eq!(
2703 fired(&r, sub),
2704 [("del", "d")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2705 );
2706 }
2707
2708 #[test]
2712 fn a_key_that_lands_on_another_database_is_new_over_there() {
2713 let (mut r, sub, mut batch) = engine();
2714 let writer = r.engine_mut().accept();
2715 r.engine_mut().feed(
2716 writer,
2717 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EAnoc"]),
2718 );
2719 r.engine_mut().feed(
2720 sub,
2721 &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*", b"__keyevent@1__:*"]),
2722 );
2723 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2724 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2725 pump(&mut r, &mut batch);
2726 r.engine_mut().sink_mut().clear();
2727
2728 r.engine_mut()
2729 .feed(writer, &wire(&[b"COPY", b"a", b"b", b"DB", b"1"]));
2730 r.engine_mut().feed(writer, &wire(&[b"MOVE", b"k", b"1"]));
2731 pump(&mut r, &mut batch);
2732 assert_eq!(
2733 fired_on(&r, sub, 1),
2734 [
2735 ("new", "b"),
2736 ("copy_to", "b"),
2737 ("new", "k"),
2738 ("move_to", "k")
2739 ]
2740 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2741 );
2742 assert_eq!(
2745 fired_on(&r, sub, 0),
2746 [("move_from", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2747 );
2748 }
2749
2750 #[test]
2756 fn a_read_that_found_nothing_says_which_key_it_was() {
2757 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2758
2759 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2760 r.engine_mut()
2761 .feed(writer, &wire(&[b"MGET", b"a", b"nk", b"nk"]));
2762 r.engine_mut()
2763 .feed(writer, &wire(&[b"EXISTS", b"nj", b"a"]));
2764 pump(&mut r, &mut batch);
2765 assert_eq!(
2766 fired(&r, sub),
2767 [("keymiss", "nk"), ("keymiss", "nk"), ("keymiss", "nj")]
2768 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2769 );
2770 }
2771
2772 #[test]
2775 fn only_the_shape_of_a_write_that_reads_says_it() {
2776 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2777
2778 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2781 r.engine_mut().feed(
2782 writer,
2783 &wire(&[b"BITFIELD", b"nk", b"SET", b"u8", b"0", b"1"]),
2784 );
2785 r.engine_mut().feed(writer, &wire(&[b"LPOP", b"nk"]));
2786 pump(&mut r, &mut batch);
2787 assert_eq!(fired(&r, sub), []);
2788
2789 r.engine_mut()
2791 .feed(writer, &wire(&[b"SET", b"nj", b"v", b"GET"]));
2792 r.engine_mut()
2793 .feed(writer, &wire(&[b"BITFIELD", b"nl", b"GET", b"u8", b"0"]));
2794 r.engine_mut().feed(writer, &wire(&[b"GETDEL", b"nm"]));
2795 pump(&mut r, &mut batch);
2796 assert_eq!(
2797 fired(&r, sub),
2798 [("keymiss", "nj"), ("keymiss", "nl"), ("keymiss", "nm")]
2799 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2800 );
2801 }
2802
2803 #[test]
2806 fn a_store_form_says_it_only_for_its_sources() {
2807 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2808
2809 r.engine_mut()
2810 .feed(writer, &wire(&[b"SINTERSTORE", b"dst", b"nk", b"nj"]));
2811 r.engine_mut()
2812 .feed(writer, &wire(&[b"ZUNIONSTORE", b"dst", b"1", b"nz"]));
2813 r.engine_mut()
2814 .feed(writer, &wire(&[b"ZRANGESTORE", b"dst", b"nz", b"0", b"-1"]));
2815 pump(&mut r, &mut batch);
2816 assert_eq!(
2817 fired(&r, sub),
2818 [
2819 ("keymiss", "nk"),
2820 ("keymiss", "nj"),
2821 ("keymiss", "nz"),
2822 ("keymiss", "nz")
2823 ]
2824 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2825 );
2826 }
2827
2828 #[test]
2832 fn the_stream_reads_say_it_for_the_keys_behind_the_keyword() {
2833 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2834
2835 r.engine_mut().feed(
2836 writer,
2837 &wire(&[b"XREAD", b"STREAMS", b"nk", b"nj", b"0", b"0"]),
2838 );
2839 pump(&mut r, &mut batch);
2840 assert_eq!(
2841 fired(&r, sub),
2842 [
2843 ("keymiss", "nk"),
2844 ("keymiss", "nj"),
2845 ("keymiss", "nk"),
2846 ("keymiss", "nj")
2847 ]
2848 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2849 );
2850 }
2851
2852 #[test]
2856 fn an_argument_that_did_not_parse_takes_the_miss_back() {
2857 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2858
2859 r.engine_mut()
2860 .feed(writer, &wire(&[b"GETRANGE", b"nk", b"x", b"-1"]));
2861 r.engine_mut()
2862 .feed(writer, &wire(&[b"LPOS", b"nk", b"a", b"RANK", b"0"]));
2863 pump(&mut r, &mut batch);
2864 assert_eq!(fired(&r, sub), []);
2865
2866 r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2870 pump(&mut r, &mut batch);
2871 r.engine_mut().sink_mut().clear();
2872
2873 r.engine_mut()
2874 .feed(writer, &wire(&[b"SINTER", b"nk", b"s"]));
2875 pump(&mut r, &mut batch);
2876 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2877 }
2878
2879 #[test]
2883 fn a_read_stops_missing_where_it_stops_looking() {
2884 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2885
2886 r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2887 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"x"]));
2888 pump(&mut r, &mut batch);
2889 r.engine_mut().sink_mut().clear();
2890
2891 r.engine_mut()
2892 .feed(writer, &wire(&[b"SINTER", b"s", b"nk"]));
2893 pump(&mut r, &mut batch);
2894 assert_eq!(fired(&r, sub), []);
2895
2896 r.engine_mut().feed(writer, &wire(&[b"MGET", b"l", b"nk"]));
2899 pump(&mut r, &mut batch);
2900 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2901 }
2902
2903 #[test]
2907 fn the_keys_a_sort_pattern_names_say_it_as_they_are_read() {
2908 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2909
2910 r.engine_mut()
2911 .feed(writer, &wire(&[b"RPUSH", b"l", b"1", b"2"]));
2912 r.engine_mut().feed(writer, &wire(&[b"SET", b"w_1", b"5"]));
2913 pump(&mut r, &mut batch);
2914 r.engine_mut().sink_mut().clear();
2915
2916 r.engine_mut().feed(
2917 writer,
2918 &wire(&[b"SORT", b"l", b"BY", b"w_*", b"GET", b"p_*"]),
2919 );
2920 pump(&mut r, &mut batch);
2921 assert_eq!(
2922 fired(&r, sub),
2923 [("keymiss", "w_2"), ("keymiss", "p_2"), ("keymiss", "p_1")]
2924 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2925 );
2926 }
2927
2928 #[test]
2932 fn a_deadline_that_passed_is_news_before_the_miss_it_causes() {
2933 let (mut r, sub, mut batch) = timed();
2934 let writer = r.engine_mut().accept();
2935 r.engine_mut().feed(
2936 writer,
2937 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EgAm"]),
2938 );
2939 r.engine_mut()
2940 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2941 r.engine_mut()
2942 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
2943 pump(&mut r, &mut batch);
2944 r.engine_mut().sink_mut().clear();
2945
2946 r.engine().server().advance_clock_ms(50);
2947 r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
2948 pump(&mut r, &mut batch);
2949 assert_eq!(
2950 fired(&r, sub),
2951 [("expired", "k"), ("keymiss", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2952 );
2953 }
2954
2955 #[test]
2958 fn a_module_read_says_it_the_way_a_core_read_does() {
2959 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2960
2961 r.engine_mut().feed(writer, &wire(&[b"JSON.GET", b"nk"]));
2962 r.engine_mut().feed(writer, &wire(&[b"TS.GET", b"nj"]));
2963 r.engine_mut()
2964 .feed(writer, &wire(&[b"BF.EXISTS", b"nl", b"x"]));
2965 r.engine_mut().feed(writer, &wire(&[b"TDIGEST.MIN", b"nm"]));
2966 r.engine_mut().feed(writer, &wire(&[b"TOPK.LIST", b"nn"]));
2967 r.engine_mut().feed(writer, &wire(&[b"CMS.INFO", b"no"]));
2968 r.engine_mut().feed(writer, &wire(&[b"VCARD", b"np"]));
2969 pump(&mut r, &mut batch);
2970 assert_eq!(
2971 fired(&r, sub),
2972 [
2973 ("keymiss", "nk"),
2974 ("keymiss", "nj"),
2975 ("keymiss", "nl"),
2976 ("keymiss", "nm"),
2977 ("keymiss", "nn"),
2978 ("keymiss", "no"),
2979 ("keymiss", "np")
2980 ]
2981 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2982 );
2983
2984 r.engine_mut().sink_mut().clear();
2987 r.engine_mut()
2988 .feed(writer, &wire(&[b"JSON.MGET", b"nk", b"nj", b"$"]));
2989 pump(&mut r, &mut batch);
2990 assert_eq!(
2991 fired(&r, sub),
2992 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2993 );
2994 }
2995
2996 #[test]
3000 fn the_quiet_module_commands_stay_quiet() {
3001 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
3002
3003 r.engine_mut()
3004 .feed(writer, &wire(&[b"JSON.SET", b"nk", b"$", b"1"]));
3005 r.engine_mut()
3006 .feed(writer, &wire(&[b"BF.ADD", b"nj", b"x"]));
3007 r.engine_mut()
3008 .feed(writer, &wire(&[b"TS.ADD", b"nl", b"1000", b"1"]));
3009 r.engine_mut().feed(writer, &wire(&[b"TS.INFO", b"nm"]));
3010 r.engine_mut().feed(writer, &wire(&[b"CF.COMPACT", b"nn"]));
3011 r.engine_mut()
3012 .feed(writer, &wire(&[b"JSON.DEBUG", b"HELP"]));
3013 r.engine_mut()
3014 .feed(writer, &wire(&[b"FT.GET", b"ni", b"no"]));
3015 r.engine_mut()
3016 .feed(writer, &wire(&[b"FT.SEARCH", b"ni", b"*"]));
3017 pump(&mut r, &mut batch);
3018 assert_eq!(fired(&r, sub), []);
3019
3020 r.engine_mut()
3022 .feed(writer, &wire(&[b"JSON.DEBUG", b"MEMORY", b"np"]));
3023 r.engine_mut()
3024 .feed(writer, &wire(&[b"FT.SUGGET", b"nq", b"x"]));
3025 r.engine_mut().feed(writer, &wire(&[b"FT.SUGLEN", b"nr"]));
3026 pump(&mut r, &mut batch);
3027 assert_eq!(
3028 fired(&r, sub),
3029 [("keymiss", "np"), ("keymiss", "nq"), ("keymiss", "nr")]
3030 .map(|(e, k)| (e.to_owned(), k.to_owned()))
3031 );
3032 }
3033
3034 #[test]
3041 fn a_module_read_keeps_the_miss_a_later_argument_spoiled() {
3042 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
3043
3044 r.engine_mut()
3045 .feed(writer, &wire(&[b"JSON.GET", b"nk", b"$..["]));
3046 r.engine_mut().feed(
3047 writer,
3048 &wire(&[b"VSIM", b"nj", b"ELE", b"e", b"COUNT", b"x"]),
3049 );
3050 pump(&mut r, &mut batch);
3051 assert_eq!(
3052 fired(&r, sub),
3053 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3054 );
3055 }
3056
3057 #[test]
3060 fn the_module_merges_stop_at_the_first_empty_source() {
3061 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
3062
3063 r.engine_mut().feed(
3064 writer,
3065 &wire(&[b"TDIGEST.MERGE", b"nk", b"2", b"nj", b"nl"]),
3066 );
3067 pump(&mut r, &mut batch);
3068 assert_eq!(
3069 fired(&r, sub),
3070 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3071 );
3072
3073 r.engine_mut().sink_mut().clear();
3077 r.engine_mut()
3078 .feed(writer, &wire(&[b"CMS.MERGE", b"nk", b"1", b"nj"]));
3079 pump(&mut r, &mut batch);
3080 assert_eq!(fired(&r, sub), []);
3081
3082 r.engine_mut()
3085 .feed(writer, &wire(&[b"CMS.INITBYDIM", b"cm", b"100", b"5"]));
3086 pump(&mut r, &mut batch);
3087 r.engine_mut().sink_mut().clear();
3088
3089 r.engine_mut()
3090 .feed(writer, &wire(&[b"CMS.MERGE", b"cm", b"2", b"nj", b"nl"]));
3091 pump(&mut r, &mut batch);
3092 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nj".to_owned())]);
3093 }
3094
3095 fn watching_fields(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3101 let (mut r, sub, mut batch) = engine();
3102 let writer = r.engine_mut().accept();
3103 r.engine_mut().feed(
3104 writer,
3105 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
3106 );
3107 r.engine_mut()
3108 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__subkey*@0__:*"]));
3109 pump(&mut r, &mut batch);
3110 r.engine_mut().sink_mut().clear();
3111 (r, sub, writer, batch)
3112 }
3113
3114 fn carried(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
3120 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
3121 let mut out = Vec::new();
3122 let mut parts = sent.split("\r\n");
3123 while let Some(p) = parts.next() {
3124 if p != "pmessage" {
3125 continue;
3126 }
3127 let mut next = || {
3130 parts.next();
3131 parts.next().unwrap_or_default().to_owned()
3132 };
3133 next();
3134 let channel = next();
3135 out.push((channel, next()));
3136 }
3137 out
3138 }
3139
3140 #[test]
3144 fn the_subkey_channels_carry_the_fields_an_event_touched() {
3145 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3146
3147 r.engine_mut()
3148 .feed(writer, &wire(&[b"HSET", b"h", b"a,b", b"1", b"c", b"2"]));
3149 pump(&mut r, &mut batch);
3150 assert_eq!(
3151 carried(&r, sub),
3152 [
3153 ("__subkeyspace@0__:h", "hset|3:a,b,1:c"),
3154 ("__subkeyevent@0__:hset", "1:h|3:a,b,1:c"),
3155 ("__subkeyspaceitem@0__:h\na,b", "hset"),
3156 ("__subkeyspaceitem@0__:h\nc", "hset"),
3157 ("__subkeyspaceevent@0__:hset|h", "3:a,b,1:c"),
3158 ]
3159 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3160 );
3161 }
3162
3163 #[test]
3167 fn a_key_holding_a_newline_skips_the_per_field_channel() {
3168 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3169
3170 r.engine_mut()
3171 .feed(writer, &wire(&[b"HSET", b"h\nx", b"f", b"1"]));
3172 pump(&mut r, &mut batch);
3173 assert_eq!(
3174 carried(&r, sub),
3175 [
3176 ("__subkeyspace@0__:h\nx", "hset|1:f"),
3177 ("__subkeyevent@0__:hset", "3:h\nx|1:f"),
3178 ("__subkeyspaceevent@0__:hset|h\nx", "1:f"),
3179 ]
3180 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3181 );
3182 }
3183
3184 #[test]
3188 fn an_event_with_no_fields_stays_off_the_subkey_channels() {
3189 let (mut r, sub, writer, mut batch) = watching_fields(b"AS");
3190
3191 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3192 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
3193 r.engine_mut()
3194 .feed(writer, &wire(&[b"HSET", b"h", b"f", b"1"]));
3195 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"f"]));
3196 pump(&mut r, &mut batch);
3197 assert_eq!(
3198 carried(&r, sub),
3199 [
3200 ("__subkeyspace@0__:h", "hset|1:f"),
3201 ("__subkeyspace@0__:h", "hdel|1:f"),
3202 ]
3203 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3204 );
3205 }
3206
3207 fn watching_clock() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3213 let (mut r, sub, mut batch) = timed();
3214 let writer = r.engine_mut().accept();
3215 r.engine_mut().feed(
3216 writer,
3217 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3218 );
3219 r.engine_mut()
3220 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3221 pump(&mut r, &mut batch);
3222 r.engine_mut().sink_mut().clear();
3223 (r, sub, writer, batch)
3224 }
3225
3226 #[test]
3230 fn a_deadline_that_passed_is_news_when_a_reader_finds_it() {
3231 let (mut r, sub, writer, mut batch) = watching_clock();
3232
3233 r.engine_mut()
3234 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3235 pump(&mut r, &mut batch);
3236 r.engine_mut().sink_mut().clear();
3237
3238 r.engine().server().advance_clock_ms(50);
3239 r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
3240 pump(&mut r, &mut batch);
3241 assert_eq!(
3242 fired(&r, sub),
3243 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned())),
3244 "and not a del alongside it, which is a different piece of news"
3245 );
3246 }
3247
3248 #[test]
3256 fn a_deadline_that_passed_is_news_with_nobody_reading() {
3257 let (mut r, sub, writer, mut batch) = watching_clock();
3258
3259 r.engine_mut()
3260 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3261 pump(&mut r, &mut batch);
3262 r.engine_mut().sink_mut().clear();
3263
3264 r.engine().server().advance_clock_ms(50);
3265 pump(&mut r, &mut batch);
3267 assert_eq!(
3268 fired(&r, sub),
3269 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3270 );
3271
3272 r.engine_mut().sink_mut().clear();
3273 pump(&mut r, &mut batch);
3274 assert!(fired(&r, sub).is_empty(), "and it only goes once");
3275 }
3276
3277 #[test]
3281 fn a_key_a_limit_took_says_it_was_evicted() {
3282 let (mut r, sub, writer, mut batch) = watching();
3283
3284 let val = vec![b'v'; 256];
3285 for i in 0..2000u32 {
3286 let k = format!("key:{i:08}");
3287 r.engine_mut()
3288 .feed(writer, &wire(&[b"SET", k.as_bytes(), &val]));
3289 }
3290 pump(&mut r, &mut batch);
3291 r.engine().server().refresh_memory();
3292 let full = r.engine().server().memory_bytes();
3293 r.engine_mut().sink_mut().clear();
3294
3295 let limit = (full / 2).to_string();
3298 r.engine_mut().feed(
3299 writer,
3300 &wire(&[b"CONFIG", b"SET", b"maxmemory-policy", b"allkeys-random"]),
3301 );
3302 r.engine_mut().feed(
3303 writer,
3304 &wire(&[b"CONFIG", b"SET", b"maxmemory", limit.as_bytes()]),
3305 );
3306 r.engine_mut()
3307 .feed(writer, &wire(&[b"SET", b"newcomer", &val]));
3308 pump(&mut r, &mut batch);
3309
3310 let events = fired(&r, sub);
3311 assert!(
3312 events.iter().any(|(e, _)| e == "evicted"),
3313 "the write made room and never said so: {events:?}"
3314 );
3315 assert!(
3316 events
3317 .iter()
3318 .all(|(e, k)| e != "evicted" || k != "newcomer"),
3319 "the key the write was for is the one key it cannot have taken"
3320 );
3321 }
3322
3323 #[test]
3326 fn a_transaction_publishes_between_its_commands_and_not_after_them() {
3327 let (mut r, sub, mut batch) = engine();
3328 let writer = r.engine_mut().accept();
3329
3330 r.engine_mut().feed(
3331 writer,
3332 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3333 );
3334 r.engine_mut()
3335 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3336 pump(&mut r, &mut batch);
3337 r.engine_mut().sink_mut().clear();
3338
3339 r.engine_mut().feed(writer, &wire(&[b"MULTI"]));
3340 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3341 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
3342 r.engine_mut().feed(writer, &wire(&[b"EXEC"]));
3343 pump(&mut r, &mut batch);
3344 assert_eq!(
3345 r.engine().sink().sent(sub),
3346 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3347 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
3348 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3349 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
3350 );
3351 }
3352
3353 #[test]
3354 fn a_reply_the_socket_would_not_take_is_offered_again() {
3355 let mut r = Reactor::inline(Wire::new(Trickle::default()));
3356 let conn = r.engine_mut().accept();
3357 let mut batch = Vec::new();
3358
3359 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3360 pump(&mut r, &mut batch);
3361 assert_eq!(r.engine().sink().sent, b"+PONG\r\n");
3363 assert_eq!(r.engine().sink().writes, 2);
3364 }
3365 #[test]
3369 fn client_reply_skip_covers_the_command_after_it_and_nothing_else() {
3370 let (mut r, conn, mut batch) = engine();
3371
3372 r.engine_mut()
3373 .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"SKIP"]));
3374 r.engine_mut().feed(conn, &wire(&[b"SET", b"a", b"1"]));
3375 r.engine_mut().feed(conn, &wire(&[b"SET", b"b", b"2"]));
3376 pump(&mut r, &mut batch);
3377 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
3380 }
3381
3382 #[test]
3383 fn client_reply_off_stays_off_until_it_is_turned_back_on() {
3384 let (mut r, conn, mut batch) = engine();
3385
3386 r.engine_mut()
3387 .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"OFF"]));
3388 r.engine_mut().feed(conn, &wire(&[b"SET", b"c", b"3"]));
3389 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3390 r.engine_mut()
3391 .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"ON"]));
3392 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3393 pump(&mut r, &mut batch);
3394 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n+PONG\r\n");
3397
3398 r.engine_mut().sink_mut().clear();
3400 r.engine_mut().feed(conn, &wire(&[b"GET", b"c"]));
3401 pump(&mut r, &mut batch);
3402 assert_eq!(r.engine().sink().sent(conn), b"$1\r\n3\r\n");
3403 }
3404
3405 #[test]
3408 fn a_connection_reports_the_socket_it_was_opened_on() {
3409 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3410 let conn = r
3411 .engine_mut()
3412 .accept_from("10.0.0.7:54321", "10.0.0.1:6379", 11, false);
3413 let mut batch = Vec::new();
3414
3415 r.engine_mut().feed(conn, &wire(&[b"CLIENT", b"INFO"]));
3416 pump(&mut r, &mut batch);
3417 let sent = String::from_utf8_lossy(r.engine().sink().sent(conn)).into_owned();
3418 assert!(sent.contains("addr=10.0.0.7:54321"), "{sent}");
3419 assert!(sent.contains("laddr=10.0.0.1:6379"), "{sent}");
3420 assert!(sent.contains("fd=11"), "{sent}");
3421 }
3422
3423 #[test]
3426 fn a_connection_counts_the_bytes_and_the_commands_that_went_over_it() {
3427 let (mut r, conn, mut batch) = engine();
3428 let mut stream = wire(&[b"PING"]);
3429 stream.extend(wire(&[b"PING"]));
3430 let sent_in = stream.len();
3431
3432 r.engine_mut().feed(conn, &stream);
3433 pump(&mut r, &mut batch);
3434 r.engine_mut().sink_mut().clear();
3435
3436 r.engine_mut().feed(conn, &wire(&[b"CLIENT", b"INFO"]));
3437 pump(&mut r, &mut batch);
3438 let sent = String::from_utf8_lossy(r.engine().sink().sent(conn)).into_owned();
3439 assert!(sent.contains("tot-cmds=2"), "{sent}");
3443 assert!(sent.contains("read-events=2"), "{sent}");
3444 assert!(
3445 sent.contains(&format!("tot-net-in={}", sent_in + 26)),
3446 "{sent}"
3447 );
3448 assert!(sent.contains("tot-net-out=14"), "{sent}");
3449 }
3450
3451 #[test]
3455 fn client_list_reports_every_connection_and_not_just_the_one_asking() {
3456 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3457 let one = r
3458 .engine_mut()
3459 .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3460 let two = r
3461 .engine_mut()
3462 .accept_from("10.0.0.8:2222", "10.0.0.1:6379", 12, false);
3463 let mut batch = Vec::new();
3464
3465 r.engine_mut()
3466 .feed(two, &wire(&[b"CLIENT", b"SETNAME", b"worker"]));
3467 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3468 pump(&mut r, &mut batch);
3469
3470 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3471 let lines: Vec<&str> = sent.lines().filter(|l| l.starts_with("id=")).collect();
3472 assert_eq!(lines.len(), 2, "{sent}");
3473 assert!(lines[0].contains("addr=10.0.0.7:1111"), "{sent}");
3474 assert!(lines[0].contains("cmd=client|list"), "{sent}");
3475 assert!(lines[1].contains("addr=10.0.0.8:2222"), "{sent}");
3476 assert!(lines[1].contains("name=worker"), "{sent}");
3477 assert!(lines[1].contains("cmd=client|setname"), "{sent}");
3478 }
3479
3480 #[test]
3483 fn client_list_keeps_the_order_the_connections_were_opened_in() {
3484 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3485 let one = r.engine_mut().accept();
3486 let two = r.engine_mut().accept();
3487 let three = r.engine_mut().accept();
3488 let mut batch = Vec::new();
3489
3490 r.engine_mut().hangup(two);
3491 r.engine_mut().feed(three, &wire(&[b"CLIENT", b"LIST"]));
3492 pump(&mut r, &mut batch);
3493
3494 let sent = String::from_utf8_lossy(r.engine().sink().sent(three)).into_owned();
3495 let ids: Vec<&str> = sent
3496 .lines()
3497 .filter(|l| l.starts_with("id="))
3498 .map(|l| l.split(' ').next().unwrap_or(""))
3499 .collect();
3500 assert_eq!(ids, vec!["id=1", "id=3"], "{sent}");
3501 let _ = one;
3502 }
3503
3504 #[test]
3508 fn client_kill_closes_the_connection_it_names_and_answers_a_count() {
3509 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3510 let one = r
3511 .engine_mut()
3512 .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3513 let two = r
3514 .engine_mut()
3515 .accept_from("10.0.0.8:2222", "10.0.0.1:6379", 12, false);
3516 let mut batch = Vec::new();
3517
3518 r.engine_mut()
3519 .feed(one, &wire(&[b"CLIENT", b"KILL", b"ADDR", b"10.0.0.8:2222"]));
3520 pump(&mut r, &mut batch);
3521
3522 assert_eq!(r.engine().sink().sent(one), b":1\r\n");
3523 assert!(r.engine().sink().was_closed(two), "the named one went away");
3524 assert!(!r.engine().sink().was_closed(one), "the caller did not");
3525 }
3526
3527 #[test]
3530 fn the_old_kill_takes_one_address_and_will_take_the_caller() {
3531 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3532 let one = r
3533 .engine_mut()
3534 .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3535 let mut batch = Vec::new();
3536
3537 r.engine_mut()
3538 .feed(one, &wire(&[b"CLIENT", b"KILL", b"10.0.0.9:9999"]));
3539 pump(&mut r, &mut batch);
3540 assert_eq!(r.engine().sink().sent(one), b"-ERR No such client\r\n");
3541
3542 r.engine_mut().sink_mut().clear();
3543 r.engine_mut()
3544 .feed(one, &wire(&[b"CLIENT", b"KILL", b"10.0.0.7:1111"]));
3545 pump(&mut r, &mut batch);
3546 assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
3547 assert!(r.engine().sink().was_closed(one), "it took itself");
3548 }
3549
3550 #[test]
3553 fn a_kill_spares_the_caller_unless_it_is_told_not_to() {
3554 let (mut r, conn, mut batch) = engine();
3555 r.engine_mut()
3556 .feed(conn, &wire(&[b"CLIENT", b"KILL", b"TYPE", b"normal"]));
3557 pump(&mut r, &mut batch);
3558 assert_eq!(r.engine().sink().sent(conn), b":0\r\n");
3559 assert!(!r.engine().sink().was_closed(conn));
3560
3561 r.engine_mut().sink_mut().clear();
3562 r.engine_mut().feed(
3563 conn,
3564 &wire(&[b"CLIENT", b"KILL", b"TYPE", b"normal", b"SKIPME", b"no"]),
3565 );
3566 pump(&mut r, &mut batch);
3567 assert_eq!(r.engine().sink().sent(conn), b":1\r\n");
3568 assert!(r.engine().sink().was_closed(conn));
3569 }
3570
3571 #[test]
3574 fn a_connection_that_went_away_is_off_the_list() {
3575 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3576 let one = r.engine_mut().accept();
3577 let two = r.engine_mut().accept();
3578 let mut batch = Vec::new();
3579 assert_eq!(r.engine().server().client_count(), 2);
3580
3581 r.engine_mut().hangup(two);
3582 assert_eq!(r.engine().server().client_count(), 1);
3583
3584 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3585 pump(&mut r, &mut batch);
3586 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3587 assert_eq!(sent.lines().filter(|l| l.starts_with("id=")).count(), 1);
3588 }
3589
3590 #[test]
3593 fn a_write_pause_holds_the_writes_and_lets_the_reads_through() {
3594 let (mut r, one, mut batch) = timed();
3595 let two = r.engine_mut().accept();
3596
3597 r.engine_mut()
3598 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3599 pump(&mut r, &mut batch);
3600 assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
3601
3602 r.engine_mut().sink_mut().clear();
3603 r.engine_mut().feed(two, &wire(&[b"GET", b"k"]));
3604 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3605 pump(&mut r, &mut batch);
3606 assert_eq!(
3607 r.engine().sink().sent(two),
3608 b"$-1\r\n",
3609 "the read answered and the write is being held"
3610 );
3611 assert_eq!(r.engine().waiting(), 1, "the held connection");
3612
3613 r.engine_mut().sink_mut().clear();
3614 r.engine().server().advance_clock_ms(500);
3615 pump(&mut r, &mut batch);
3616 assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3617 assert_eq!(r.engine().waiting(), 0);
3618 }
3619
3620 #[test]
3622 fn an_all_pause_holds_every_command_and_cannot_be_called_off() {
3623 let (mut r, one, mut batch) = timed();
3624 let two = r.engine_mut().accept();
3625
3626 r.engine_mut()
3627 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3628 pump(&mut r, &mut batch);
3629
3630 r.engine_mut().sink_mut().clear();
3631 r.engine_mut().feed(two, &wire(&[b"PING"]));
3632 r.engine_mut().feed(two, &wire(&[b"CLIENT", b"UNPAUSE"]));
3633 pump(&mut r, &mut batch);
3634 assert_eq!(r.engine().sink().sent(two), b"", "not even the ping");
3635
3636 r.engine().server().advance_clock_ms(499);
3637 pump(&mut r, &mut batch);
3638 assert_eq!(r.engine().sink().sent(two), b"", "still inside the pause");
3639
3640 r.engine().server().advance_clock_ms(1);
3641 pump(&mut r, &mut batch);
3642 assert_eq!(
3643 r.engine().sink().sent(two),
3644 b"+PONG\r\n+OK\r\n",
3645 "both, in the order they were sent"
3646 );
3647 }
3648
3649 #[test]
3651 fn a_shorter_pause_does_not_shorten_the_one_already_running() {
3652 let (mut r, one, mut batch) = timed();
3653 let two = r.engine_mut().accept();
3654
3655 r.engine_mut()
3656 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3657 r.engine_mut()
3658 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"10", b"WRITE"]));
3659 pump(&mut r, &mut batch);
3660 assert_eq!(r.engine().server().pause_ends(), START_MS + 500);
3661
3662 r.engine_mut().sink_mut().clear();
3663 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3664 r.engine().server().advance_clock_ms(100);
3665 pump(&mut r, &mut batch);
3666 assert_eq!(r.engine().sink().sent(two), b"", "the longer end holds");
3667
3668 r.engine().server().advance_clock_ms(400);
3669 pump(&mut r, &mut batch);
3670 assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3671 }
3672
3673 #[test]
3675 fn a_write_pause_on_top_of_an_all_pause_still_holds_the_reads() {
3676 let (mut r, one, mut batch) = timed();
3677 let two = r.engine_mut().accept();
3678
3679 r.engine_mut()
3680 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3681 pump(&mut r, &mut batch);
3682 r.engine_mut()
3685 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3686
3687 r.engine_mut().sink_mut().clear();
3688 r.engine_mut().feed(two, &wire(&[b"GET", b"k"]));
3689 r.engine().server().advance_clock_ms(200);
3690 pump(&mut r, &mut batch);
3691 assert_eq!(r.engine().sink().sent(two), b"", "still everything");
3692 }
3693
3694 #[test]
3696 fn unpause_lets_go_of_a_write_pause_at_once() {
3697 let (mut r, one, mut batch) = timed();
3698 let two = r.engine_mut().accept();
3699
3700 r.engine_mut()
3701 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"5000", b"WRITE"]));
3702 pump(&mut r, &mut batch);
3703 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3704 pump(&mut r, &mut batch);
3705 assert_eq!(r.engine().sink().sent(two), b"");
3706
3707 r.engine_mut().sink_mut().clear();
3708 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"UNPAUSE"]));
3709 pump(&mut r, &mut batch);
3710 assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3711 }
3712
3713 #[test]
3716 fn a_write_pause_holds_an_exec_only_when_the_transaction_writes() {
3717 let (mut r, one, mut batch) = timed();
3718 let two = r.engine_mut().accept();
3719 let three = r.engine_mut().accept();
3720
3721 for conn in [two, three] {
3722 r.engine_mut().feed(conn, &wire(&[b"MULTI"]));
3723 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
3724 }
3725 r.engine_mut().feed(three, &wire(&[b"SET", b"k", b"v"]));
3726 pump(&mut r, &mut batch);
3727
3728 r.engine_mut()
3729 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3730 pump(&mut r, &mut batch);
3731
3732 r.engine_mut().sink_mut().clear();
3733 r.engine_mut().feed(two, &wire(&[b"EXEC"]));
3734 r.engine_mut().feed(three, &wire(&[b"EXEC"]));
3735 pump(&mut r, &mut batch);
3736 assert_eq!(r.engine().sink().sent(two), b"*1\r\n$-1\r\n", "reads only");
3737 assert_eq!(r.engine().sink().sent(three), b"", "one write in it");
3738
3739 r.engine_mut().sink_mut().clear();
3740 r.engine().server().advance_clock_ms(500);
3741 pump(&mut r, &mut batch);
3742 assert_eq!(r.engine().sink().sent(three), b"*2\r\n$-1\r\n+OK\r\n");
3743 }
3744
3745 #[test]
3748 fn a_held_connection_that_hangs_up_lets_go_of_its_slot() {
3749 let (mut r, one, mut batch) = timed();
3750 let two = r.engine_mut().accept();
3751
3752 r.engine_mut()
3753 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3754 pump(&mut r, &mut batch);
3755 r.engine_mut().feed(two, &wire(&[b"PING"]));
3756 pump(&mut r, &mut batch);
3757 assert_eq!(r.engine().waiting(), 1);
3758
3759 r.engine_mut().hangup(two);
3760 pump(&mut r, &mut batch);
3761 assert_eq!(r.engine().server().client_count(), 1);
3762
3763 r.engine().server().advance_clock_ms(500);
3764 pump(&mut r, &mut batch);
3765 assert_eq!(r.engine().waiting(), 0, "nothing left holding a slot");
3766 }
3767
3768 #[test]
3771 fn a_held_connection_names_the_command_it_is_waiting_to_run() {
3772 let (mut r, one, mut batch) = timed();
3773 let two = r.engine_mut().accept();
3774
3775 r.engine_mut()
3776 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3777 pump(&mut r, &mut batch);
3778 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3779 pump(&mut r, &mut batch);
3780
3781 r.engine_mut().sink_mut().clear();
3782 r.engine().server().advance_clock_ms(0);
3783 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3784 r.engine().server().advance_clock_ms(500);
3788 pump(&mut r, &mut batch);
3789 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3790 assert!(sent.contains("cmd=set"), "{sent}");
3791 }
3792
3793 fn watched() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3798 let (mut r, eye, mut batch) = timed();
3799 let one = r.engine_mut().accept();
3800 r.engine_mut().feed(eye, &wire(&[b"MONITOR"]));
3801 pump(&mut r, &mut batch);
3802 assert_eq!(r.engine().sink().sent(eye), b"+OK\r\n");
3803 r.engine_mut().sink_mut().clear();
3804 (r, eye, one, batch)
3805 }
3806
3807 const STAMP: &str = "1000.000000";
3809
3810 fn fed(r: &Reactor<Wire<Recorder>>, eye: ConnId) -> String {
3812 String::from_utf8_lossy(r.engine().sink().sent(eye)).into_owned()
3813 }
3814
3815 #[test]
3816 fn a_monitor_is_fed_a_command_another_connection_ran() {
3817 let (mut r, eye, one, mut batch) = watched();
3818
3819 r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
3820 pump(&mut r, &mut batch);
3821
3822 assert_eq!(
3823 fed(&r, eye),
3824 format!("+{STAMP} [0 ?:0] \"SET\" \"k\" \"v\"\r\n")
3825 );
3826 }
3827
3828 #[test]
3831 fn a_select_is_reported_on_the_database_it_moved_to() {
3832 let (mut r, eye, one, mut batch) = watched();
3833
3834 r.engine_mut().feed(one, &wire(&[b"SELECT", b"3"]));
3835 r.engine_mut().feed(one, &wire(&[b"GET", b"k"]));
3836 r.engine_mut().feed(one, &wire(&[b"SELECT", b"0"]));
3837 pump(&mut r, &mut batch);
3838
3839 assert_eq!(
3840 fed(&r, eye),
3841 format!(
3842 "+{STAMP} [3 ?:0] \"SELECT\" \"3\"\r\n\
3843 +{STAMP} [3 ?:0] \"GET\" \"k\"\r\n\
3844 +{STAMP} [0 ?:0] \"SELECT\" \"0\"\r\n"
3845 )
3846 );
3847 }
3848
3849 #[test]
3852 fn an_argument_is_quoted_the_way_a_real_server_quotes_it() {
3853 let (mut r, eye, one, mut batch) = watched();
3854
3855 r.engine_mut()
3856 .feed(one, &wire(&[b"SET", b"a b", b"q\"s\\n\nt\tz\x01\xff"]));
3857 pump(&mut r, &mut batch);
3858
3859 assert_eq!(
3860 fed(&r, eye),
3861 format!("+{STAMP} [0 ?:0] \"SET\" \"a b\" \"q\\\"s\\\\n\\nt\\tz\\x01\\xff\"\r\n")
3862 );
3863 }
3864
3865 #[test]
3868 fn only_a_command_that_ran_is_reported() {
3869 let (mut r, eye, one, mut batch) = watched();
3870
3871 r.engine_mut().feed(one, &wire(&[b"NOSUCHCOMMAND", b"a"]));
3872 r.engine_mut().feed(one, &wire(&[b"GET"]));
3873 r.engine_mut().feed(one, &wire(&[b"LPUSH", b"l", b"x"]));
3874 r.engine_mut().feed(one, &wire(&[b"GET", b"l"]));
3875 pump(&mut r, &mut batch);
3876
3877 assert_eq!(
3878 fed(&r, eye),
3879 format!(
3880 "+{STAMP} [0 ?:0] \"LPUSH\" \"l\" \"x\"\r\n\
3881 +{STAMP} [0 ?:0] \"GET\" \"l\"\r\n"
3882 ),
3883 "the unknown command and the wrong arity are not commands that ran"
3884 );
3885 }
3886
3887 #[test]
3891 fn a_transaction_is_reported_at_exec_and_in_order() {
3892 let (mut r, eye, one, mut batch) = watched();
3893
3894 r.engine_mut().feed(one, &wire(&[b"MULTI"]));
3895 r.engine_mut().feed(one, &wire(&[b"SET", b"t", b"1"]));
3896 r.engine_mut().feed(one, &wire(&[b"INCR", b"t"]));
3897 r.engine_mut().feed(one, &wire(&[b"EXEC"]));
3898 pump(&mut r, &mut batch);
3899
3900 assert_eq!(
3901 fed(&r, eye),
3902 format!(
3903 "+{STAMP} [0 ?:0] \"MULTI\"\r\n\
3904 +{STAMP} [0 ?:0] \"SET\" \"t\" \"1\"\r\n\
3905 +{STAMP} [0 ?:0] \"INCR\" \"t\"\r\n\
3906 +{STAMP} [0 ?:0] \"EXEC\"\r\n"
3907 )
3908 );
3909 }
3910
3911 #[test]
3914 #[cfg_attr(miri, ignore = "a Lua state is C, and Miri interprets Rust")]
3915 fn a_script_is_reported_in_front_of_its_own_effects() {
3916 let (mut r, eye, one, mut batch) = watched();
3917
3918 r.engine_mut().feed(
3919 one,
3920 &wire(&[
3921 b"EVAL",
3922 b"redis.call('set', KEYS[1], 'z') return 1",
3923 b"1",
3924 b"sk",
3925 ]),
3926 );
3927 pump(&mut r, &mut batch);
3928
3929 assert_eq!(
3930 fed(&r, eye),
3931 format!(
3932 "+{STAMP} [0 ?:0] \"EVAL\" \"redis.call('set', KEYS[1], 'z') return 1\" \"1\" \"sk\"\r\n\
3933 +{STAMP} [0 lua] \"set\" \"sk\" \"z\"\r\n"
3934 )
3935 );
3936 }
3937
3938 #[test]
3941 fn an_administrative_command_is_not_reported() {
3942 let (mut r, eye, one, mut batch) = watched();
3943
3944 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3945 r.engine_mut()
3946 .feed(one, &wire(&[b"CONFIG", b"GET", b"maxmemory"]));
3947 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"ID"]));
3948 r.engine_mut().feed(one, &wire(&[b"CONFIG", b"HELP"]));
3949 pump(&mut r, &mut batch);
3950
3951 assert_eq!(
3952 fed(&r, eye),
3953 format!(
3954 "+{STAMP} [0 ?:0] \"CLIENT\" \"ID\"\r\n\
3955 +{STAMP} [0 ?:0] \"CONFIG\" \"HELP\"\r\n"
3956 )
3957 );
3958 }
3959
3960 #[test]
3963 fn a_password_is_not_echoed_to_a_monitor() {
3964 let (mut r, eye, one, mut batch) = watched();
3965
3966 r.engine_mut().feed(
3967 one,
3968 &wire(&[b"HELLO", b"3", b"AUTH", b"default", b"hunter2"]),
3969 );
3970 pump(&mut r, &mut batch);
3971
3972 let sent = fed(&r, eye);
3973 assert!(
3974 sent.contains("\"HELLO\" \"3\" \"AUTH\" \"(redacted)\" \"(redacted)\""),
3975 "{sent}"
3976 );
3977 assert!(!sent.contains("hunter2"), "{sent}");
3978 }
3979
3980 #[test]
3983 fn a_monitor_may_not_touch_the_keyspace() {
3984 let (mut r, eye, _one, mut batch) = watched();
3985
3986 r.engine_mut().feed(eye, &wire(&[b"PING"]));
3991 pump(&mut r, &mut batch);
3992 r.engine_mut().feed(eye, &wire(&[b"GET", b"k"]));
3993 pump(&mut r, &mut batch);
3994
3995 assert_eq!(
3996 fed(&r, eye),
3997 format!(
3998 "+PONG\r\n\
3999 +{STAMP} [0 ?:0] \"PING\"\r\n\
4000 -ERR Replica can't interact with the keyspace\r\n"
4001 )
4002 );
4003 }
4004
4005 #[test]
4008 fn a_monitor_is_refused_the_keyspace_at_queue_time() {
4009 let (mut r, eye, _one, mut batch) = watched();
4010
4011 r.engine_mut().feed(eye, &wire(&[b"MULTI"]));
4012 r.engine_mut().feed(eye, &wire(&[b"GET", b"k"]));
4013 r.engine_mut().feed(eye, &wire(&[b"EXEC"]));
4014 pump(&mut r, &mut batch);
4015
4016 let sent = fed(&r, eye);
4017 assert!(
4018 sent.contains("-ERR Replica can't interact with the keyspace"),
4019 "{sent}"
4020 );
4021 assert!(sent.contains("-EXECABORT"), "{sent}");
4022 }
4023
4024 #[test]
4027 fn a_monitor_runs_through_a_pause() {
4028 let (mut r, eye, one, mut batch) = watched();
4029
4030 r.engine_mut()
4031 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"5000", b"ALL"]));
4032 pump(&mut r, &mut batch);
4033 r.engine_mut().sink_mut().clear();
4034
4035 r.engine_mut().feed(eye, &wire(&[b"PING"]));
4036 r.engine_mut().feed(one, &wire(&[b"PING"]));
4037 pump(&mut r, &mut batch);
4038
4039 assert!(
4040 fed(&r, eye).starts_with("+PONG\r\n"),
4041 "the monitor is let through"
4042 );
4043 assert_eq!(r.engine().sink().sent(one), b"", "and the client is not");
4044 }
4045
4046 #[test]
4049 fn monitor_sent_twice_answers_nothing_the_second_time() {
4050 let (mut r, eye, _one, mut batch) = watched();
4051
4052 r.engine_mut().feed(eye, &wire(&[b"MONITOR"]));
4053 pump(&mut r, &mut batch);
4054
4055 assert_eq!(fed(&r, eye), "", "no reply and no line either");
4056 }
4057
4058 #[test]
4060 fn reset_takes_a_connection_out_of_monitor_mode() {
4061 let (mut r, eye, one, mut batch) = watched();
4062
4063 r.engine_mut().feed(eye, &wire(&[b"RESET"]));
4064 pump(&mut r, &mut batch);
4065 r.engine_mut().sink_mut().clear();
4066
4067 r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
4068 r.engine_mut().feed(eye, &wire(&[b"GET", b"k"]));
4069 pump(&mut r, &mut batch);
4070
4071 assert_eq!(fed(&r, eye), "$1\r\nv\r\n", "not watching and not refused");
4072 }
4073
4074 #[test]
4077 fn a_monitor_that_closes_stops_being_one() {
4078 let (mut r, eye, one, mut batch) = watched();
4079
4080 r.engine_mut().hangup(eye);
4081 pump(&mut r, &mut batch);
4082 assert!(!r.engine().server().monitored());
4083
4084 r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
4085 pump(&mut r, &mut batch);
4086 assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
4087 }
4088
4089 #[test]
4091 fn two_monitors_are_fed_the_same_bytes() {
4092 let (mut r, eye, one, mut batch) = watched();
4093 let other = r.engine_mut().accept();
4094 r.engine_mut().feed(other, &wire(&[b"MONITOR"]));
4095 pump(&mut r, &mut batch);
4096 r.engine_mut().sink_mut().clear();
4097
4098 r.engine_mut().feed(one, &wire(&[b"SET", b"k", b"v"]));
4099 pump(&mut r, &mut batch);
4100
4101 assert_eq!(fed(&r, eye), fed(&r, other));
4102 assert_eq!(
4103 fed(&r, eye),
4104 format!("+{STAMP} [0 ?:0] \"SET\" \"k\" \"v\"\r\n")
4105 );
4106 }
4107
4108 #[test]
4110 fn a_monitor_is_reported_as_one_in_client_list() {
4111 let (mut r, _eye, one, mut batch) = watched();
4112
4113 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
4114 pump(&mut r, &mut batch);
4115
4116 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
4117 assert!(sent.contains("flags=O"), "{sent}");
4118 assert!(sent.contains("flags=N"), "and the other one is not: {sent}");
4119 }
4120}