1use std::sync::Arc;
75
76use yo_reactor::{BATCH_MAX, Engine, Reactor};
77
78use crate::dispatch::table;
79use crate::dispatch::{self, Flow, Parked, Reply, Server};
80use crate::front::{Front, Wrote};
81use crate::proto::Limits;
82use yo_kv::Keyspace;
83
84pub use crate::front::Cmd;
85
86pub type ConnId = u32;
88
89const SWEEP_LOOKS: usize = yo_reactor::MAINTENANCE_UNITS as usize;
96
97pub trait Sink {
103 fn write(&mut self, conn: ConnId, bytes: &[u8]) -> usize;
108
109 fn closed(&mut self, conn: ConnId) {
111 let _ = conn;
112 }
113}
114
115#[derive(Debug, Default)]
117pub struct Recorder {
118 sent: Vec<Vec<u8>>,
119 closed: Vec<ConnId>,
120}
121
122impl Recorder {
123 #[must_use]
125 pub fn new() -> Recorder {
126 Recorder::default()
127 }
128
129 #[must_use]
131 pub fn sent(&self, conn: ConnId) -> &[u8] {
132 self.sent.get(conn as usize).map_or(&[], Vec::as_slice)
133 }
134
135 #[must_use]
137 pub fn was_closed(&self, conn: ConnId) -> bool {
138 self.closed.contains(&conn)
139 }
140
141 pub fn clear(&mut self) {
143 for c in &mut self.sent {
144 c.clear();
145 }
146 self.closed.clear();
147 }
148}
149
150impl Sink for Recorder {
151 fn write(&mut self, conn: ConnId, bytes: &[u8]) -> usize {
152 yo_alloc::allow(|| {
154 if self.sent.len() <= conn as usize {
155 self.sent.resize_with(conn as usize + 1, Vec::new);
156 }
157 self.sent[conn as usize].extend_from_slice(bytes);
158 });
159 bytes.len()
160 }
161
162 fn closed(&mut self, conn: ConnId) {
163 yo_alloc::allow(|| self.closed.push(conn));
164 }
165}
166
167pub struct Wire<S> {
177 front: Front<S>,
178 server: Arc<Server>,
179 parked: Vec<Parked>,
186 post: Vec<dispatch::Envelope>,
193 held: Vec<(ConnId, u64)>,
201}
202
203impl<S: Sink> Wire<S> {
204 #[must_use]
206 pub fn new(sink: S) -> Wire<S> {
207 Wire::with_server(Server::new(), sink)
208 }
209
210 #[must_use]
213 pub fn with_server(server: Server, sink: S) -> Wire<S> {
214 Wire::over(Arc::new(server), sink)
215 }
216
217 #[must_use]
226 pub fn over(server: Arc<Server>, sink: S) -> Wire<S> {
227 Wire {
228 front: Front::new(sink),
229 parked: Vec::new(),
230 post: Vec::new(),
231 held: Vec::new(),
232 server,
233 }
234 }
235
236 #[must_use]
238 pub fn server(&self) -> &Server {
239 &self.server
240 }
241
242 #[must_use]
245 pub fn shared(&self) -> Arc<Server> {
246 Arc::clone(&self.server)
247 }
248
249 pub fn server_mut(&mut self) -> &mut Server {
264 Arc::get_mut(&mut self.server)
265 .expect("the server is set up before the threads that share it are started")
266 }
267
268 #[must_use]
270 pub const fn sink(&self) -> &S {
271 self.front.sink()
272 }
273
274 pub const fn sink_mut(&mut self) -> &mut S {
276 self.front.sink_mut()
277 }
278
279 pub fn set_limits(&mut self, limits: Limits) {
281 self.front.set_limits(limits);
282 }
283
284 pub fn accept(&mut self) -> ConnId {
286 self.server.counted().opened();
287 let at = self.front.open(self.server.next_client());
288 let now = self.server.now_ms();
289 let row = if let Some(session) = self.front.session_mut(at) {
290 session.opened(now);
291 Some(session.row().clone())
292 } else {
293 None
294 };
295 if let Some(row) = row {
300 self.server.register_client(&row);
301 }
302 self.note_buffers();
303 at
304 }
305
306 pub fn accept_from(&mut self, peer: &str, local: &str, fd: i32, unix: bool) -> ConnId {
314 let at = self.accept();
315 if let Some(session) = self.front.session_mut(at) {
316 session.set_socket(peer, local, fd, unix);
317 }
318 at
319 }
320
321 fn note_buffers(&mut self) {
326 let delta = self.front.buffer_delta();
327 if delta != 0 {
328 self.server.note_conn_bytes(delta);
329 }
330 }
331
332 pub fn hangup(&mut self, conn: ConnId) {
338 if !self.front.live(conn) {
339 return;
340 }
341 self.front.mark_gone(conn);
342 if self.front.blocked(conn) {
347 self.front.unpark(conn);
348 }
349 if self.front.pending(conn) == 0 {
350 self.release(conn);
351 }
352 self.note_buffers();
353 }
354
355 fn serve_waiters(&mut self) {
368 let now = self.server.now_ms();
369 let mine = self.server.my_slot();
370 self.server.waiters().mine(mine, &mut self.parked);
371 for at in 0..self.parked.len() {
372 let p = self.parked[at];
373 if !self.front.answers(p.conn, p.client) {
378 self.server.forget_waiters(p.client);
379 continue;
380 }
381 let served = {
385 let Wire { server, front, .. } = self;
386 server.serve_waiter(p.client, now, front.out(p.conn))
387 };
388 if served {
389 self.server.forget_waiters(p.client);
390 self.front.unpark(p.conn);
391 self.front.soil(p.conn);
392 }
393 }
394 self.parked.clear();
395 }
396
397 fn deliver(&mut self) {
406 let mut post = core::mem::take(&mut self.post);
409 self.server.take_mail(&mut post);
410 for env in post.drain(..) {
411 let conn = env.conn();
412 if !self.front.answers(conn, env.client()) {
413 continue;
414 }
415 env.write(self.front.out(conn));
416 self.front.soil(conn);
417 }
418 self.post = post;
419 }
420
421 #[must_use]
423 pub fn clients(&self) -> usize {
424 self.front.clients()
425 }
426
427 #[must_use]
429 pub fn ready(&self) -> usize {
430 self.front.ready()
431 }
432
433 #[must_use]
439 pub fn owed(&self) -> usize {
440 self.front.owed()
441 }
442
443 #[must_use]
454 pub fn waiting(&self) -> usize {
455 self.server.parked_here() + self.held.len()
456 }
457
458 #[must_use]
467 pub fn posted(&self) -> usize {
468 self.server.posted()
469 }
470
471 #[must_use]
478 pub fn stopping(&self) -> bool {
479 self.server.stopping()
480 }
481
482 #[must_use]
484 pub fn decoders(&self) -> usize {
485 self.front.decoders()
486 }
487
488 #[must_use]
490 pub fn buffer_bytes(&self) -> usize {
491 self.front.buffer_bytes()
492 }
493
494 pub fn feed(&mut self, conn: ConnId, bytes: &[u8]) {
500 self.front.feed(conn, bytes);
501 self.note_buffers();
502 }
503
504 fn release(&mut self, conn: ConnId) {
506 if let Some(session) = self.front.session_mut(conn) {
510 dispatch::forget_session(&self.server, session);
511 }
512 let Some(client) = self.front.close(conn) else {
513 return;
514 };
515 self.forget(client);
516 }
517
518 fn forget(&mut self, client: u64) {
525 self.server.forget_waiters(client);
526 self.server.forget_client(client);
527 self.server.counted().closed();
528 }
529
530 fn resume(&mut self) {
544 let mut held = core::mem::take(&mut self.held);
547 for &(conn, client) in &held {
548 if self.front.answers(conn, client) && self.front.blocked(conn) {
553 self.front.unpark(conn);
554 }
555 }
556 held.clear();
557 self.held = held;
558 }
559
560 fn reap(&mut self) {
561 for (conn, client) in self.server.my_kills() {
562 self.server.kill_done();
563 if self.front.answers(conn, client) {
564 self.hangup(conn);
565 }
566 }
567 }
568
569 pub fn take_ready(&mut self, into: &mut Vec<Cmd>, max: usize) -> usize {
574 self.front.take_ready(into, max)
575 }
576
577 pub fn tick(&mut self) {
583 self.server.refresh_clock();
584 }
585
586 pub fn maintain(&mut self) -> Option<usize> {
604 self.server.refresh_memory();
610 self.server.backup_expire();
614 self.server.expire_slice(SWEEP_LOOKS);
619 self.server.compact_step()
620 }
621}
622
623impl<S: Sink> Engine for Wire<S> {
624 type Work = Cmd;
625
626 fn key_hash(&self, cmd: &Cmd) -> Option<u64> {
627 let spec = table::at(cmd.spec)?;
632 if spec.first_key <= 0 {
633 return None;
634 }
635 let args = self.front.args(cmd);
636 let key = args.opt(spec.first_key as usize)?;
641 Some(Keyspace::hash_of(key))
642 }
643
644 fn prefetch(&self, cmd: &Cmd, hash: u64) {
645 let db = self.front.db(cmd.conn());
646 self.server.striped_ref(db).prefetch_hashed(hash);
651 }
652
653 fn run(&mut self, cmd: Cmd, _hash: Option<u64>) -> yo_reactor::Flow {
654 let conn = cmd.conn();
655 if self.front.blocked(conn) {
660 self.front.park(conn, cmd);
661 return yo_reactor::Flow::Next;
662 }
663
664 let flow = if self.front.start(&cmd) {
668 let Wire { front, server, .. } = self;
669 let (args, session, out) = front.parts(&cmd);
670 let spec = table::at(cmd.spec);
671 let mark = out.len();
672 let flow = dispatch::resolved(server, session, spec, args, out);
673 if flow != Flow::Hold {
678 session.finished();
685 session.note_proto(out.proto().version());
686 let mode = session.reply_mode();
687 session.step_reply();
688 if mode != Reply::On {
689 out.truncate(mark);
690 }
691 }
692 flow
693 } else {
694 Flow::Continue
698 };
699
700 if flow == Flow::Hold {
707 self.front.hold(conn, cmd);
708 let client = self.front.client(conn);
709 yo_alloc::allow(|| self.held.push((conn, client)));
710 return yo_reactor::Flow::Next;
711 }
712
713 self.front.done(&cmd);
714 if self.front.gone(conn) {
715 if self.front.pending(conn) == 0 {
716 self.release(conn);
717 }
718 } else {
719 match flow {
720 Flow::Close => {
721 self.front.quit(conn);
722 self.front.soil(conn);
723 }
724 Flow::Block => {
729 self.front.block(conn);
730 let client = self.front.client(conn);
731 self.server.bind_waiter(client, conn);
732 }
733 Flow::Hold => {}
736 Flow::Continue => self.front.soil(conn),
737 }
738 }
739
740 if self.server.parked_here() != 0 {
745 self.serve_waiters();
746 }
747 yo_reactor::Flow::Next
748 }
749
750 fn flush(&mut self) {
751 if self.server.parked_here() != 0 {
762 self.server.refresh_clock();
763 self.serve_waiters();
764 }
765
766 if !self.held.is_empty() {
772 self.server.refresh_clock();
773 if self.server.paused(self.server.now_ms()).is_none() {
774 self.resume();
775 }
776 }
777
778 if self.server.kills() != 0 {
783 self.reap();
784 }
785
786 if self.server.mail_here() != 0 {
791 self.deliver();
792 }
793
794 let mut dirty = self.front.take_dirty();
798 let mut at = 0;
799 while at < dirty.len() {
800 let conn = dirty[at];
801 match self.front.write_out(conn) {
802 Wrote::Owed => at += 1,
806 Wrote::Done => {
807 dirty.swap_remove(at);
808 }
809 Wrote::Ended(client) => {
810 self.forget(client);
811 dirty.swap_remove(at);
812 }
813 }
814 }
815 self.front.give_dirty(dirty);
816 self.note_buffers();
817 }
818
819 fn maintain(&mut self, budget: &mut yo_reactor::Budget) {
820 if !budget.spend(1) {
823 return;
824 }
825 self.tick();
826 let looks = budget.left() as usize;
832 let spent = self.server.expire_slice(looks);
833 budget.spend(u32::try_from(spent).unwrap_or(u32::MAX));
834 }
835}
836
837pub fn pump<S: Sink>(reactor: &mut Reactor<Wire<S>>, batch: &mut Vec<Cmd>) -> usize {
844 let mut ran = 0;
845 reactor.engine_mut().tick();
846 loop {
852 loop {
853 batch.clear();
854 if reactor.engine_mut().take_ready(batch, BATCH_MAX) == 0 {
855 break;
856 }
857 let armed = yo_alloc::guard();
867 ran += reactor.execute_all(batch.drain(..));
868 drop(armed);
869 reactor.engine_mut().flush();
870 reactor.engine_mut().maintain();
873 }
874 reactor.engine_mut().maintain();
877 reactor.engine_mut().flush();
885 if reactor.engine().ready() == 0 {
886 break;
887 }
888 }
889 ran
890}
891
892#[cfg(test)]
893mod tests {
894 use super::*;
895
896 fn wire(args: &[&[u8]]) -> Vec<u8> {
898 let mut b = format!("*{}\r\n", args.len()).into_bytes();
899 for a in args {
900 b.extend_from_slice(format!("${}\r\n", a.len()).as_bytes());
901 b.extend_from_slice(a);
902 b.extend_from_slice(b"\r\n");
903 }
904 b
905 }
906
907 fn engine() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
908 let mut r = Reactor::inline(Wire::new(Recorder::new()));
909 let conn = r.engine_mut().accept();
910 (r, conn, Vec::new())
911 }
912
913 const START_MS: u64 = 1_000_000;
915
916 fn timed() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
922 let server = crate::dispatch::Server::with_clock(yo_kv::Clock::fixed(START_MS));
923 let mut r = Reactor::inline(Wire::with_server(server, Recorder::new()));
924 let conn = r.engine_mut().accept();
925 (r, conn, Vec::new())
926 }
927
928 #[test]
929 fn a_pipelined_batch_comes_back_in_order_and_in_one_write() {
930 let (mut r, conn, mut batch) = engine();
931 let mut stream = wire(&[b"SET", b"k", b"v"]);
932 stream.extend(wire(&[b"GET", b"k"]));
933 stream.extend(wire(&[b"INCR", b"n"]));
934
935 r.engine_mut().feed(conn, &stream);
936 assert_eq!(r.engine().ready(), 3);
937 assert_eq!(pump(&mut r, &mut batch), 3);
938
939 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$1\r\nv\r\n:1\r\n");
940 assert_eq!(r.engine().ready(), 0);
941 }
942
943 #[test]
946 fn a_command_split_across_reads_resumes_rather_than_restarts() {
947 let (mut r, conn, mut batch) = engine();
948 let bytes = wire(&[b"SET", b"key", b"value"]);
949
950 for at in 1..bytes.len() {
951 r.engine_mut().feed(conn, &bytes[at - 1..at]);
952 assert_eq!(r.engine().ready(), 0, "not a command yet at {at}");
953 }
954 r.engine_mut().feed(conn, &bytes[bytes.len() - 1..]);
955 assert_eq!(r.engine().ready(), 1);
956 assert_eq!(pump(&mut r, &mut batch), 1);
957 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
958
959 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
962 pump(&mut r, &mut batch);
963 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$5\r\nvalue\r\n");
964 }
965
966 #[test]
967 fn two_connections_are_two_sessions_over_one_server() {
968 let (mut r, a, mut batch) = engine();
969 let b = r.engine_mut().accept();
970
971 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
972 r.engine_mut().feed(a, &wire(&[b"SET", b"k", b"a"]));
973 r.engine_mut().feed(b, &wire(&[b"SET", b"k", b"b"]));
974 r.engine_mut().feed(a, &wire(&[b"GET", b"k"]));
975 r.engine_mut().feed(b, &wire(&[b"GET", b"k"]));
976 pump(&mut r, &mut batch);
977
978 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n+OK\r\n$1\r\na\r\n");
979 assert_eq!(r.engine().sink().sent(b), b"+OK\r\n$1\r\nb\r\n");
980 assert_eq!(r.engine().clients(), 2);
981 }
982
983 #[test]
995 fn two_threads_write_into_one_server() {
996 const EACH: usize = 200;
997
998 let mut server = Server::new();
999 server.set_threads(2);
1000 let first = Wire::with_server(server, Recorder::new());
1001 let second = Wire::over(first.shared(), Recorder::new());
1002 let server = first.shared();
1003
1004 std::thread::scope(|s| {
1005 for (at, engine) in [first, second].into_iter().enumerate() {
1006 s.spawn(move || {
1007 let mut r = Reactor::inline(engine);
1008 let mut batch = Vec::new();
1009 let conn = r.engine_mut().accept();
1010 for i in 0..EACH {
1011 let key = format!("t{at}:{i}");
1012 r.engine_mut()
1013 .feed(conn, &wire(&[b"SET", key.as_bytes(), b"v"]));
1014 pump(&mut r, &mut batch);
1015 }
1016 });
1017 }
1018 });
1019
1020 assert_eq!(server.striped_ref(0).len(), 2 * EACH);
1023 assert_eq!(server.totals().connections, 2);
1026 }
1027
1028 #[test]
1031 fn a_waiter_belongs_to_the_thread_that_parked_it() {
1032 let mut server = Server::new();
1033 server.set_threads(2);
1034 let first = Wire::with_server(server, Recorder::new());
1035 let second = Wire::over(first.shared(), Recorder::new());
1036 let server = first.shared();
1037
1038 let parked = std::sync::Barrier::new(2);
1039 let swept = std::sync::Barrier::new(2);
1040
1041 std::thread::scope(|s| {
1042 let (parked, swept) = (&parked, &swept);
1043 s.spawn(move || {
1044 let mut r = Reactor::inline(first);
1045 let mut batch = Vec::new();
1046 let conn = r.engine_mut().accept();
1047 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
1048 pump(&mut r, &mut batch);
1049 parked.wait();
1050
1051 for _ in 0..50 {
1054 pump(&mut r, &mut batch);
1055 }
1056 swept.wait();
1057 assert!(r.engine().sink().sent(conn).is_empty(), "nothing to say");
1058 });
1059 s.spawn(move || {
1060 let mut r = Reactor::inline(second);
1061 let mut batch = Vec::new();
1062 let conn = r.engine_mut().accept();
1063 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"b", b"0"]));
1064 pump(&mut r, &mut batch);
1065 parked.wait();
1066 swept.wait();
1067
1068 let pusher = r.engine_mut().accept();
1071 r.engine_mut().feed(pusher, &wire(&[b"RPUSH", b"b", b"v"]));
1072 pump(&mut r, &mut batch);
1073 assert_eq!(
1074 r.engine().sink().sent(conn),
1075 b"*2\r\n$1\r\nb\r\n$1\r\nv\r\n",
1076 "served by the thread that parked it"
1077 );
1078 });
1079 });
1080
1081 assert_eq!(server.parked(), 1, "and the other one is still waiting");
1082 }
1083
1084 #[test]
1090 fn a_thread_counts_the_clients_it_blocked_and_nobody_else_s() {
1091 let mut server = Server::new();
1092 server.set_threads(2);
1093 let first = Wire::with_server(server, Recorder::new());
1094 let second = Wire::over(first.shared(), Recorder::new());
1095 let server = first.shared();
1096
1097 let parked = std::sync::Barrier::new(2);
1098 let looked = std::sync::Barrier::new(2);
1099
1100 std::thread::scope(|s| {
1101 let (parked, looked) = (&parked, &looked);
1102 s.spawn(move || {
1103 let mut r = Reactor::inline(first);
1104 let mut batch = Vec::new();
1105 let conn = r.engine_mut().accept();
1106 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
1107 pump(&mut r, &mut batch);
1108 assert_eq!(r.engine().waiting(), 1, "the one this thread blocked");
1109 parked.wait();
1110 looked.wait();
1111
1112 let other = r.engine_mut().accept();
1116 r.engine_mut().feed(other, &wire(&[b"PING"]));
1117 pump(&mut r, &mut batch);
1118 r.engine_mut().hangup(other);
1119 pump(&mut r, &mut batch);
1120 assert_eq!(r.engine().waiting(), 1, "still just the blocked one");
1121 });
1122 s.spawn(move || {
1123 let mut r = Reactor::inline(second);
1124 let mut batch = Vec::new();
1125 parked.wait();
1126
1127 pump(&mut r, &mut batch);
1130 assert_eq!(r.engine().waiting(), 0, "none of them are this one's");
1131 assert_eq!(r.engine().server().parked(), 1, "one on the server");
1132 looked.wait();
1133 });
1134 });
1135
1136 assert_eq!(server.parked(), 1);
1137 }
1138
1139 #[test]
1142 fn client_ids_are_the_server_s_to_hand_out() {
1143 let first = Wire::new(Recorder::new());
1144 let second = Wire::over(first.shared(), Recorder::new());
1145 let mut a = Reactor::inline(first);
1146 let mut b = Reactor::inline(second);
1147
1148 let (one, two) = (a.engine_mut().accept(), b.engine_mut().accept());
1149 assert_eq!(one, two, "the same slot on each front");
1150
1151 let mut batch = Vec::new();
1156 a.engine_mut().feed(one, &wire(&[b"HELLO", b"3"]));
1157 b.engine_mut().feed(two, &wire(&[b"HELLO", b"3"]));
1158 pump(&mut a, &mut batch);
1159 pump(&mut b, &mut batch);
1160
1161 let first = String::from_utf8_lossy(a.engine().sink().sent(one)).into_owned();
1162 let second = String::from_utf8_lossy(b.engine().sink().sent(two)).into_owned();
1163 assert!(first.contains(":1\r\n"), "{first}");
1164 assert!(second.contains(":2\r\n"), "{second}");
1165 }
1166
1167 #[test]
1168 fn quit_is_answered_and_then_the_connection_goes() {
1169 let (mut r, conn, mut batch) = engine();
1170 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1171 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1172 pump(&mut r, &mut batch);
1173
1174 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1175 assert!(r.engine().sink().was_closed(conn));
1176 assert_eq!(r.engine().clients(), 0);
1177
1178 let again = r.engine_mut().accept();
1180 assert_eq!(again, conn);
1181 assert_eq!(r.engine().clients(), 1);
1182 }
1183
1184 #[test]
1187 fn what_a_client_pipelined_behind_quit_is_never_run() {
1188 let (mut r, conn, mut batch) = engine();
1189 let mut stream = wire(&[b"QUIT"]);
1190 stream.extend(wire(&[b"SET", b"foo", b"bar"]));
1191 r.engine_mut().feed(conn, &stream);
1192 assert_eq!(r.engine().ready(), 2);
1194 pump(&mut r, &mut batch);
1195
1196 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
1198 assert!(r.engine().sink().was_closed(conn));
1199
1200 r.engine_mut().sink_mut().clear();
1205 let next = r.engine_mut().accept();
1206 r.engine_mut().feed(next, &wire(&[b"GET", b"foo"]));
1207 pump(&mut r, &mut batch);
1208 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1209 }
1210
1211 #[test]
1221 fn a_slot_that_last_spoke_resp3_answers_the_next_client_in_resp2() {
1222 let (mut r, conn, mut batch) = engine();
1223 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1224 r.engine_mut().feed(conn, &wire(&[b"GET", b"nothing"]));
1225 pump(&mut r, &mut batch);
1226 assert!(r.engine().sink().sent(conn).ends_with(b"_\r\n"));
1227 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1228 pump(&mut r, &mut batch);
1229
1230 r.engine_mut().sink_mut().clear();
1231 let next = r.engine_mut().accept();
1232 assert_eq!(next, conn, "the same slot, which is what this is about");
1233 r.engine_mut().feed(next, &wire(&[b"GET", b"nothing"]));
1234 pump(&mut r, &mut batch);
1235 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1236 }
1237
1238 #[test]
1240 fn commands_that_arrived_before_a_protocol_error_are_still_answered() {
1241 let (mut r, conn, mut batch) = engine();
1242 let mut stream = wire(&[b"SET", b"k", b"v"]);
1243 stream.extend(wire(&[b"GET", b"k"]));
1244 stream.extend_from_slice(b"*1\r\n+notabulk\r\n");
1245 r.engine_mut().feed(conn, &stream);
1246 pump(&mut r, &mut batch);
1247
1248 let sent = r.engine().sink().sent(conn);
1251 assert!(
1252 sent.starts_with(b"+OK\r\n$1\r\nv\r\n-ERR Protocol error: "),
1253 "{sent:?}"
1254 );
1255 assert!(r.engine().sink().was_closed(conn));
1256 }
1257
1258 #[test]
1259 fn a_protocol_error_is_written_and_closes_the_connection() {
1260 let (mut r, conn, mut batch) = engine();
1261 r.engine_mut().feed(conn, b"*1\r\n+notabulk\r\n");
1263 pump(&mut r, &mut batch);
1264
1265 let sent = r.engine().sink().sent(conn);
1266 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1267 assert!(r.engine().sink().was_closed(conn));
1268 assert_eq!(r.engine().clients(), 0);
1269 }
1270
1271 #[test]
1275 fn a_decoder_that_came_back_mid_command_starts_the_next_one_clean() {
1276 let (mut r, conn, mut batch) = engine();
1277 r.engine_mut()
1279 .feed(conn, b"*3\r\n$3\r\nSET\r\n$1\r\nx\r\n$blabla\r\n");
1280 pump(&mut r, &mut batch);
1281 let sent = r.engine().sink().sent(conn);
1282 assert!(
1283 sent.starts_with(b"-ERR Protocol error: invalid bulk length"),
1284 "{sent:?}"
1285 );
1286
1287 r.engine_mut().sink_mut().clear();
1291 let next = r.engine_mut().accept();
1292 r.engine_mut().feed(next, &wire(&[b"GET", b"k"]));
1293 pump(&mut r, &mut batch);
1294 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1295
1296 r.engine_mut().sink_mut().clear();
1297 let third = r.engine_mut().accept();
1298 r.engine_mut().feed(third, b"*1\r\n+notabulk\r\n");
1299 pump(&mut r, &mut batch);
1300 let sent = r.engine().sink().sent(third);
1301 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1302 }
1303
1304 #[test]
1307 fn a_hangup_with_commands_in_flight_waits_for_them() {
1308 let (mut r, conn, mut batch) = engine();
1309 r.engine_mut().feed(conn, &wire(&[b"SET", b"k", b"v"]));
1310 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1311
1312 batch.clear();
1313 r.engine_mut().take_ready(&mut batch, BATCH_MAX);
1314 r.engine_mut().hangup(conn);
1315 assert_eq!(r.engine().clients(), 1, "still holding the buffer");
1316
1317 r.execute_all(batch.drain(..));
1318 r.engine_mut().flush();
1319 assert_eq!(r.engine().clients(), 0);
1320 assert!(r.engine().sink().sent(conn).is_empty(), "nobody to answer");
1321
1322 let decoders = r.engine().decoders();
1325 let again = r.engine_mut().accept();
1326 assert_eq!(again, conn);
1327 r.engine_mut().feed(again, &wire(&[b"PING"]));
1328 pump(&mut r, &mut batch);
1329 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1330 assert_eq!(r.engine().decoders(), decoders);
1331 }
1332
1333 #[test]
1336 fn the_buffers_and_the_decoder_pool_stop_growing() {
1337 let (mut r, conn, mut batch) = engine();
1338 let mut stream = Vec::new();
1339 for i in 0..32 {
1340 stream.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1341 }
1342
1343 r.engine_mut().feed(conn, &stream);
1344 pump(&mut r, &mut batch);
1345 let decoders = r.engine().decoders();
1346 let batch_cap = batch.capacity();
1347
1348 for _ in 0..10 {
1349 r.engine_mut().feed(conn, &stream);
1350 pump(&mut r, &mut batch);
1351 }
1352 assert_eq!(r.engine().decoders(), decoders, "the pool is reused");
1353 assert_eq!(batch.capacity(), batch_cap, "the batch buffer is reused");
1354 assert!(
1355 decoders <= BATCH_MAX + 1,
1356 "{decoders} decoders for 32 commands"
1357 );
1358 }
1359
1360 #[test]
1369 fn a_pipelining_client_does_not_grow_the_read_buffer() {
1370 let (mut r, conn, mut batch) = engine();
1371 let mut round = Vec::new();
1372 for i in 0..16 {
1373 round.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1374 }
1375
1376 r.engine_mut().feed(conn, &round);
1377 pump(&mut r, &mut batch);
1378 r.engine_mut().sink_mut().clear();
1379 let after_one = r.engine().buffer_bytes();
1380
1381 let rounds = if cfg!(miri) { 50 } else { 1000 };
1390 for _ in 0..rounds {
1391 r.engine_mut().feed(conn, &round);
1392 pump(&mut r, &mut batch);
1393 r.engine_mut().sink_mut().clear();
1394 }
1395
1396 assert_eq!(
1397 r.engine().buffer_bytes(),
1398 after_one,
1399 "the buffers grew over {rounds} rounds of the same sixteen commands"
1400 );
1401 assert!(
1402 r.engine().server().memory_bytes() >= after_one,
1403 "the buffers are counted in what the server reports"
1404 );
1405 }
1406
1407 #[test]
1410 fn a_command_split_across_reads_survives_compaction() {
1411 let (mut r, conn, mut batch) = engine();
1412 let cmd = wire(&[b"SET", b"key", b"value"]);
1413 let (head, tail) = cmd.split_at(cmd.len() - 4);
1414
1415 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1418 r.engine_mut().feed(conn, head);
1419 pump(&mut r, &mut batch);
1420 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n");
1421
1422 r.engine_mut().feed(conn, tail);
1424 pump(&mut r, &mut batch);
1425 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1426
1427 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
1428 pump(&mut r, &mut batch);
1429 assert!(r.engine().sink().sent(conn).ends_with(b"$5\r\nvalue\r\n"));
1430 }
1431
1432 #[test]
1435 fn the_batch_goes_through_the_reactors_two_walks() {
1436 let (mut r, conn, mut batch) = engine();
1437 for i in 0..100 {
1438 r.engine_mut()
1439 .feed(conn, &wire(&[b"INCR", format!("k{}", i % 7).as_bytes()]));
1440 }
1441 let ran = pump(&mut r, &mut batch);
1442
1443 assert_eq!(ran, 100);
1444 assert_eq!(r.commands(), 100);
1445 assert_eq!(r.turns(), 2);
1447 assert!(r.engine().sink().sent(conn).ends_with(b":15\r\n"));
1449 }
1450
1451 #[derive(Default)]
1454 struct Trickle {
1455 sent: Vec<u8>,
1456 writes: usize,
1457 }
1458
1459 impl Sink for Trickle {
1460 fn write(&mut self, _conn: ConnId, bytes: &[u8]) -> usize {
1461 self.writes += 1;
1462 let n = bytes.len().min(4);
1463 self.sent.extend_from_slice(&bytes[..n]);
1464 n
1465 }
1466 }
1467
1468 #[test]
1471 fn a_blpop_on_a_list_with_something_in_it_never_waits() {
1472 let (mut r, conn, mut batch) = engine();
1473 r.engine_mut().feed(conn, &wire(&[b"RPUSH", b"q", b"a"]));
1474 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"0"]));
1475 pump(&mut r, &mut batch);
1476
1477 assert_eq!(
1478 r.engine().sink().sent(conn),
1479 b":1\r\n*2\r\n$1\r\nq\r\n$1\r\na\r\n"
1480 );
1481 assert_eq!(r.engine().server().parked(), 0);
1482 }
1483
1484 #[test]
1487 fn a_parked_client_is_answered_by_another_connections_push() {
1488 let (mut r, a, mut batch) = engine();
1489 let b = r.engine_mut().accept();
1490
1491 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1492 pump(&mut r, &mut batch);
1493 assert!(r.engine().sink().sent(a).is_empty(), "nothing to say yet");
1494 assert_eq!(r.engine().server().parked(), 1);
1495
1496 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"one"]));
1497 pump(&mut r, &mut batch);
1498
1499 assert_eq!(r.engine().sink().sent(a), b"*2\r\n$1\r\nq\r\n$3\r\none\r\n");
1500 assert_eq!(r.engine().sink().sent(b), b":1\r\n");
1503 assert_eq!(r.engine().server().parked(), 0);
1504 }
1505
1506 #[test]
1509 fn only_a_list_arriving_under_a_named_key_wakes_a_waiter() {
1510 let (mut r, a, mut batch) = engine();
1511 let b = r.engine_mut().accept();
1512 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1513 pump(&mut r, &mut batch);
1514
1515 r.engine_mut()
1516 .feed(b, &wire(&[b"RPUSH", b"elsewhere", b"x"]));
1517 r.engine_mut().feed(b, &wire(&[b"SADD", b"q", b"x"]));
1518 pump(&mut r, &mut batch);
1519
1520 assert!(r.engine().sink().sent(a).is_empty());
1521 assert_eq!(r.engine().server().parked(), 1, "still waiting");
1522 assert_eq!(r.engine().sink().sent(b), b":1\r\n:1\r\n");
1525 }
1526
1527 #[test]
1530 fn two_parked_clients_are_served_in_the_order_they_arrived() {
1531 let (mut r, a, mut batch) = engine();
1532 let b = r.engine_mut().accept();
1533 let c = r.engine_mut().accept();
1534
1535 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1536 pump(&mut r, &mut batch);
1537 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"q", b"0"]));
1538 pump(&mut r, &mut batch);
1539 assert_eq!(r.engine().server().parked(), 2);
1540
1541 r.engine_mut()
1542 .feed(c, &wire(&[b"RPUSH", b"q", b"first", b"second"]));
1543 pump(&mut r, &mut batch);
1544
1545 assert_eq!(
1546 r.engine().sink().sent(a),
1547 b"*2\r\n$1\r\nq\r\n$5\r\nfirst\r\n"
1548 );
1549 assert_eq!(
1550 r.engine().sink().sent(b),
1551 b"*2\r\n$1\r\nq\r\n$6\r\nsecond\r\n"
1552 );
1553 assert_eq!(r.engine().server().parked(), 0);
1554 }
1555
1556 #[test]
1559 fn what_a_client_pipelined_behind_a_block_waits_for_the_block() {
1560 let (mut r, a, mut batch) = engine();
1561 let b = r.engine_mut().accept();
1562
1563 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1566 stream.extend(wire(&[b"PING"]));
1567 r.engine_mut().feed(a, &stream);
1568 pump(&mut r, &mut batch);
1569 assert!(
1570 r.engine().sink().sent(a).is_empty(),
1571 "the PING went out in front of the answer it was sent behind"
1572 );
1573
1574 r.engine_mut().feed(a, &wire(&[b"ECHO", b"after"]));
1576 pump(&mut r, &mut batch);
1577 assert!(r.engine().sink().sent(a).is_empty());
1578
1579 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1580 pump(&mut r, &mut batch);
1581 assert_eq!(
1582 r.engine().sink().sent(a),
1583 b"*2\r\n$1\r\nq\r\n$1\r\nx\r\n+PONG\r\n$5\r\nafter\r\n"
1584 );
1585 }
1586
1587 #[test]
1592 fn a_waiter_is_served_between_two_pipelined_pushes() {
1593 let (mut r, a, mut batch) = engine();
1594 let b = r.engine_mut().accept();
1595 r.engine_mut()
1596 .feed(a, &wire(&[b"BLPOP", b"p1", b"p2", b"0"]));
1597 pump(&mut r, &mut batch);
1598
1599 let mut stream = wire(&[b"RPUSH", b"p2", b"second"]);
1600 stream.extend(wire(&[b"RPUSH", b"p1", b"first"]));
1601 r.engine_mut().feed(b, &stream);
1602 pump(&mut r, &mut batch);
1603
1604 assert_eq!(
1605 r.engine().sink().sent(a),
1606 b"*2\r\n$2\r\np2\r\n$6\r\nsecond\r\n"
1607 );
1608 r.engine_mut()
1610 .feed(b, &wire(&[b"LRANGE", b"p1", b"0", b"-1"]));
1611 pump(&mut r, &mut batch);
1612 assert!(
1613 r.engine()
1614 .sink()
1615 .sent(b)
1616 .ends_with(b"*1\r\n$5\r\nfirst\r\n")
1617 );
1618 }
1619
1620 #[test]
1624 fn a_waiter_woken_by_another_waiter() {
1625 let (mut r, a, mut batch) = engine();
1626 let b = r.engine_mut().accept();
1627 let c = r.engine_mut().accept();
1628
1629 r.engine_mut()
1630 .feed(a, &wire(&[b"BLMOVE", b"x", b"y", b"LEFT", b"RIGHT", b"0"]));
1631 pump(&mut r, &mut batch);
1632 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"y", b"0"]));
1633 pump(&mut r, &mut batch);
1634 assert_eq!(r.engine().server().parked(), 2);
1635
1636 r.engine_mut().feed(c, &wire(&[b"RPUSH", b"x", b"chain"]));
1637 pump(&mut r, &mut batch);
1638
1639 assert_eq!(r.engine().sink().sent(a), b"$5\r\nchain\r\n");
1640 assert_eq!(
1641 r.engine().sink().sent(b),
1642 b"*2\r\n$1\r\ny\r\n$5\r\nchain\r\n"
1643 );
1644 assert_eq!(r.engine().server().parked(), 0);
1645 }
1646
1647 #[test]
1650 fn a_waiter_is_only_woken_on_the_database_it_blocked_on() {
1651 let (mut r, a, mut batch) = engine();
1652 let b = r.engine_mut().accept();
1653 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
1654 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1655 pump(&mut r, &mut batch);
1656 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n");
1657
1658 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"wrongdb"]));
1659 pump(&mut r, &mut batch);
1660 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n", "still waiting");
1661
1662 r.engine_mut().feed(b, &wire(&[b"SELECT", b"3"]));
1663 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"rightdb"]));
1664 pump(&mut r, &mut batch);
1665 assert!(r.engine().sink().sent(a).ends_with(b"$7\r\nrightdb\r\n"));
1666 }
1667
1668 #[test]
1670 fn a_client_that_waited_long_enough_gets_a_null_array() {
1671 let (mut r, conn, mut batch) = timed();
1672 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"30"]));
1673 pump(&mut r, &mut batch);
1674 assert!(r.engine().sink().sent(conn).is_empty());
1675
1676 r.engine_mut().server_mut().set_clock_ms(START_MS + 29_999);
1677 pump(&mut r, &mut batch);
1678 assert!(
1679 r.engine().sink().sent(conn).is_empty(),
1680 "a millisecond short"
1681 );
1682
1683 r.engine_mut().server_mut().set_clock_ms(START_MS + 30_000);
1684 pump(&mut r, &mut batch);
1685 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n");
1687 assert_eq!(r.engine().server().parked(), 0);
1688 }
1689
1690 #[test]
1694 fn every_blocking_command_times_out_with_the_same_null_array() {
1695 for cmd in [
1696 &[b"BLPOP".as_slice(), b"q", b"0.001"][..],
1697 &[b"BRPOP", b"q", b"0.001"],
1698 &[b"BLMOVE", b"q", b"d", b"LEFT", b"RIGHT", b"0.001"],
1699 &[b"BRPOPLPUSH", b"q", b"d", b"0.001"],
1700 &[b"BLMPOP", b"0.001", b"1", b"q", b"LEFT"],
1701 ] {
1702 let (mut r, conn, mut batch) = timed();
1703 r.engine_mut().feed(conn, &wire(cmd));
1704 pump(&mut r, &mut batch);
1705 r.engine_mut().server_mut().set_clock_ms(START_MS + 1);
1706 pump(&mut r, &mut batch);
1707 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n", "for {cmd:?}");
1708 }
1709 }
1710
1711 #[test]
1714 fn a_waiter_that_timed_out_does_not_eat_a_later_push() {
1715 let (mut r, a, mut batch) = timed();
1716 let b = r.engine_mut().accept();
1717 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"1"]));
1718 pump(&mut r, &mut batch);
1719 r.engine_mut().server_mut().set_clock_ms(START_MS + 1000);
1720 pump(&mut r, &mut batch);
1721 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n");
1722
1723 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"late"]));
1724 r.engine_mut()
1725 .feed(b, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1726 pump(&mut r, &mut batch);
1727 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n", "nothing more");
1728 assert!(r.engine().sink().sent(b).ends_with(b"*1\r\n$4\r\nlate\r\n"));
1729 }
1730
1731 #[test]
1736 fn a_client_that_goes_away_while_it_waits_takes_its_waiter_with_it() {
1737 let (mut r, a, mut batch) = engine();
1738 let b = r.engine_mut().accept();
1739 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1740 pump(&mut r, &mut batch);
1741 assert_eq!(r.engine().server().parked(), 1);
1742
1743 r.engine_mut().hangup(a);
1744 pump(&mut r, &mut batch);
1745 assert_eq!(r.engine().server().parked(), 0);
1746 assert_eq!(r.engine().clients(), 1);
1747
1748 let again = r.engine_mut().accept();
1751 assert_eq!(again, a);
1752 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1753 r.engine_mut()
1754 .feed(again, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1755 pump(&mut r, &mut batch);
1756 assert_eq!(r.engine().sink().sent(again), b"*1\r\n$1\r\nx\r\n");
1757 }
1758
1759 #[test]
1763 fn a_hangup_while_parked_gives_back_the_slot_and_the_decoders() {
1764 let (mut r, a, mut batch) = engine();
1765 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1766 stream.extend(wire(&[b"PING"]));
1767 stream.extend(wire(&[b"PING"]));
1768 r.engine_mut().feed(a, &stream);
1769 pump(&mut r, &mut batch);
1770
1771 let decoders = r.engine().decoders();
1772 r.engine_mut().hangup(a);
1773 pump(&mut r, &mut batch);
1774
1775 assert_eq!(r.engine().clients(), 0);
1776 assert!(r.engine().sink().was_closed(a));
1777 assert_eq!(r.engine().decoders(), decoders, "the pool came back whole");
1778 let again = r.engine_mut().accept();
1779 assert_eq!(again, a);
1780 r.engine_mut().feed(again, &wire(&[b"PING"]));
1781 pump(&mut r, &mut batch);
1782 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1783 }
1784
1785 #[test]
1788 fn a_published_message_lands_on_the_subscriber() {
1789 let (mut r, sub, mut batch) = engine();
1790 let pubr = r.engine_mut().accept();
1791
1792 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1793 pump(&mut r, &mut batch);
1794 assert_eq!(
1795 r.engine().sink().sent(sub),
1796 b"*3\r\n$9\r\nsubscribe\r\n$4\r\nnews\r\n:1\r\n"
1797 );
1798 r.engine_mut().sink_mut().clear();
1799
1800 r.engine_mut()
1801 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1802 pump(&mut r, &mut batch);
1803 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1804 assert_eq!(
1805 r.engine().sink().sent(sub),
1806 b"*3\r\n$7\r\nmessage\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1807 );
1808 }
1809
1810 #[test]
1813 fn a_pattern_subscriber_is_told_the_pattern_and_the_channel() {
1814 let (mut r, sub, mut batch) = engine();
1815 let pubr = r.engine_mut().accept();
1816
1817 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"ne*"]));
1818 pump(&mut r, &mut batch);
1819 r.engine_mut().sink_mut().clear();
1820
1821 r.engine_mut()
1822 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1823 pump(&mut r, &mut batch);
1824 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1825 assert_eq!(
1826 r.engine().sink().sent(sub),
1827 b"*4\r\n$8\r\npmessage\r\n$3\r\nne*\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1828 );
1829 }
1830
1831 #[test]
1836 fn resp2_takes_almost_nothing_from_a_subscriber() {
1837 let (mut r, conn, mut batch) = engine();
1838
1839 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1840 pump(&mut r, &mut batch);
1841 r.engine_mut().sink_mut().clear();
1842
1843 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1844 pump(&mut r, &mut batch);
1845 assert_eq!(
1846 r.engine().sink().sent(conn),
1847 b"-ERR Can't execute 'get': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context\r\n"
1848 );
1849 r.engine_mut().sink_mut().clear();
1850
1851 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1853 pump(&mut r, &mut batch);
1854 assert_eq!(
1855 r.engine().sink().sent(conn),
1856 b"*2\r\n$4\r\npong\r\n$0\r\n\r\n"
1857 );
1858 r.engine_mut().sink_mut().clear();
1859
1860 r.engine_mut().feed(conn, &wire(&[b"UNSUBSCRIBE", b"a"]));
1862 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1863 pump(&mut r, &mut batch);
1864 assert_eq!(
1865 r.engine().sink().sent(conn),
1866 b"*3\r\n$11\r\nunsubscribe\r\n$1\r\na\r\n:0\r\n$-1\r\n"
1867 );
1868 }
1869
1870 #[test]
1874 fn a_shard_channel_and_a_pattern_do_not_hear_each_other() {
1875 let (mut r, sub, mut batch) = engine();
1876 let pubr = r.engine_mut().accept();
1877
1878 r.engine_mut().feed(sub, &wire(&[b"SSUBSCRIBE", b"sx"]));
1879 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"s*"]));
1880 pump(&mut r, &mut batch);
1881 r.engine_mut().sink_mut().clear();
1882
1883 r.engine_mut()
1884 .feed(pubr, &wire(&[b"SPUBLISH", b"sx", b"one"]));
1885 pump(&mut r, &mut batch);
1886 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1887 assert_eq!(
1888 r.engine().sink().sent(sub),
1889 b"*3\r\n$8\r\nsmessage\r\n$2\r\nsx\r\n$3\r\none\r\n"
1890 );
1891 r.engine_mut().sink_mut().clear();
1892
1893 r.engine_mut()
1894 .feed(pubr, &wire(&[b"PUBLISH", b"sx", b"two"]));
1895 pump(&mut r, &mut batch);
1896 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1897 assert_eq!(
1898 r.engine().sink().sent(sub),
1899 b"*4\r\n$8\r\npmessage\r\n$2\r\ns*\r\n$2\r\nsx\r\n$3\r\ntwo\r\n"
1900 );
1901 }
1902
1903 #[test]
1907 fn a_subscriber_that_goes_away_leaves_the_registry() {
1908 let (mut r, sub, mut batch) = engine();
1909 let pubr = r.engine_mut().accept();
1910
1911 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1912 pump(&mut r, &mut batch);
1913 r.engine_mut().hangup(sub);
1914 pump(&mut r, &mut batch);
1915 r.engine_mut().sink_mut().clear();
1916
1917 r.engine_mut()
1918 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1919 pump(&mut r, &mut batch);
1920 assert_eq!(r.engine().sink().sent(pubr), b":0\r\n");
1921
1922 let next = r.engine_mut().accept();
1924 assert_eq!(next, sub);
1925 r.engine_mut()
1926 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1927 pump(&mut r, &mut batch);
1928 assert_eq!(r.engine().sink().sent(next), b"");
1929 }
1930
1931 #[test]
1940 fn resp3_delivers_a_message_as_a_push() {
1941 let (mut r, conn, mut batch) = engine();
1942
1943 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1944 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1945 pump(&mut r, &mut batch);
1946 r.engine_mut().sink_mut().clear();
1947
1948 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1949 r.engine_mut().feed(conn, &wire(&[b"PUBLISH", b"a", b"w"]));
1950 pump(&mut r, &mut batch);
1951 assert_eq!(
1952 r.engine().sink().sent(conn),
1953 b"_\r\n:1\r\n>3\r\n$7\r\nmessage\r\n$1\r\na\r\n$1\r\nw\r\n"
1954 );
1955 }
1956
1957 #[test]
1960 fn a_write_reaches_a_keyspace_subscriber() {
1961 let (mut r, sub, mut batch) = engine();
1962 let writer = r.engine_mut().accept();
1963
1964 r.engine_mut().feed(
1965 writer,
1966 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"KEA"]),
1967 );
1968 r.engine_mut()
1969 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1970 pump(&mut r, &mut batch);
1971 r.engine_mut().sink_mut().clear();
1972
1973 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1974 pump(&mut r, &mut batch);
1975 assert_eq!(r.engine().sink().sent(writer), b"+OK\r\n");
1976 assert_eq!(
1977 r.engine().sink().sent(sub),
1978 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1979 $16\r\n__keyspace@0__:k\r\n$3\r\nset\r\n\
1980 *4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1981 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n"
1982 );
1983 }
1984
1985 #[test]
1988 fn a_write_says_nothing_until_the_setting_turns_it_on() {
1989 let (mut r, sub, mut batch) = engine();
1990 let writer = r.engine_mut().accept();
1991
1992 r.engine_mut()
1993 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1994 pump(&mut r, &mut batch);
1995 r.engine_mut().sink_mut().clear();
1996
1997 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1998 pump(&mut r, &mut batch);
1999 assert_eq!(r.engine().sink().sent(sub), b"");
2000 }
2001
2002 #[test]
2005 fn only_the_classes_that_were_asked_for_are_published() {
2006 let (mut r, sub, mut batch) = engine();
2007 let writer = r.engine_mut().accept();
2008
2009 r.engine_mut().feed(
2010 writer,
2011 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"Eg"]),
2012 );
2013 r.engine_mut()
2014 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
2015 pump(&mut r, &mut batch);
2016 r.engine_mut().sink_mut().clear();
2017
2018 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2019 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
2020 pump(&mut r, &mut batch);
2021 assert_eq!(
2022 r.engine().sink().sent(sub),
2023 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
2024 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
2025 );
2026 }
2027
2028 #[test]
2031 fn a_write_with_a_deadline_on_it_says_two_things() {
2032 let (mut r, sub, mut batch) = engine();
2033 let writer = r.engine_mut().accept();
2034
2035 r.engine_mut().feed(
2036 writer,
2037 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
2038 );
2039 r.engine_mut()
2040 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2041 pump(&mut r, &mut batch);
2042 r.engine_mut().sink_mut().clear();
2043
2044 r.engine_mut()
2045 .feed(writer, &wire(&[b"SETEX", b"k", b"100", b"v"]));
2046 pump(&mut r, &mut batch);
2047 assert_eq!(
2048 r.engine().sink().sent(sub),
2049 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2050 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
2051 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2052 $21\r\n__keyevent@0__:expire\r\n$1\r\nk\r\n"
2053 );
2054 }
2055
2056 fn watching() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2062 watching_flags(b"EA")
2063 }
2064
2065 fn watching_flags(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2067 let (mut r, sub, mut batch) = engine();
2068 let writer = r.engine_mut().accept();
2069 r.engine_mut().feed(
2070 writer,
2071 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
2072 );
2073 r.engine_mut()
2074 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2075 pump(&mut r, &mut batch);
2076 r.engine_mut().sink_mut().clear();
2077 (r, sub, writer, batch)
2078 }
2079
2080 fn fired(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
2086 fired_on(r, sub, 0)
2087 }
2088
2089 fn fired_on(r: &Reactor<Wire<Recorder>>, sub: ConnId, db: usize) -> Vec<(String, String)> {
2092 let head = format!("__keyevent@{db}__:");
2093 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
2094 let mut out = Vec::new();
2095 let mut parts = sent.split("\r\n");
2096 while let Some(p) = parts.next() {
2097 let Some(event) = p.strip_prefix(head.as_str()) else {
2098 continue;
2099 };
2100 if event == "*" {
2103 continue;
2104 }
2105 parts.next();
2106 let key = parts.next().unwrap_or_default();
2107 out.push((event.to_owned(), key.to_owned()));
2108 }
2109 out
2110 }
2111
2112 #[test]
2115 fn taking_the_last_of_a_collection_says_the_key_went_with_it() {
2116 let (mut r, sub, writer, mut batch) = watching();
2117
2118 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"k", b"a"]));
2119 r.engine_mut().feed(writer, &wire(&[b"LPOP", b"k"]));
2120 pump(&mut r, &mut batch);
2121 assert_eq!(
2122 fired(&r, sub),
2123 [("rpush", "k"), ("lpop", "k"), ("del", "k")]
2124 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2125 );
2126 }
2127
2128 #[test]
2131 fn a_move_onto_a_member_already_there_says_only_the_removal() {
2132 let (mut r, sub, writer, mut batch) = watching();
2133
2134 r.engine_mut().feed(writer, &wire(&[b"SADD", b"a", b"m"]));
2135 r.engine_mut()
2136 .feed(writer, &wire(&[b"SADD", b"b", b"m", b"n"]));
2137 pump(&mut r, &mut batch);
2138 r.engine_mut().sink_mut().clear();
2139
2140 r.engine_mut()
2141 .feed(writer, &wire(&[b"SMOVE", b"a", b"b", b"m"]));
2142 pump(&mut r, &mut batch);
2143 assert_eq!(
2144 fired(&r, sub),
2145 [("srem", "a"), ("del", "a")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2146 );
2147 }
2148
2149 #[test]
2152 fn a_score_that_did_not_move_says_nothing() {
2153 let (mut r, sub, writer, mut batch) = watching();
2154
2155 r.engine_mut()
2156 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2157 pump(&mut r, &mut batch);
2158 r.engine_mut().sink_mut().clear();
2159
2160 r.engine_mut()
2161 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2162 r.engine_mut()
2163 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"0", b"m"]));
2164 pump(&mut r, &mut batch);
2165 assert_eq!(fired(&r, sub), []);
2166
2167 r.engine_mut()
2170 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"1", b"m"]));
2171 pump(&mut r, &mut batch);
2172 assert_eq!(fired(&r, sub), [("zincr".to_owned(), "z".to_owned())]);
2173 }
2174
2175 #[test]
2178 fn a_stream_write_says_what_the_trim_behind_it_took() {
2179 let (mut r, sub, writer, mut batch) = watching();
2180
2181 r.engine_mut()
2182 .feed(writer, &wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]));
2183 r.engine_mut().feed(
2184 writer,
2185 &wire(&[b"XADD", b"s", b"MAXLEN", b"9", b"2-1", b"f", b"v"]),
2186 );
2187 r.engine_mut().feed(
2188 writer,
2189 &wire(&[b"XADD", b"s", b"MAXLEN", b"1", b"3-1", b"f", b"v"]),
2190 );
2191 pump(&mut r, &mut batch);
2192 assert_eq!(
2193 fired(&r, sub),
2194 [("xadd", "s"), ("xadd", "s"), ("xadd", "s"), ("xtrim", "s")]
2195 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2196 );
2197 }
2198
2199 #[test]
2203 fn acknowledging_an_entry_that_is_already_gone_says_nothing() {
2204 let (mut r, sub, writer, mut batch) = watching();
2205
2206 for cmd in [
2207 wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]),
2208 wire(&[b"XGROUP", b"CREATE", b"s", b"g", b"0"]),
2209 wire(&[b"XREADGROUP", b"GROUP", b"g", b"c", b"STREAMS", b"s", b">"]),
2210 wire(&[b"XDEL", b"s", b"1-1"]),
2211 ] {
2212 r.engine_mut().feed(writer, &cmd);
2213 }
2214 pump(&mut r, &mut batch);
2215 r.engine_mut().sink_mut().clear();
2216
2217 r.engine_mut().feed(
2218 writer,
2219 &wire(&[b"XACKDEL", b"s", b"g", b"IDS", b"1", b"1-1"]),
2220 );
2221 pump(&mut r, &mut batch);
2222 assert_eq!(fired(&r, sub), []);
2223 }
2224
2225 #[test]
2228 fn emptying_a_hash_says_the_key_went_with_the_last_field() {
2229 let (mut r, sub, writer, mut batch) = watching();
2230
2231 r.engine_mut()
2232 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2233 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"a"]));
2234 r.engine_mut()
2237 .feed(writer, &wire(&[b"HDEL", b"h", b"b", b"a"]));
2238 pump(&mut r, &mut batch);
2239 assert_eq!(
2240 fired(&r, sub),
2241 [("hset", "h"), ("hdel", "h"), ("hdel", "h"), ("del", "h")]
2242 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2243 );
2244 }
2245
2246 #[test]
2249 fn a_field_deadline_already_past_reads_as_a_removal() {
2250 let (mut r, sub, writer, mut batch) = watching();
2251
2252 r.engine_mut()
2253 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2254 pump(&mut r, &mut batch);
2255 r.engine_mut().sink_mut().clear();
2256
2257 r.engine_mut().feed(
2258 writer,
2259 &wire(&[b"HEXPIRE", b"h", b"0", b"FIELDS", b"1", b"a"]),
2260 );
2261 r.engine_mut().feed(
2262 writer,
2263 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"b"]),
2264 );
2265 pump(&mut r, &mut batch);
2266 assert_eq!(
2267 fired(&r, sub),
2268 [("hdel", "h"), ("hexpire", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2269 );
2270 }
2271
2272 #[test]
2275 fn a_write_under_a_deadline_already_gone_says_the_write_first() {
2276 let (mut r, sub, writer, mut batch) = watching();
2277
2278 r.engine_mut().feed(
2279 writer,
2280 &wire(&[b"HSETEX", b"h", b"EXAT", b"1", b"FIELDS", b"1", b"a", b"1"]),
2281 );
2282 pump(&mut r, &mut batch);
2283 assert_eq!(
2284 fired(&r, sub),
2285 [("hset", "h"), ("hdel", "h"), ("del", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2286 );
2287 }
2288
2289 #[test]
2292 fn clearing_a_deadline_that_was_never_set_says_nothing() {
2293 let (mut r, sub, writer, mut batch) = watching();
2294
2295 r.engine_mut()
2296 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2297 r.engine_mut().feed(
2298 writer,
2299 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"a"]),
2300 );
2301 pump(&mut r, &mut batch);
2302 r.engine_mut().sink_mut().clear();
2303
2304 r.engine_mut()
2305 .feed(writer, &wire(&[b"HPERSIST", b"h", b"FIELDS", b"1", b"b"]));
2306 r.engine_mut().feed(
2307 writer,
2308 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"1", b"b"]),
2309 );
2310 pump(&mut r, &mut batch);
2311 assert_eq!(fired(&r, sub), []);
2312
2313 r.engine_mut().feed(
2316 writer,
2317 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"2", b"a", b"b"]),
2318 );
2319 pump(&mut r, &mut batch);
2320 assert_eq!(fired(&r, sub), [("hpersist".to_owned(), "h".to_owned())]);
2321 }
2322
2323 #[test]
2326 fn a_key_that_was_not_there_before_says_so() {
2327 let (mut r, sub, writer, mut batch) = watching_flags(b"En");
2328
2329 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2330 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2331 r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"x"]));
2332 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2333 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2334 pump(&mut r, &mut batch);
2335 assert_eq!(
2336 fired(&r, sub),
2337 [("new", "k"), ("new", "l")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2338 );
2339 }
2340
2341 #[test]
2344 fn the_news_of_a_new_key_comes_before_the_write_that_made_it() {
2345 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2346
2347 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2348 r.engine_mut().feed(writer, &wire(&[b"SET", b"b", b"2"]));
2349 pump(&mut r, &mut batch);
2350 r.engine_mut().sink_mut().clear();
2351
2352 r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2356 pump(&mut r, &mut batch);
2357 assert_eq!(
2358 fired(&r, sub),
2359 [("new", "b"), ("rename_from", "a"), ("rename_to", "b")]
2360 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2361 );
2362 }
2363
2364 #[test]
2368 fn writing_over_a_destination_is_not_a_key_arriving() {
2369 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2370
2371 r.engine_mut()
2372 .feed(writer, &wire(&[b"RPUSH", b"l", b"c", b"a", b"b"]));
2373 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"d", b"x"]));
2374 pump(&mut r, &mut batch);
2375 r.engine_mut().sink_mut().clear();
2376
2377 r.engine_mut()
2378 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2379 pump(&mut r, &mut batch);
2380 assert_eq!(fired(&r, sub), [("sortstore".to_owned(), "d".to_owned())]);
2381 r.engine_mut().sink_mut().clear();
2382
2383 r.engine_mut().feed(writer, &wire(&[b"DEL", b"d"]));
2386 r.engine_mut()
2387 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2388 pump(&mut r, &mut batch);
2389 assert_eq!(
2390 fired(&r, sub),
2391 [("del", "d"), ("new", "d"), ("sortstore", "d")]
2392 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2393 );
2394 }
2395
2396 #[test]
2399 fn replacing_a_value_says_what_went_and_whether_the_kind_changed() {
2400 let (mut r, sub, writer, mut batch) = watching_flags(b"Eoc");
2401
2402 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2403 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2404 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2405 r.engine_mut().feed(writer, &wire(&[b"SET", b"l", b"v"]));
2406 pump(&mut r, &mut batch);
2407 assert_eq!(
2408 fired(&r, sub),
2409 [
2410 ("overwritten", "k"),
2411 ("overwritten", "l"),
2412 ("type_changed", "l")
2413 ]
2414 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2415 );
2416 }
2417
2418 #[test]
2421 fn a_write_that_changes_part_of_a_value_has_not_replaced_it() {
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"1"]));
2425 r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"2"]));
2426 r.engine_mut().feed(writer, &wire(&[b"INCR", b"k"]));
2427 r.engine_mut()
2428 .feed(writer, &wire(&[b"SETRANGE", b"k", b"0", b"9"]));
2429 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2430 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2431 pump(&mut r, &mut batch);
2432 assert_eq!(fired(&r, sub), []);
2433 }
2434
2435 #[test]
2439 fn a_rename_says_what_it_replaced_after_saying_what_it_did() {
2440 let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2441
2442 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2443 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"b", b"x"]));
2444 pump(&mut r, &mut batch);
2445 r.engine_mut().sink_mut().clear();
2446
2447 r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2448 pump(&mut r, &mut batch);
2449 assert_eq!(
2450 fired(&r, sub),
2451 [
2452 ("new", "b"),
2453 ("rename_from", "a"),
2454 ("rename_to", "b"),
2455 ("overwritten", "b"),
2456 ("type_changed", "b")
2457 ]
2458 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2459 );
2460 }
2461
2462 #[test]
2465 fn a_store_form_says_what_it_replaced_before_saying_what_it_did() {
2466 let (mut r, sub, writer, mut batch) = watching_flags(b"EAnoc");
2467
2468 r.engine_mut().feed(writer, &wire(&[b"SADD", b"s", b"m"]));
2469 r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"q"]));
2470 pump(&mut r, &mut batch);
2471 r.engine_mut().sink_mut().clear();
2472
2473 r.engine_mut()
2474 .feed(writer, &wire(&[b"SINTERSTORE", b"d", b"s"]));
2475 pump(&mut r, &mut batch);
2476 assert_eq!(
2477 fired(&r, sub),
2478 [
2479 ("overwritten", "d"),
2480 ("type_changed", "d"),
2481 ("sinterstore", "d")
2482 ]
2483 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2484 );
2485 }
2486
2487 #[test]
2490 fn a_bit_write_that_left_the_value_alone_says_nothing() {
2491 let (mut r, sub, writer, mut batch) = watching();
2492
2493 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2497 pump(&mut r, &mut batch);
2498 r.engine_mut().sink_mut().clear();
2499
2500 r.engine_mut()
2501 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"1"]));
2502 r.engine_mut()
2503 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2504 r.engine_mut()
2505 .feed(writer, &wire(&[b"SETBIT", b"k", b"1", b"0"]));
2506 r.engine_mut()
2510 .feed(writer, &wire(&[b"SETBIT", b"k", b"100", b"0"]));
2511 pump(&mut r, &mut batch);
2512 assert_eq!(
2513 fired(&r, sub),
2514 [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2515 );
2516 }
2517
2518 #[test]
2521 fn a_bitfield_that_wrote_the_same_values_back_says_nothing() {
2522 let (mut r, sub, writer, mut batch) = watching();
2523
2524 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"abc"]));
2525 pump(&mut r, &mut batch);
2526 r.engine_mut().sink_mut().clear();
2527
2528 r.engine_mut().feed(
2530 writer,
2531 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"97"]),
2532 );
2533 r.engine_mut()
2534 .feed(writer, &wire(&[b"BITFIELD", b"k", b"GET", b"u8", b"0"]));
2535 r.engine_mut().feed(
2536 writer,
2537 &wire(&[b"BITFIELD", b"k", b"INCRBY", b"u8", b"0", b"0"]),
2538 );
2539 pump(&mut r, &mut batch);
2540 assert_eq!(fired(&r, sub), []);
2541
2542 r.engine_mut().feed(
2545 writer,
2546 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"0", b"98"]),
2547 );
2548 r.engine_mut().feed(
2549 writer,
2550 &wire(&[b"BITFIELD", b"k", b"SET", b"u8", b"800", b"0"]),
2551 );
2552 pump(&mut r, &mut batch);
2553 assert_eq!(
2554 fired(&r, sub),
2555 [("setbit", "k"), ("setbit", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2556 );
2557 }
2558
2559 #[test]
2562 fn the_sketch_commands_say_what_a_mass_add_says() {
2563 let (mut r, sub, writer, mut batch) = watching();
2564
2565 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2566 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h", b"a"]));
2568 r.engine_mut().feed(writer, &wire(&[b"PFADD", b"h"]));
2570 r.engine_mut().feed(writer, &wire(&[b"PFMERGE", b"d"]));
2572 r.engine_mut()
2573 .feed(writer, &wire(&[b"PFMERGE", b"d", b"h"]));
2574 pump(&mut r, &mut batch);
2575 assert_eq!(
2576 fired(&r, sub),
2577 [("pfadd", "h"), ("pfadd", "d"), ("pfadd", "d")]
2578 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2579 );
2580 }
2581
2582 #[test]
2585 fn the_geo_commands_say_what_the_sorted_set_under_them_did() {
2586 let (mut r, sub, writer, mut batch) = watching();
2587
2588 let point: &[&[u8]] = &[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"];
2589 r.engine_mut().feed(writer, &wire(point));
2590 r.engine_mut().feed(writer, &wire(point));
2592 r.engine_mut().feed(
2594 writer,
2595 &wire(&[b"GEOADD", b"g", b"14.0", b"38.115556", b"P"]),
2596 );
2597 r.engine_mut().feed(
2598 writer,
2599 &wire(&[
2600 b"GEORADIUS",
2601 b"g",
2602 b"14.0",
2603 b"38.0",
2604 b"200",
2605 b"km",
2606 b"STORE",
2607 b"d",
2608 ]),
2609 );
2610 r.engine_mut().feed(
2611 writer,
2612 &wire(&[
2613 b"GEOSEARCHSTORE",
2614 b"e",
2615 b"g",
2616 b"FROMLONLAT",
2617 b"14.0",
2618 b"38.0",
2619 b"BYRADIUS",
2620 b"200",
2621 b"km",
2622 ]),
2623 );
2624 pump(&mut r, &mut batch);
2625 assert_eq!(
2626 fired(&r, sub),
2627 [
2628 ("zadd", "g"),
2629 ("zadd", "g"),
2630 ("georadiusstore", "d"),
2631 ("geosearchstore", "e")
2632 ]
2633 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2634 );
2635 }
2636
2637 #[test]
2640 fn a_geo_store_that_found_nothing_takes_the_destination_with_it() {
2641 let (mut r, sub, writer, mut batch) = watching();
2642
2643 r.engine_mut().feed(
2644 writer,
2645 &wire(&[b"GEOADD", b"g", b"13.361389", b"38.115556", b"P"]),
2646 );
2647 r.engine_mut().feed(writer, &wire(&[b"SET", b"d", b"x"]));
2648 pump(&mut r, &mut batch);
2649 r.engine_mut().sink_mut().clear();
2650
2651 r.engine_mut().feed(
2652 writer,
2653 &wire(&[
2654 b"GEORADIUS",
2655 b"g",
2656 b"1.0",
2657 b"1.0",
2658 b"1",
2659 b"km",
2660 b"STORE",
2661 b"d",
2662 ]),
2663 );
2664 r.engine_mut().feed(
2667 writer,
2668 &wire(&[
2669 b"GEORADIUS",
2670 b"g",
2671 b"1.0",
2672 b"1.0",
2673 b"1",
2674 b"km",
2675 b"STORE",
2676 b"d",
2677 ]),
2678 );
2679 pump(&mut r, &mut batch);
2680 assert_eq!(
2681 fired(&r, sub),
2682 [("del", "d")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2683 );
2684 }
2685
2686 #[test]
2690 fn a_key_that_lands_on_another_database_is_new_over_there() {
2691 let (mut r, sub, mut batch) = engine();
2692 let writer = r.engine_mut().accept();
2693 r.engine_mut().feed(
2694 writer,
2695 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EAnoc"]),
2696 );
2697 r.engine_mut().feed(
2698 sub,
2699 &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*", b"__keyevent@1__:*"]),
2700 );
2701 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2702 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2703 pump(&mut r, &mut batch);
2704 r.engine_mut().sink_mut().clear();
2705
2706 r.engine_mut()
2707 .feed(writer, &wire(&[b"COPY", b"a", b"b", b"DB", b"1"]));
2708 r.engine_mut().feed(writer, &wire(&[b"MOVE", b"k", b"1"]));
2709 pump(&mut r, &mut batch);
2710 assert_eq!(
2711 fired_on(&r, sub, 1),
2712 [
2713 ("new", "b"),
2714 ("copy_to", "b"),
2715 ("new", "k"),
2716 ("move_to", "k")
2717 ]
2718 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2719 );
2720 assert_eq!(
2723 fired_on(&r, sub, 0),
2724 [("move_from", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2725 );
2726 }
2727
2728 #[test]
2734 fn a_read_that_found_nothing_says_which_key_it_was() {
2735 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2736
2737 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2738 r.engine_mut()
2739 .feed(writer, &wire(&[b"MGET", b"a", b"nk", b"nk"]));
2740 r.engine_mut()
2741 .feed(writer, &wire(&[b"EXISTS", b"nj", b"a"]));
2742 pump(&mut r, &mut batch);
2743 assert_eq!(
2744 fired(&r, sub),
2745 [("keymiss", "nk"), ("keymiss", "nk"), ("keymiss", "nj")]
2746 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2747 );
2748 }
2749
2750 #[test]
2753 fn only_the_shape_of_a_write_that_reads_says_it() {
2754 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2755
2756 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"v"]));
2759 r.engine_mut().feed(
2760 writer,
2761 &wire(&[b"BITFIELD", b"nk", b"SET", b"u8", b"0", b"1"]),
2762 );
2763 r.engine_mut().feed(writer, &wire(&[b"LPOP", b"nk"]));
2764 pump(&mut r, &mut batch);
2765 assert_eq!(fired(&r, sub), []);
2766
2767 r.engine_mut()
2769 .feed(writer, &wire(&[b"SET", b"nj", b"v", b"GET"]));
2770 r.engine_mut()
2771 .feed(writer, &wire(&[b"BITFIELD", b"nl", b"GET", b"u8", b"0"]));
2772 r.engine_mut().feed(writer, &wire(&[b"GETDEL", b"nm"]));
2773 pump(&mut r, &mut batch);
2774 assert_eq!(
2775 fired(&r, sub),
2776 [("keymiss", "nj"), ("keymiss", "nl"), ("keymiss", "nm")]
2777 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2778 );
2779 }
2780
2781 #[test]
2784 fn a_store_form_says_it_only_for_its_sources() {
2785 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2786
2787 r.engine_mut()
2788 .feed(writer, &wire(&[b"SINTERSTORE", b"dst", b"nk", b"nj"]));
2789 r.engine_mut()
2790 .feed(writer, &wire(&[b"ZUNIONSTORE", b"dst", b"1", b"nz"]));
2791 r.engine_mut()
2792 .feed(writer, &wire(&[b"ZRANGESTORE", b"dst", b"nz", b"0", b"-1"]));
2793 pump(&mut r, &mut batch);
2794 assert_eq!(
2795 fired(&r, sub),
2796 [
2797 ("keymiss", "nk"),
2798 ("keymiss", "nj"),
2799 ("keymiss", "nz"),
2800 ("keymiss", "nz")
2801 ]
2802 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2803 );
2804 }
2805
2806 #[test]
2810 fn the_stream_reads_say_it_for_the_keys_behind_the_keyword() {
2811 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2812
2813 r.engine_mut().feed(
2814 writer,
2815 &wire(&[b"XREAD", b"STREAMS", b"nk", b"nj", b"0", b"0"]),
2816 );
2817 pump(&mut r, &mut batch);
2818 assert_eq!(
2819 fired(&r, sub),
2820 [
2821 ("keymiss", "nk"),
2822 ("keymiss", "nj"),
2823 ("keymiss", "nk"),
2824 ("keymiss", "nj")
2825 ]
2826 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2827 );
2828 }
2829
2830 #[test]
2834 fn an_argument_that_did_not_parse_takes_the_miss_back() {
2835 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2836
2837 r.engine_mut()
2838 .feed(writer, &wire(&[b"GETRANGE", b"nk", b"x", b"-1"]));
2839 r.engine_mut()
2840 .feed(writer, &wire(&[b"LPOS", b"nk", b"a", b"RANK", b"0"]));
2841 pump(&mut r, &mut batch);
2842 assert_eq!(fired(&r, sub), []);
2843
2844 r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2848 pump(&mut r, &mut batch);
2849 r.engine_mut().sink_mut().clear();
2850
2851 r.engine_mut()
2852 .feed(writer, &wire(&[b"SINTER", b"nk", b"s"]));
2853 pump(&mut r, &mut batch);
2854 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2855 }
2856
2857 #[test]
2861 fn a_read_stops_missing_where_it_stops_looking() {
2862 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2863
2864 r.engine_mut().feed(writer, &wire(&[b"SET", b"s", b"v"]));
2865 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"x"]));
2866 pump(&mut r, &mut batch);
2867 r.engine_mut().sink_mut().clear();
2868
2869 r.engine_mut()
2870 .feed(writer, &wire(&[b"SINTER", b"s", b"nk"]));
2871 pump(&mut r, &mut batch);
2872 assert_eq!(fired(&r, sub), []);
2873
2874 r.engine_mut().feed(writer, &wire(&[b"MGET", b"l", b"nk"]));
2877 pump(&mut r, &mut batch);
2878 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nk".to_owned())]);
2879 }
2880
2881 #[test]
2885 fn the_keys_a_sort_pattern_names_say_it_as_they_are_read() {
2886 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2887
2888 r.engine_mut()
2889 .feed(writer, &wire(&[b"RPUSH", b"l", b"1", b"2"]));
2890 r.engine_mut().feed(writer, &wire(&[b"SET", b"w_1", b"5"]));
2891 pump(&mut r, &mut batch);
2892 r.engine_mut().sink_mut().clear();
2893
2894 r.engine_mut().feed(
2895 writer,
2896 &wire(&[b"SORT", b"l", b"BY", b"w_*", b"GET", b"p_*"]),
2897 );
2898 pump(&mut r, &mut batch);
2899 assert_eq!(
2900 fired(&r, sub),
2901 [("keymiss", "w_2"), ("keymiss", "p_2"), ("keymiss", "p_1")]
2902 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2903 );
2904 }
2905
2906 #[test]
2910 fn a_deadline_that_passed_is_news_before_the_miss_it_causes() {
2911 let (mut r, sub, mut batch) = timed();
2912 let writer = r.engine_mut().accept();
2913 r.engine_mut().feed(
2914 writer,
2915 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EgAm"]),
2916 );
2917 r.engine_mut()
2918 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2919 r.engine_mut()
2920 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
2921 pump(&mut r, &mut batch);
2922 r.engine_mut().sink_mut().clear();
2923
2924 r.engine().server().advance_clock_ms(50);
2925 r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
2926 pump(&mut r, &mut batch);
2927 assert_eq!(
2928 fired(&r, sub),
2929 [("expired", "k"), ("keymiss", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2930 );
2931 }
2932
2933 #[test]
2936 fn a_module_read_says_it_the_way_a_core_read_does() {
2937 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2938
2939 r.engine_mut().feed(writer, &wire(&[b"JSON.GET", b"nk"]));
2940 r.engine_mut().feed(writer, &wire(&[b"TS.GET", b"nj"]));
2941 r.engine_mut()
2942 .feed(writer, &wire(&[b"BF.EXISTS", b"nl", b"x"]));
2943 r.engine_mut().feed(writer, &wire(&[b"TDIGEST.MIN", b"nm"]));
2944 r.engine_mut().feed(writer, &wire(&[b"TOPK.LIST", b"nn"]));
2945 r.engine_mut().feed(writer, &wire(&[b"CMS.INFO", b"no"]));
2946 r.engine_mut().feed(writer, &wire(&[b"VCARD", b"np"]));
2947 pump(&mut r, &mut batch);
2948 assert_eq!(
2949 fired(&r, sub),
2950 [
2951 ("keymiss", "nk"),
2952 ("keymiss", "nj"),
2953 ("keymiss", "nl"),
2954 ("keymiss", "nm"),
2955 ("keymiss", "nn"),
2956 ("keymiss", "no"),
2957 ("keymiss", "np")
2958 ]
2959 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2960 );
2961
2962 r.engine_mut().sink_mut().clear();
2965 r.engine_mut()
2966 .feed(writer, &wire(&[b"JSON.MGET", b"nk", b"nj", b"$"]));
2967 pump(&mut r, &mut batch);
2968 assert_eq!(
2969 fired(&r, sub),
2970 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2971 );
2972 }
2973
2974 #[test]
2978 fn the_quiet_module_commands_stay_quiet() {
2979 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
2980
2981 r.engine_mut()
2982 .feed(writer, &wire(&[b"JSON.SET", b"nk", b"$", b"1"]));
2983 r.engine_mut()
2984 .feed(writer, &wire(&[b"BF.ADD", b"nj", b"x"]));
2985 r.engine_mut()
2986 .feed(writer, &wire(&[b"TS.ADD", b"nl", b"1000", b"1"]));
2987 r.engine_mut().feed(writer, &wire(&[b"TS.INFO", b"nm"]));
2988 r.engine_mut().feed(writer, &wire(&[b"CF.COMPACT", b"nn"]));
2989 r.engine_mut()
2990 .feed(writer, &wire(&[b"JSON.DEBUG", b"HELP"]));
2991 r.engine_mut()
2992 .feed(writer, &wire(&[b"FT.GET", b"ni", b"no"]));
2993 r.engine_mut()
2994 .feed(writer, &wire(&[b"FT.SEARCH", b"ni", b"*"]));
2995 pump(&mut r, &mut batch);
2996 assert_eq!(fired(&r, sub), []);
2997
2998 r.engine_mut()
3000 .feed(writer, &wire(&[b"JSON.DEBUG", b"MEMORY", b"np"]));
3001 r.engine_mut()
3002 .feed(writer, &wire(&[b"FT.SUGGET", b"nq", b"x"]));
3003 r.engine_mut().feed(writer, &wire(&[b"FT.SUGLEN", b"nr"]));
3004 pump(&mut r, &mut batch);
3005 assert_eq!(
3006 fired(&r, sub),
3007 [("keymiss", "np"), ("keymiss", "nq"), ("keymiss", "nr")]
3008 .map(|(e, k)| (e.to_owned(), k.to_owned()))
3009 );
3010 }
3011
3012 #[test]
3019 fn a_module_read_keeps_the_miss_a_later_argument_spoiled() {
3020 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
3021
3022 r.engine_mut()
3023 .feed(writer, &wire(&[b"JSON.GET", b"nk", b"$..["]));
3024 r.engine_mut().feed(
3025 writer,
3026 &wire(&[b"VSIM", b"nj", b"ELE", b"e", b"COUNT", b"x"]),
3027 );
3028 pump(&mut r, &mut batch);
3029 assert_eq!(
3030 fired(&r, sub),
3031 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3032 );
3033 }
3034
3035 #[test]
3038 fn the_module_merges_stop_at_the_first_empty_source() {
3039 let (mut r, sub, writer, mut batch) = watching_flags(b"Em");
3040
3041 r.engine_mut().feed(
3042 writer,
3043 &wire(&[b"TDIGEST.MERGE", b"nk", b"2", b"nj", b"nl"]),
3044 );
3045 pump(&mut r, &mut batch);
3046 assert_eq!(
3047 fired(&r, sub),
3048 [("keymiss", "nk"), ("keymiss", "nj")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3049 );
3050
3051 r.engine_mut().sink_mut().clear();
3055 r.engine_mut()
3056 .feed(writer, &wire(&[b"CMS.MERGE", b"nk", b"1", b"nj"]));
3057 pump(&mut r, &mut batch);
3058 assert_eq!(fired(&r, sub), []);
3059
3060 r.engine_mut()
3063 .feed(writer, &wire(&[b"CMS.INITBYDIM", b"cm", b"100", b"5"]));
3064 pump(&mut r, &mut batch);
3065 r.engine_mut().sink_mut().clear();
3066
3067 r.engine_mut()
3068 .feed(writer, &wire(&[b"CMS.MERGE", b"cm", b"2", b"nj", b"nl"]));
3069 pump(&mut r, &mut batch);
3070 assert_eq!(fired(&r, sub), [("keymiss".to_owned(), "nj".to_owned())]);
3071 }
3072
3073 fn watching_fields(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3079 let (mut r, sub, mut batch) = engine();
3080 let writer = r.engine_mut().accept();
3081 r.engine_mut().feed(
3082 writer,
3083 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
3084 );
3085 r.engine_mut()
3086 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__subkey*@0__:*"]));
3087 pump(&mut r, &mut batch);
3088 r.engine_mut().sink_mut().clear();
3089 (r, sub, writer, batch)
3090 }
3091
3092 fn carried(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
3098 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
3099 let mut out = Vec::new();
3100 let mut parts = sent.split("\r\n");
3101 while let Some(p) = parts.next() {
3102 if p != "pmessage" {
3103 continue;
3104 }
3105 let mut next = || {
3108 parts.next();
3109 parts.next().unwrap_or_default().to_owned()
3110 };
3111 next();
3112 let channel = next();
3113 out.push((channel, next()));
3114 }
3115 out
3116 }
3117
3118 #[test]
3122 fn the_subkey_channels_carry_the_fields_an_event_touched() {
3123 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3124
3125 r.engine_mut()
3126 .feed(writer, &wire(&[b"HSET", b"h", b"a,b", b"1", b"c", b"2"]));
3127 pump(&mut r, &mut batch);
3128 assert_eq!(
3129 carried(&r, sub),
3130 [
3131 ("__subkeyspace@0__:h", "hset|3:a,b,1:c"),
3132 ("__subkeyevent@0__:hset", "1:h|3:a,b,1:c"),
3133 ("__subkeyspaceitem@0__:h\na,b", "hset"),
3134 ("__subkeyspaceitem@0__:h\nc", "hset"),
3135 ("__subkeyspaceevent@0__:hset|h", "3:a,b,1:c"),
3136 ]
3137 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3138 );
3139 }
3140
3141 #[test]
3145 fn a_key_holding_a_newline_skips_the_per_field_channel() {
3146 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
3147
3148 r.engine_mut()
3149 .feed(writer, &wire(&[b"HSET", b"h\nx", b"f", b"1"]));
3150 pump(&mut r, &mut batch);
3151 assert_eq!(
3152 carried(&r, sub),
3153 [
3154 ("__subkeyspace@0__:h\nx", "hset|1:f"),
3155 ("__subkeyevent@0__:hset", "3:h\nx|1:f"),
3156 ("__subkeyspaceevent@0__:hset|h\nx", "1:f"),
3157 ]
3158 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3159 );
3160 }
3161
3162 #[test]
3166 fn an_event_with_no_fields_stays_off_the_subkey_channels() {
3167 let (mut r, sub, writer, mut batch) = watching_fields(b"AS");
3168
3169 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3170 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
3171 r.engine_mut()
3172 .feed(writer, &wire(&[b"HSET", b"h", b"f", b"1"]));
3173 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"f"]));
3174 pump(&mut r, &mut batch);
3175 assert_eq!(
3176 carried(&r, sub),
3177 [
3178 ("__subkeyspace@0__:h", "hset|1:f"),
3179 ("__subkeyspace@0__:h", "hdel|1:f"),
3180 ]
3181 .map(|(c, p)| (c.to_owned(), p.to_owned()))
3182 );
3183 }
3184
3185 fn watching_clock() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
3191 let (mut r, sub, mut batch) = timed();
3192 let writer = r.engine_mut().accept();
3193 r.engine_mut().feed(
3194 writer,
3195 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3196 );
3197 r.engine_mut()
3198 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3199 pump(&mut r, &mut batch);
3200 r.engine_mut().sink_mut().clear();
3201 (r, sub, writer, batch)
3202 }
3203
3204 #[test]
3208 fn a_deadline_that_passed_is_news_when_a_reader_finds_it() {
3209 let (mut r, sub, writer, mut batch) = watching_clock();
3210
3211 r.engine_mut()
3212 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3213 pump(&mut r, &mut batch);
3214 r.engine_mut().sink_mut().clear();
3215
3216 r.engine().server().advance_clock_ms(50);
3217 r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
3218 pump(&mut r, &mut batch);
3219 assert_eq!(
3220 fired(&r, sub),
3221 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned())),
3222 "and not a del alongside it, which is a different piece of news"
3223 );
3224 }
3225
3226 #[test]
3234 fn a_deadline_that_passed_is_news_with_nobody_reading() {
3235 let (mut r, sub, writer, mut batch) = watching_clock();
3236
3237 r.engine_mut()
3238 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
3239 pump(&mut r, &mut batch);
3240 r.engine_mut().sink_mut().clear();
3241
3242 r.engine().server().advance_clock_ms(50);
3243 pump(&mut r, &mut batch);
3245 assert_eq!(
3246 fired(&r, sub),
3247 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
3248 );
3249
3250 r.engine_mut().sink_mut().clear();
3251 pump(&mut r, &mut batch);
3252 assert!(fired(&r, sub).is_empty(), "and it only goes once");
3253 }
3254
3255 #[test]
3259 fn a_key_a_limit_took_says_it_was_evicted() {
3260 let (mut r, sub, writer, mut batch) = watching();
3261
3262 let val = vec![b'v'; 256];
3263 for i in 0..2000u32 {
3264 let k = format!("key:{i:08}");
3265 r.engine_mut()
3266 .feed(writer, &wire(&[b"SET", k.as_bytes(), &val]));
3267 }
3268 pump(&mut r, &mut batch);
3269 r.engine().server().refresh_memory();
3270 let full = r.engine().server().memory_bytes();
3271 r.engine_mut().sink_mut().clear();
3272
3273 let limit = (full / 2).to_string();
3276 r.engine_mut().feed(
3277 writer,
3278 &wire(&[b"CONFIG", b"SET", b"maxmemory-policy", b"allkeys-random"]),
3279 );
3280 r.engine_mut().feed(
3281 writer,
3282 &wire(&[b"CONFIG", b"SET", b"maxmemory", limit.as_bytes()]),
3283 );
3284 r.engine_mut()
3285 .feed(writer, &wire(&[b"SET", b"newcomer", &val]));
3286 pump(&mut r, &mut batch);
3287
3288 let events = fired(&r, sub);
3289 assert!(
3290 events.iter().any(|(e, _)| e == "evicted"),
3291 "the write made room and never said so: {events:?}"
3292 );
3293 assert!(
3294 events
3295 .iter()
3296 .all(|(e, k)| e != "evicted" || k != "newcomer"),
3297 "the key the write was for is the one key it cannot have taken"
3298 );
3299 }
3300
3301 #[test]
3304 fn a_transaction_publishes_between_its_commands_and_not_after_them() {
3305 let (mut r, sub, mut batch) = engine();
3306 let writer = r.engine_mut().accept();
3307
3308 r.engine_mut().feed(
3309 writer,
3310 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
3311 );
3312 r.engine_mut()
3313 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
3314 pump(&mut r, &mut batch);
3315 r.engine_mut().sink_mut().clear();
3316
3317 r.engine_mut().feed(writer, &wire(&[b"MULTI"]));
3318 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
3319 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
3320 r.engine_mut().feed(writer, &wire(&[b"EXEC"]));
3321 pump(&mut r, &mut batch);
3322 assert_eq!(
3323 r.engine().sink().sent(sub),
3324 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3325 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
3326 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
3327 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
3328 );
3329 }
3330
3331 #[test]
3332 fn a_reply_the_socket_would_not_take_is_offered_again() {
3333 let mut r = Reactor::inline(Wire::new(Trickle::default()));
3334 let conn = r.engine_mut().accept();
3335 let mut batch = Vec::new();
3336
3337 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3338 pump(&mut r, &mut batch);
3339 assert_eq!(r.engine().sink().sent, b"+PONG\r\n");
3341 assert_eq!(r.engine().sink().writes, 2);
3342 }
3343 #[test]
3347 fn client_reply_skip_covers_the_command_after_it_and_nothing_else() {
3348 let (mut r, conn, mut batch) = engine();
3349
3350 r.engine_mut()
3351 .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"SKIP"]));
3352 r.engine_mut().feed(conn, &wire(&[b"SET", b"a", b"1"]));
3353 r.engine_mut().feed(conn, &wire(&[b"SET", b"b", b"2"]));
3354 pump(&mut r, &mut batch);
3355 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
3358 }
3359
3360 #[test]
3361 fn client_reply_off_stays_off_until_it_is_turned_back_on() {
3362 let (mut r, conn, mut batch) = engine();
3363
3364 r.engine_mut()
3365 .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"OFF"]));
3366 r.engine_mut().feed(conn, &wire(&[b"SET", b"c", b"3"]));
3367 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3368 r.engine_mut()
3369 .feed(conn, &wire(&[b"CLIENT", b"REPLY", b"ON"]));
3370 r.engine_mut().feed(conn, &wire(&[b"PING"]));
3371 pump(&mut r, &mut batch);
3372 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n+PONG\r\n");
3375
3376 r.engine_mut().sink_mut().clear();
3378 r.engine_mut().feed(conn, &wire(&[b"GET", b"c"]));
3379 pump(&mut r, &mut batch);
3380 assert_eq!(r.engine().sink().sent(conn), b"$1\r\n3\r\n");
3381 }
3382
3383 #[test]
3386 fn a_connection_reports_the_socket_it_was_opened_on() {
3387 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3388 let conn = r
3389 .engine_mut()
3390 .accept_from("10.0.0.7:54321", "10.0.0.1:6379", 11, false);
3391 let mut batch = Vec::new();
3392
3393 r.engine_mut().feed(conn, &wire(&[b"CLIENT", b"INFO"]));
3394 pump(&mut r, &mut batch);
3395 let sent = String::from_utf8_lossy(r.engine().sink().sent(conn)).into_owned();
3396 assert!(sent.contains("addr=10.0.0.7:54321"), "{sent}");
3397 assert!(sent.contains("laddr=10.0.0.1:6379"), "{sent}");
3398 assert!(sent.contains("fd=11"), "{sent}");
3399 }
3400
3401 #[test]
3404 fn a_connection_counts_the_bytes_and_the_commands_that_went_over_it() {
3405 let (mut r, conn, mut batch) = engine();
3406 let mut stream = wire(&[b"PING"]);
3407 stream.extend(wire(&[b"PING"]));
3408 let sent_in = stream.len();
3409
3410 r.engine_mut().feed(conn, &stream);
3411 pump(&mut r, &mut batch);
3412 r.engine_mut().sink_mut().clear();
3413
3414 r.engine_mut().feed(conn, &wire(&[b"CLIENT", b"INFO"]));
3415 pump(&mut r, &mut batch);
3416 let sent = String::from_utf8_lossy(r.engine().sink().sent(conn)).into_owned();
3417 assert!(sent.contains("tot-cmds=2"), "{sent}");
3421 assert!(sent.contains("read-events=2"), "{sent}");
3422 assert!(
3423 sent.contains(&format!("tot-net-in={}", sent_in + 26)),
3424 "{sent}"
3425 );
3426 assert!(sent.contains("tot-net-out=14"), "{sent}");
3427 }
3428
3429 #[test]
3433 fn client_list_reports_every_connection_and_not_just_the_one_asking() {
3434 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3435 let one = r
3436 .engine_mut()
3437 .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3438 let two = r
3439 .engine_mut()
3440 .accept_from("10.0.0.8:2222", "10.0.0.1:6379", 12, false);
3441 let mut batch = Vec::new();
3442
3443 r.engine_mut()
3444 .feed(two, &wire(&[b"CLIENT", b"SETNAME", b"worker"]));
3445 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3446 pump(&mut r, &mut batch);
3447
3448 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3449 let lines: Vec<&str> = sent.lines().filter(|l| l.starts_with("id=")).collect();
3450 assert_eq!(lines.len(), 2, "{sent}");
3451 assert!(lines[0].contains("addr=10.0.0.7:1111"), "{sent}");
3452 assert!(lines[0].contains("cmd=client|list"), "{sent}");
3453 assert!(lines[1].contains("addr=10.0.0.8:2222"), "{sent}");
3454 assert!(lines[1].contains("name=worker"), "{sent}");
3455 assert!(lines[1].contains("cmd=client|setname"), "{sent}");
3456 }
3457
3458 #[test]
3461 fn client_list_keeps_the_order_the_connections_were_opened_in() {
3462 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3463 let one = r.engine_mut().accept();
3464 let two = r.engine_mut().accept();
3465 let three = r.engine_mut().accept();
3466 let mut batch = Vec::new();
3467
3468 r.engine_mut().hangup(two);
3469 r.engine_mut().feed(three, &wire(&[b"CLIENT", b"LIST"]));
3470 pump(&mut r, &mut batch);
3471
3472 let sent = String::from_utf8_lossy(r.engine().sink().sent(three)).into_owned();
3473 let ids: Vec<&str> = sent
3474 .lines()
3475 .filter(|l| l.starts_with("id="))
3476 .map(|l| l.split(' ').next().unwrap_or(""))
3477 .collect();
3478 assert_eq!(ids, vec!["id=1", "id=3"], "{sent}");
3479 let _ = one;
3480 }
3481
3482 #[test]
3486 fn client_kill_closes_the_connection_it_names_and_answers_a_count() {
3487 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3488 let one = r
3489 .engine_mut()
3490 .accept_from("10.0.0.7:1111", "10.0.0.1:6379", 11, false);
3491 let two = r
3492 .engine_mut()
3493 .accept_from("10.0.0.8:2222", "10.0.0.1:6379", 12, false);
3494 let mut batch = Vec::new();
3495
3496 r.engine_mut()
3497 .feed(one, &wire(&[b"CLIENT", b"KILL", b"ADDR", b"10.0.0.8:2222"]));
3498 pump(&mut r, &mut batch);
3499
3500 assert_eq!(r.engine().sink().sent(one), b":1\r\n");
3501 assert!(r.engine().sink().was_closed(two), "the named one went away");
3502 assert!(!r.engine().sink().was_closed(one), "the caller did not");
3503 }
3504
3505 #[test]
3508 fn the_old_kill_takes_one_address_and_will_take_the_caller() {
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 mut batch = Vec::new();
3514
3515 r.engine_mut()
3516 .feed(one, &wire(&[b"CLIENT", b"KILL", b"10.0.0.9:9999"]));
3517 pump(&mut r, &mut batch);
3518 assert_eq!(r.engine().sink().sent(one), b"-ERR No such client\r\n");
3519
3520 r.engine_mut().sink_mut().clear();
3521 r.engine_mut()
3522 .feed(one, &wire(&[b"CLIENT", b"KILL", b"10.0.0.7:1111"]));
3523 pump(&mut r, &mut batch);
3524 assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
3525 assert!(r.engine().sink().was_closed(one), "it took itself");
3526 }
3527
3528 #[test]
3531 fn a_kill_spares_the_caller_unless_it_is_told_not_to() {
3532 let (mut r, conn, mut batch) = engine();
3533 r.engine_mut()
3534 .feed(conn, &wire(&[b"CLIENT", b"KILL", b"TYPE", b"normal"]));
3535 pump(&mut r, &mut batch);
3536 assert_eq!(r.engine().sink().sent(conn), b":0\r\n");
3537 assert!(!r.engine().sink().was_closed(conn));
3538
3539 r.engine_mut().sink_mut().clear();
3540 r.engine_mut().feed(
3541 conn,
3542 &wire(&[b"CLIENT", b"KILL", b"TYPE", b"normal", b"SKIPME", b"no"]),
3543 );
3544 pump(&mut r, &mut batch);
3545 assert_eq!(r.engine().sink().sent(conn), b":1\r\n");
3546 assert!(r.engine().sink().was_closed(conn));
3547 }
3548
3549 #[test]
3552 fn a_connection_that_went_away_is_off_the_list() {
3553 let mut r = Reactor::inline(Wire::new(Recorder::new()));
3554 let one = r.engine_mut().accept();
3555 let two = r.engine_mut().accept();
3556 let mut batch = Vec::new();
3557 assert_eq!(r.engine().server().client_count(), 2);
3558
3559 r.engine_mut().hangup(two);
3560 assert_eq!(r.engine().server().client_count(), 1);
3561
3562 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3563 pump(&mut r, &mut batch);
3564 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3565 assert_eq!(sent.lines().filter(|l| l.starts_with("id=")).count(), 1);
3566 }
3567
3568 #[test]
3571 fn a_write_pause_holds_the_writes_and_lets_the_reads_through() {
3572 let (mut r, one, mut batch) = timed();
3573 let two = r.engine_mut().accept();
3574
3575 r.engine_mut()
3576 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3577 pump(&mut r, &mut batch);
3578 assert_eq!(r.engine().sink().sent(one), b"+OK\r\n");
3579
3580 r.engine_mut().sink_mut().clear();
3581 r.engine_mut().feed(two, &wire(&[b"GET", b"k"]));
3582 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3583 pump(&mut r, &mut batch);
3584 assert_eq!(
3585 r.engine().sink().sent(two),
3586 b"$-1\r\n",
3587 "the read answered and the write is being held"
3588 );
3589 assert_eq!(r.engine().waiting(), 1, "the held connection");
3590
3591 r.engine_mut().sink_mut().clear();
3592 r.engine().server().advance_clock_ms(500);
3593 pump(&mut r, &mut batch);
3594 assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3595 assert_eq!(r.engine().waiting(), 0);
3596 }
3597
3598 #[test]
3600 fn an_all_pause_holds_every_command_and_cannot_be_called_off() {
3601 let (mut r, one, mut batch) = timed();
3602 let two = r.engine_mut().accept();
3603
3604 r.engine_mut()
3605 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3606 pump(&mut r, &mut batch);
3607
3608 r.engine_mut().sink_mut().clear();
3609 r.engine_mut().feed(two, &wire(&[b"PING"]));
3610 r.engine_mut().feed(two, &wire(&[b"CLIENT", b"UNPAUSE"]));
3611 pump(&mut r, &mut batch);
3612 assert_eq!(r.engine().sink().sent(two), b"", "not even the ping");
3613
3614 r.engine().server().advance_clock_ms(499);
3615 pump(&mut r, &mut batch);
3616 assert_eq!(r.engine().sink().sent(two), b"", "still inside the pause");
3617
3618 r.engine().server().advance_clock_ms(1);
3619 pump(&mut r, &mut batch);
3620 assert_eq!(
3621 r.engine().sink().sent(two),
3622 b"+PONG\r\n+OK\r\n",
3623 "both, in the order they were sent"
3624 );
3625 }
3626
3627 #[test]
3629 fn a_shorter_pause_does_not_shorten_the_one_already_running() {
3630 let (mut r, one, mut batch) = timed();
3631 let two = r.engine_mut().accept();
3632
3633 r.engine_mut()
3634 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3635 r.engine_mut()
3636 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"10", b"WRITE"]));
3637 pump(&mut r, &mut batch);
3638 assert_eq!(r.engine().server().pause_ends(), START_MS + 500);
3639
3640 r.engine_mut().sink_mut().clear();
3641 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3642 r.engine().server().advance_clock_ms(100);
3643 pump(&mut r, &mut batch);
3644 assert_eq!(r.engine().sink().sent(two), b"", "the longer end holds");
3645
3646 r.engine().server().advance_clock_ms(400);
3647 pump(&mut r, &mut batch);
3648 assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3649 }
3650
3651 #[test]
3653 fn a_write_pause_on_top_of_an_all_pause_still_holds_the_reads() {
3654 let (mut r, one, mut batch) = timed();
3655 let two = r.engine_mut().accept();
3656
3657 r.engine_mut()
3658 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3659 pump(&mut r, &mut batch);
3660 r.engine_mut()
3663 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3664
3665 r.engine_mut().sink_mut().clear();
3666 r.engine_mut().feed(two, &wire(&[b"GET", b"k"]));
3667 r.engine().server().advance_clock_ms(200);
3668 pump(&mut r, &mut batch);
3669 assert_eq!(r.engine().sink().sent(two), b"", "still everything");
3670 }
3671
3672 #[test]
3674 fn unpause_lets_go_of_a_write_pause_at_once() {
3675 let (mut r, one, mut batch) = timed();
3676 let two = r.engine_mut().accept();
3677
3678 r.engine_mut()
3679 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"5000", b"WRITE"]));
3680 pump(&mut r, &mut batch);
3681 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3682 pump(&mut r, &mut batch);
3683 assert_eq!(r.engine().sink().sent(two), b"");
3684
3685 r.engine_mut().sink_mut().clear();
3686 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"UNPAUSE"]));
3687 pump(&mut r, &mut batch);
3688 assert_eq!(r.engine().sink().sent(two), b"+OK\r\n");
3689 }
3690
3691 #[test]
3694 fn a_write_pause_holds_an_exec_only_when_the_transaction_writes() {
3695 let (mut r, one, mut batch) = timed();
3696 let two = r.engine_mut().accept();
3697 let three = r.engine_mut().accept();
3698
3699 for conn in [two, three] {
3700 r.engine_mut().feed(conn, &wire(&[b"MULTI"]));
3701 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
3702 }
3703 r.engine_mut().feed(three, &wire(&[b"SET", b"k", b"v"]));
3704 pump(&mut r, &mut batch);
3705
3706 r.engine_mut()
3707 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3708 pump(&mut r, &mut batch);
3709
3710 r.engine_mut().sink_mut().clear();
3711 r.engine_mut().feed(two, &wire(&[b"EXEC"]));
3712 r.engine_mut().feed(three, &wire(&[b"EXEC"]));
3713 pump(&mut r, &mut batch);
3714 assert_eq!(r.engine().sink().sent(two), b"*1\r\n$-1\r\n", "reads only");
3715 assert_eq!(r.engine().sink().sent(three), b"", "one write in it");
3716
3717 r.engine_mut().sink_mut().clear();
3718 r.engine().server().advance_clock_ms(500);
3719 pump(&mut r, &mut batch);
3720 assert_eq!(r.engine().sink().sent(three), b"*2\r\n$-1\r\n+OK\r\n");
3721 }
3722
3723 #[test]
3726 fn a_held_connection_that_hangs_up_lets_go_of_its_slot() {
3727 let (mut r, one, mut batch) = timed();
3728 let two = r.engine_mut().accept();
3729
3730 r.engine_mut()
3731 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"ALL"]));
3732 pump(&mut r, &mut batch);
3733 r.engine_mut().feed(two, &wire(&[b"PING"]));
3734 pump(&mut r, &mut batch);
3735 assert_eq!(r.engine().waiting(), 1);
3736
3737 r.engine_mut().hangup(two);
3738 pump(&mut r, &mut batch);
3739 assert_eq!(r.engine().server().client_count(), 1);
3740
3741 r.engine().server().advance_clock_ms(500);
3742 pump(&mut r, &mut batch);
3743 assert_eq!(r.engine().waiting(), 0, "nothing left holding a slot");
3744 }
3745
3746 #[test]
3749 fn a_held_connection_names_the_command_it_is_waiting_to_run() {
3750 let (mut r, one, mut batch) = timed();
3751 let two = r.engine_mut().accept();
3752
3753 r.engine_mut()
3754 .feed(one, &wire(&[b"CLIENT", b"PAUSE", b"500", b"WRITE"]));
3755 pump(&mut r, &mut batch);
3756 r.engine_mut().feed(two, &wire(&[b"SET", b"k", b"v"]));
3757 pump(&mut r, &mut batch);
3758
3759 r.engine_mut().sink_mut().clear();
3760 r.engine().server().advance_clock_ms(0);
3761 r.engine_mut().feed(one, &wire(&[b"CLIENT", b"LIST"]));
3762 r.engine().server().advance_clock_ms(500);
3766 pump(&mut r, &mut batch);
3767 let sent = String::from_utf8_lossy(r.engine().sink().sent(one)).into_owned();
3768 assert!(sent.contains("cmd=set"), "{sent}");
3769 }
3770}