1use spate_core::feed::{
12 Confirmation, Confirmer, Delivery, Depth, DepthOf, DepthReading, Feed, FeedError,
13 FeedErrorKind, FeedWaker, Receipt, Unit, confirmation, depth_reading,
14};
15use spate_core::hash::{FastMap, FastSet};
16use std::collections::{BTreeMap, VecDeque};
17use std::sync::{Arc, Mutex, MutexGuard};
18use std::time::Duration;
19
20#[derive(Clone, Copy, Debug)]
22enum Call {
23 Receive,
24 Renew,
25 Acknowledge,
26 Fail,
27}
28
29impl Call {
30 fn name(self) -> &'static str {
31 match self {
32 Call::Receive => "receive",
33 Call::Renew => "renew",
34 Call::Acknowledge => "acknowledge",
35 Call::Fail => "fail",
36 }
37 }
38}
39
40#[derive(Default)]
41struct State {
42 queued: VecDeque<Delivery>,
44 held: BTreeMap<Receipt, Delivery>,
46 counts: FastMap<String, u32>,
50 scripted: FastSet<Receipt>,
52 next_receipt: u64,
53 delivered: Vec<Delivery>,
54 acknowledged: Vec<Receipt>,
55 failed: Vec<(Receipt, String)>,
56 renewed: Vec<Receipt>,
57 gone: Vec<Receipt>,
58 published: Vec<Unit>,
59 dead_lettered: Vec<Unit>,
60 publish_outcomes: VecDeque<FeedErrorKind>,
61 answers: [VecDeque<FeedErrorKind>; 4],
63 hold_publishes: bool,
64 held_publishes: Vec<(Unit, Confirmer)>,
65 feed_depths: VecDeque<Result<Depth, FeedError>>,
67 dead_letter_depths: VecDeque<Result<Depth, FeedError>>,
69 feed_depth_reads: usize,
70 dead_letter_depth_reads: usize,
71 hands_back: bool,
73 stopped_receiving: usize,
74 handed_back: Vec<Receipt>,
75 closes: Vec<Duration>,
76 waker: Option<FeedWaker>,
77}
78
79impl State {
80 fn queue(&mut self, unit: Unit, deliveries: u32) -> Receipt {
81 self.next_receipt += 1;
82 let receipt = Receipt(self.next_receipt);
83 let delivery = Delivery::new(unit, receipt, deliveries);
84 self.queued.push_back(delivery);
85 receipt
86 }
87
88 fn lapse(&mut self, receipt: Receipt) -> Option<Delivery> {
90 if let Some(delivery) = self.held.remove(&receipt) {
91 return Some(delivery);
92 }
93 let at = self.queued.iter().position(|d| d.receipt == receipt)?;
94 self.queued.remove(at)
95 }
96
97 fn on_held(
100 &mut self,
101 receipt: Receipt,
102 f: impl FnOnce(&mut State) -> Result<(), FeedError>,
103 ) -> Result<(), FeedError> {
104 if self.held.contains_key(&receipt) {
105 f(self)
106 } else {
107 self.gone.push(receipt);
108 Err(FeedError::new(
109 FeedErrorKind::Gone,
110 format!("{receipt} is not held by the scripted feed"),
111 ))
112 }
113 }
114
115 fn answer(&mut self, call: Call) -> Result<(), FeedError> {
118 match self.answers[call as usize].pop_front() {
119 Some(kind) => Err(FeedError::new(kind, "refused by the feed script")),
120 None => Ok(()),
121 }
122 }
123
124 fn wake(&self) {
125 if let Some(waker) = &self.waker {
126 waker.wake();
127 }
128 }
129}
130
131impl std::fmt::Debug for State {
132 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 f.debug_struct("State")
134 .field("queued", &self.queued.len())
135 .field("held", &self.held.len())
136 .field("acknowledged", &self.acknowledged.len())
137 .finish_non_exhaustive()
138 }
139}
140
141#[derive(Debug)]
153pub struct ScriptedFeed {
154 state: Arc<Mutex<State>>,
155}
156
157#[derive(Clone, Debug)]
162pub struct FeedScript {
163 state: Arc<Mutex<State>>,
164}
165
166#[must_use]
191pub fn scripted_feed() -> (ScriptedFeed, FeedScript) {
192 let state = Arc::new(Mutex::new(State::default()));
193 (
194 ScriptedFeed {
195 state: Arc::clone(&state),
196 },
197 FeedScript { state },
198 )
199}
200
201impl FeedScript {
202 pub fn deliver(&self, unit: Unit) -> Receipt {
208 let mut state = self.lock();
209 let count = state.counts.entry(unit.id.clone()).or_default();
210 *count += 1;
211 let deliveries = *count;
212 let receipt = state.queue(unit, deliveries);
213 state.scripted.insert(receipt);
214 state.wake();
215 receipt
216 }
217
218 pub fn redeliver(&self, receipt: Receipt) -> Receipt {
226 let mut state = self.lock();
227 let Some(delivery) = state.lapse(receipt) else {
228 panic!("redeliver: {receipt} is neither queued nor held");
229 };
230 let scripted = state.scripted.remove(&receipt);
233 let deliveries = match state.counts.get_mut(&delivery.unit.id) {
234 Some(count) if scripted => {
235 *count += 1;
236 *count
237 }
238 _ => delivery.deliveries + 1,
239 };
240 let receipt = state.queue(delivery.unit, deliveries);
241 if scripted {
242 state.scripted.insert(receipt);
243 }
244 state.wake();
245 receipt
246 }
247
248 pub fn dead_letter(&self, receipt: Receipt) {
255 let mut state = self.lock();
256 let Some(delivery) = state.lapse(receipt) else {
257 panic!("dead_letter: {receipt} is neither queued nor held");
258 };
259 state.dead_lettered.push(delivery.unit);
260 state.wake();
261 }
262
263 pub fn refuse_next_publish(&self, kind: FeedErrorKind) {
266 let mut state = self.lock();
267 state.publish_outcomes.push_back(kind);
268 state.wake();
269 }
270
271 pub fn refuse_next_receive(&self, kind: FeedErrorKind) {
284 self.refuse_next(Call::Receive, kind);
285 }
286
287 pub fn refuse_next_renew(&self, kind: FeedErrorKind) {
302 self.refuse_next(Call::Renew, kind);
303 }
304
305 pub fn refuse_next_acknowledge(&self, kind: FeedErrorKind) {
341 self.refuse_next(Call::Acknowledge, kind);
342 }
343
344 pub fn refuse_next_fail(&self, kind: FeedErrorKind) {
360 self.refuse_next(Call::Fail, kind);
361 }
362
363 #[must_use]
366 pub fn refusals_left(&self) -> usize {
367 let state = self.lock();
368 state.publish_outcomes.len() + state.answers.iter().map(VecDeque::len).sum::<usize>()
369 }
370
371 fn refuse_next(&self, call: Call, kind: FeedErrorKind) {
372 let why = match call {
373 Call::Receive => "Gone has no meaning for receive",
374 _ => {
375 "the feed answers Gone itself for a receipt it does not hold; \
376 lapse one with redeliver or dead_letter"
377 }
378 };
379 assert!(
380 kind != FeedErrorKind::Gone,
381 "refuse_next_{}: {why}",
382 call.name()
383 );
384 let mut state = self.lock();
385 state.answers[call as usize].push_back(kind);
386 state.wake();
387 }
388
389 pub fn hold_publishes(&self) {
392 let mut state = self.lock();
393 state.hold_publishes = true;
394 state.wake();
395 }
396
397 pub fn confirm_held_publishes(&self) {
400 let mut state = self.lock();
401 state.hold_publishes = false;
402 for (unit, confirmer) in std::mem::take(&mut state.held_publishes) {
403 confirmer.confirm();
404 state.queue(unit, 1);
405 }
406 state.wake();
407 }
408
409 pub fn answer_depth(&self, of: DepthOf, answer: Result<Depth, FeedError>) {
448 let mut state = self.lock();
449 match of {
450 DepthOf::DeadLetters => state.dead_letter_depths.push_back(answer),
451 _ => state.feed_depths.push_back(answer),
452 }
453 state.wake();
454 }
455
456 pub fn hand_back_on_stop(&self) {
482 let mut state = self.lock();
483 state.hands_back = true;
484 state.wake();
485 }
486
487 #[must_use]
491 pub fn stopped_receiving(&self) -> usize {
492 self.lock().stopped_receiving
493 }
494
495 #[must_use]
498 pub fn handed_back(&self) -> Vec<Receipt> {
499 self.lock().handed_back.clone()
500 }
501
502 #[must_use]
506 pub fn closes(&self) -> Vec<Duration> {
507 self.lock().closes.clone()
508 }
509
510 #[must_use]
512 pub fn depth_reads(&self, of: DepthOf) -> usize {
513 let state = self.lock();
514 match of {
515 DepthOf::DeadLetters => state.dead_letter_depth_reads,
516 _ => state.feed_depth_reads,
517 }
518 }
519
520 #[must_use]
522 pub fn delivered(&self) -> Vec<Delivery> {
523 self.lock().delivered.clone()
524 }
525
526 #[must_use]
529 pub fn held(&self) -> Vec<Receipt> {
530 self.lock().held.keys().copied().collect()
531 }
532
533 #[must_use]
535 pub fn acknowledged(&self) -> Vec<Receipt> {
536 self.lock().acknowledged.clone()
537 }
538
539 #[must_use]
541 pub fn failed(&self) -> Vec<(Receipt, String)> {
542 self.lock().failed.clone()
543 }
544
545 #[must_use]
547 pub fn renewed(&self) -> Vec<Receipt> {
548 self.lock().renewed.clone()
549 }
550
551 #[must_use]
554 pub fn gone(&self) -> Vec<Receipt> {
555 self.lock().gone.clone()
556 }
557
558 #[must_use]
560 pub fn published(&self) -> Vec<Unit> {
561 self.lock().published.clone()
562 }
563
564 #[must_use]
567 pub fn dead_lettered(&self) -> Vec<Unit> {
568 self.lock().dead_lettered.clone()
569 }
570
571 fn lock(&self) -> MutexGuard<'_, State> {
572 self.state.lock().expect("feed script poisoned")
573 }
574}
575
576impl ScriptedFeed {
577 fn lock(&self) -> MutexGuard<'_, State> {
578 self.state.lock().expect("feed script poisoned")
579 }
580}
581
582impl Feed for ScriptedFeed {
583 fn backend(&self) -> &str {
584 "scripted"
585 }
586
587 fn set_waker(&self, waker: FeedWaker) {
588 let mut state = self.lock();
589 if !state.queued.is_empty() {
590 waker.wake();
591 }
592 state.waker = Some(waker);
593 }
594
595 fn receive(&self, max: usize) -> Result<Vec<Delivery>, FeedError> {
596 let mut state = self.lock();
597 state.answer(Call::Receive)?;
598 let take = max.min(state.queued.len());
599 let out: Vec<Delivery> = state.queued.drain(..take).collect();
600 for delivery in &out {
601 state.held.insert(delivery.receipt, delivery.clone());
602 state.delivered.push(delivery.clone());
603 }
604 if take > 0 && !state.queued.is_empty() {
607 state.wake();
608 }
609 Ok(out)
610 }
611
612 fn renew(&self, receipt: Receipt) -> Result<(), FeedError> {
613 let mut state = self.lock();
614 state.answer(Call::Renew)?;
615 state.on_held(receipt, |state| {
616 state.renewed.push(receipt);
617 Ok(())
618 })
619 }
620
621 fn acknowledge(&self, receipt: Receipt) -> Result<(), FeedError> {
622 let mut state = self.lock();
623 state.answer(Call::Acknowledge)?;
624 state.on_held(receipt, |state| {
625 state.held.remove(&receipt);
626 state.acknowledged.push(receipt);
627 Ok(())
628 })
629 }
630
631 fn fail(&self, receipt: Receipt, reason: &str) -> Result<(), FeedError> {
632 let mut state = self.lock();
633 state.answer(Call::Fail)?;
634 state.on_held(receipt, |state| {
635 state.held.remove(&receipt);
636 state.failed.push((receipt, reason.to_owned()));
637 Ok(())
638 })
639 }
640
641 fn publish(&self, unit: Unit) -> Confirmation {
642 let mut state = self.lock();
643 state.published.push(unit.clone());
644 let (confirmer, confirmation) = confirmation();
645 if let Some(kind) = state.publish_outcomes.pop_front() {
646 confirmer.reject(FeedError::new(kind, "refused by the feed script"));
647 } else if state.hold_publishes {
648 state.held_publishes.push((unit, confirmer));
649 } else {
650 confirmer.confirm();
651 state.queue(unit, 1);
652 state.wake();
653 }
654 confirmation
655 }
656
657 fn read_depth(&self, of: DepthOf) -> Option<DepthReading> {
658 let mut state = self.lock();
659 let answer = match of {
660 DepthOf::DeadLetters => {
661 state.dead_letter_depth_reads += 1;
662 state.dead_letter_depths.pop_front().unwrap_or_else(|| {
663 let mut depth = Depth::new("the scripted dead-letter destination", false);
664 depth.visible = state.dead_lettered.len() as u64;
665 Ok(depth)
666 })
667 }
668 _ => {
669 state.feed_depth_reads += 1;
670 state.feed_depths.pop_front().unwrap_or_else(|| {
671 let mut depth = Depth::new("the scripted feed", false);
672 depth.visible = state.queued.len() as u64;
673 depth.in_flight = state.held.len() as u64;
674 Ok(depth)
675 })
676 }
677 };
678 let (reporter, reading) = depth_reading();
679 reporter.report(answer);
680 Some(reading)
681 }
682
683 fn hands_back(&self) -> bool {
684 self.lock().hands_back
685 }
686
687 fn stop_receiving(&self) {
688 self.lock().stopped_receiving += 1;
689 }
690
691 fn hand_back(&self, receipt: Receipt) -> Result<(), FeedError> {
692 self.lock().on_held(receipt, |state| {
693 state.held.remove(&receipt);
694 state.handed_back.push(receipt);
695 Ok(())
696 })
697 }
698
699 fn close(&self, within: Duration) -> Option<Confirmation> {
700 self.lock().closes.push(within);
701 let (confirmer, confirmation) = confirmation();
702 confirmer.confirm();
703 Some(confirmation)
704 }
705}
706
707#[cfg(test)]
708mod tests {
709 use super::*;
710 use spate_core::feed::wake_channel;
711 use std::time::Duration;
712
713 fn unit(id: &str) -> Unit {
714 Unit::new(id, id.as_bytes().to_vec())
715 }
716
717 fn kind(result: Result<(), FeedError>) -> FeedErrorKind {
718 result.unwrap_err().kind
719 }
720
721 #[test]
725 fn a_scripted_feed_reports_depth_from_its_own_state() {
726 let (feed, script) = scripted_feed();
727 let read = |of| {
728 feed.read_depth(of)
729 .expect("the scripted feed reports depth")
730 .try_outcome()
731 .expect("settled at once")
732 .expect("read")
733 };
734 assert!(read(DepthOf::Feed).is_empty());
735 let held = script.deliver(unit("held"));
736 let dead: Vec<Receipt> = ["dead-1", "dead-2", "dead-3"]
737 .into_iter()
738 .map(|id| script.deliver(unit(id)))
739 .collect();
740 script.deliver(unit("queued-1"));
741 script.deliver(unit("queued-2"));
742 let got = feed.receive(1).unwrap();
743 assert_eq!(got[0].receipt, held);
744 for receipt in dead {
745 script.dead_letter(receipt);
746 }
747 let depth = read(DepthOf::Feed);
748 assert_eq!(
749 (depth.visible, depth.in_flight, depth.delayed, depth.unsent),
750 (2, 1, 0, 0)
751 );
752 assert!(!depth.approximate);
753 let dead = read(DepthOf::DeadLetters);
754 assert_eq!((dead.visible, dead.in_flight), (3, 0));
755 assert_eq!(script.depth_reads(DepthOf::Feed), 2);
756 assert_eq!(script.depth_reads(DepthOf::DeadLetters), 1);
757 }
758
759 #[test]
762 fn a_scripted_depth_answer_sequence_is_served_in_order() {
763 let (feed, script) = scripted_feed();
764 let (waker, park) = wake_channel();
765 feed.set_waker(waker);
766 let mut first = Depth::new("q", true);
767 first.delayed = 3;
768 script.answer_depth(DepthOf::Feed, Ok(first.clone()));
769 assert!(
770 park.park(Duration::ZERO),
771 "scripting did not wake the reader"
772 );
773 script.answer_depth(
774 DepthOf::Feed,
775 Err(FeedError::new(FeedErrorKind::Fatal, "gone")),
776 );
777 let mut dead = Depth::new("dlq", true);
778 dead.visible = 2;
779 script.answer_depth(DepthOf::DeadLetters, Ok(dead.clone()));
780
781 let read = |of| feed.read_depth(of).unwrap().try_outcome().unwrap();
782 assert_eq!(read(DepthOf::DeadLetters).unwrap(), dead);
783 assert_eq!(read(DepthOf::Feed).unwrap(), first);
784 assert_eq!(read(DepthOf::Feed).unwrap_err().kind, FeedErrorKind::Fatal);
785 assert!(read(DepthOf::Feed).unwrap().is_empty());
786 assert!(read(DepthOf::DeadLetters).unwrap().is_empty());
787 }
788
789 #[test]
792 fn a_redelivery_lapses_the_old_receipt() {
793 let (feed, script) = scripted_feed();
794 let first = script.deliver(unit("a"));
795 assert_eq!(feed.receive(8).unwrap()[0].receipt, first);
796 assert_eq!(script.held(), vec![first]);
797
798 let second = script.redeliver(first);
799 assert!(script.held().is_empty(), "the lapsed receipt is still held");
800 let again = feed.receive(8).unwrap();
801 assert_eq!(again.len(), 1);
802 assert_eq!((again[0].receipt, again[0].deliveries), (second, 2));
803
804 assert_eq!(kind(feed.renew(first)), FeedErrorKind::Gone);
805 assert_eq!(kind(feed.acknowledge(first)), FeedErrorKind::Gone);
806 assert_eq!(kind(feed.fail(first, "late")), FeedErrorKind::Gone);
807 assert_eq!(script.gone(), vec![first, first, first]);
808 feed.renew(second).unwrap();
809 feed.acknowledge(second).unwrap();
810 assert_eq!(script.renewed(), vec![second]);
811 assert_eq!(script.acknowledged(), vec![second]);
812 assert!(script.failed().is_empty());
813 assert_eq!(script.delivered().len(), 2);
814 }
815
816 #[test]
819 fn a_duplicate_is_held_beside_the_first_delivery() {
820 let (feed, script) = scripted_feed();
821 let first = script.deliver(unit("a"));
822 let _ = feed.receive(8).unwrap();
823 let second = script.deliver(unit("a"));
824 let dup = feed.receive(8).unwrap();
825 assert_eq!((dup[0].receipt, dup[0].deliveries), (second, 2));
826 assert_eq!(script.held(), vec![first, second]);
827 feed.acknowledge(first).unwrap();
828 feed.fail(second, "poison").unwrap();
829 assert_eq!(script.acknowledged(), vec![first]);
830 assert_eq!(script.failed(), vec![(second, "poison".to_owned())]);
831 assert!(script.held().is_empty());
832 assert!(feed.receive(8).unwrap().is_empty(), "fail redelivered");
833 }
834
835 #[test]
838 fn a_dead_lettered_unit_lapses_its_receipt() {
839 let (feed, script) = scripted_feed();
840 let queued = script.deliver(unit("q"));
841 script.dead_letter(queued);
842 assert!(feed.receive(8).unwrap().is_empty());
843
844 let held = script.deliver(unit("h"));
845 let _ = feed.receive(8).unwrap();
846 script.dead_letter(held);
847 assert_eq!(kind(feed.acknowledge(held)), FeedErrorKind::Gone);
848 assert_eq!(script.dead_lettered(), vec![unit("q"), unit("h")]);
849 }
850
851 #[test]
855 fn publishes_are_confirmed_refused_or_held_as_scripted() {
856 let (feed, script) = scripted_feed();
857 let mut plain = feed.publish(unit("plain"));
858 assert!(matches!(plain.try_outcome(), Some(Ok(()))));
859
860 script.refuse_next_publish(FeedErrorKind::Refused);
861 let mut refused = feed.publish(unit("refused"));
862 assert_eq!(
863 refused.try_outcome().unwrap().unwrap_err().kind,
864 FeedErrorKind::Refused
865 );
866
867 script.hold_publishes();
868 let mut held = feed.publish(unit("held"));
869 assert!(held.try_outcome().is_none());
870 let ids = |d: Vec<Delivery>| d.into_iter().map(|d| d.unit.id).collect::<Vec<_>>();
871 assert_eq!(ids(feed.receive(8).unwrap()), vec!["plain"]);
872
873 script.confirm_held_publishes();
874 assert!(matches!(held.try_outcome(), Some(Ok(()))));
875 assert_eq!(ids(feed.receive(8).unwrap()), vec!["held"]);
876 assert_eq!(
877 script.published(),
878 vec![unit("plain"), unit("refused"), unit("held")]
879 );
880 }
881
882 #[test]
885 fn scripting_wakes_the_reader() {
886 let (feed, script) = scripted_feed();
887 let early = script.deliver(unit("early"));
888 let (waker, park) = wake_channel();
889 feed.set_waker(waker);
890 assert!(
891 park.park(Duration::ZERO),
892 "set_waker missed a queued delivery"
893 );
894
895 let _ = feed.receive(8).unwrap();
896 assert!(!park.park(Duration::ZERO));
897 let again = script.redeliver(early);
898 assert!(park.park(Duration::ZERO), "redeliver did not wake");
899 script.dead_letter(again);
900 assert!(park.park(Duration::ZERO), "dead_letter did not wake");
901 script.hold_publishes();
902 assert!(park.park(Duration::ZERO), "hold_publishes did not wake");
903 let _held = feed.publish(unit("p"));
904 assert!(!park.park(Duration::ZERO), "a held publish woke the reader");
905 script.confirm_held_publishes();
906 assert!(
907 park.park(Duration::ZERO),
908 "confirm_held_publishes did not wake"
909 );
910 }
911
912 #[test]
915 fn a_partial_receive_leaves_a_wake_pending() {
916 let (feed, script) = scripted_feed();
917 let (waker, park) = wake_channel();
918 feed.set_waker(waker);
919 script.deliver(unit("a"));
920 script.deliver(unit("b"));
921 assert!(park.park(Duration::ZERO));
922 assert_eq!(feed.receive(1).unwrap().len(), 1);
923 assert!(
924 park.park(Duration::ZERO),
925 "a delivery is queued but the reader's park was not signalled"
926 );
927 assert!(feed.receive(0).unwrap().is_empty());
928 assert!(
929 !park.park(Duration::ZERO),
930 "receive(0) at capacity re-signalled"
931 );
932 }
933
934 #[test]
936 fn a_confirmed_publish_wakes_the_reader() {
937 let (feed, _script) = scripted_feed();
938 let (waker, park) = wake_channel();
939 feed.set_waker(waker);
940 assert!(!park.park(Duration::ZERO));
941 drop(feed.publish(unit("p")));
942 assert!(park.park(Duration::ZERO), "publish did not wake the reader");
943 }
944
945 #[test]
948 fn refusing_the_next_publish_wakes_the_reader() {
949 let (feed, script) = scripted_feed();
950 let (waker, park) = wake_channel();
951 feed.set_waker(waker);
952 assert!(!park.park(Duration::ZERO));
953 script.refuse_next_publish(FeedErrorKind::Refused);
954 assert!(
955 park.park(Duration::ZERO),
956 "refuse_next_publish did not wake the reader"
957 );
958 }
959
960 fn call(feed: &ScriptedFeed, call: Call, receipt: Receipt) -> Result<(), FeedError> {
962 match call {
963 Call::Receive => feed.receive(0).map(drop),
964 Call::Renew => feed.renew(receipt),
965 Call::Acknowledge => feed.acknowledge(receipt),
966 Call::Fail => feed.fail(receipt, "poison"),
967 }
968 }
969
970 fn refuse(script: &FeedScript, call: Call, kind: FeedErrorKind) {
971 match call {
972 Call::Receive => script.refuse_next_receive(kind),
973 Call::Renew => script.refuse_next_renew(kind),
974 Call::Acknowledge => script.refuse_next_acknowledge(kind),
975 Call::Fail => script.refuse_next_fail(kind),
976 }
977 }
978
979 const CALLS: [Call; 4] = [Call::Receive, Call::Renew, Call::Acknowledge, Call::Fail];
980
981 #[test]
984 fn scripted_answers_are_served_in_order_then_spent() {
985 for c in CALLS {
986 let (feed, script) = scripted_feed();
987 let receipt = script.deliver(unit("a"));
988 let _ = feed.receive(8).unwrap();
989 refuse(&script, c, FeedErrorKind::Retryable);
990 refuse(&script, c, FeedErrorKind::Fatal);
991 assert_eq!(script.refusals_left(), 2);
992 assert_eq!(
993 kind(call(&feed, c, receipt)),
994 FeedErrorKind::Retryable,
995 "{c:?}"
996 );
997 assert_eq!(script.refusals_left(), 1);
998 assert_eq!(kind(call(&feed, c, receipt)), FeedErrorKind::Fatal, "{c:?}");
999 assert_eq!(script.refusals_left(), 0);
1000 call(&feed, c, receipt).unwrap_or_else(|e| panic!("{c:?} after the script: {e}"));
1001 }
1002 }
1003
1004 #[test]
1008 fn a_scripted_error_changes_nothing() {
1009 let (feed, script) = scripted_feed();
1010 let receipt = script.deliver(unit("a"));
1011 script.deliver(unit("b"));
1012 let _ = feed.receive(1).unwrap();
1013 for c in [Call::Renew, Call::Acknowledge, Call::Fail] {
1014 refuse(&script, c, FeedErrorKind::Retryable);
1015 assert_eq!(kind(call(&feed, c, receipt)), FeedErrorKind::Retryable);
1016 assert_eq!(script.held(), vec![receipt], "{c:?} changed the held set");
1017 assert!(script.renewed().is_empty(), "{c:?} recorded a renewal");
1018 assert!(script.acknowledged().is_empty(), "{c:?} recorded an ack");
1019 assert!(script.failed().is_empty(), "{c:?} recorded a fail");
1020 assert!(script.gone().is_empty(), "{c:?} recorded Gone");
1021 }
1022 feed.renew(receipt).unwrap();
1023 feed.acknowledge(receipt).unwrap();
1024 assert_eq!(script.renewed(), vec![receipt]);
1025 assert_eq!(script.acknowledged(), vec![receipt]);
1026 }
1027
1028 #[test]
1031 fn a_scripted_receive_error_takes_nothing() {
1032 let (feed, script) = scripted_feed();
1033 let queued = script.deliver(unit("a"));
1034 script.refuse_next_receive(FeedErrorKind::Retryable);
1035 assert_eq!(feed.receive(8).unwrap_err().kind, FeedErrorKind::Retryable);
1036 assert!(script.held().is_empty());
1037 assert!(script.delivered().is_empty());
1038 let got = feed.receive(8).unwrap();
1039 assert_eq!(got.len(), 1);
1040 assert_eq!(got[0].receipt, queued);
1041 }
1042
1043 #[test]
1046 fn a_scripted_answer_waits_for_its_own_call() {
1047 for scripted in CALLS {
1048 let (feed, script) = scripted_feed();
1049 for id in ["a", "b", "c", "d"] {
1050 script.deliver(unit(id));
1051 }
1052 let receipts: Vec<Receipt> =
1053 feed.receive(4).unwrap().iter().map(|d| d.receipt).collect();
1054 refuse(&script, scripted, FeedErrorKind::Fatal);
1055 for (i, c) in CALLS.into_iter().enumerate() {
1058 if c as usize != scripted as usize {
1059 call(&feed, c, receipts[i])
1060 .unwrap_or_else(|e| panic!("{c:?} took {scripted:?}'s answer: {e}"));
1061 }
1062 }
1063 assert_eq!(script.refusals_left(), 1);
1064 let own = receipts[scripted as usize];
1065 assert_eq!(kind(call(&feed, scripted, own)), FeedErrorKind::Fatal);
1066 }
1067 }
1068
1069 #[test]
1073 fn a_scripted_answer_goes_to_a_lapsed_receipt_first() {
1074 for c in [Call::Renew, Call::Acknowledge, Call::Fail] {
1075 let (feed, script) = scripted_feed();
1076 let old = script.deliver(unit("a"));
1077 let _ = feed.receive(8).unwrap();
1078 script.redeliver(old);
1079 refuse(&script, c, FeedErrorKind::Retryable);
1080 assert_eq!(kind(call(&feed, c, old)), FeedErrorKind::Retryable, "{c:?}");
1081 assert!(script.gone().is_empty(), "{c:?} recorded Gone");
1082 assert_eq!(script.refusals_left(), 0, "{c:?}");
1083 assert_eq!(kind(call(&feed, c, old)), FeedErrorKind::Gone, "{c:?}");
1084 assert_eq!(script.gone(), vec![old], "{c:?}");
1085 }
1086 }
1087
1088 #[test]
1090 fn a_refused_receive_sends_no_signal() {
1091 let (feed, script) = scripted_feed();
1092 let (waker, park) = wake_channel();
1093 feed.set_waker(waker);
1094 script.deliver(unit("a"));
1095 script.refuse_next_receive(FeedErrorKind::Retryable);
1096 assert!(park.park(Duration::ZERO));
1097 assert_eq!(feed.receive(8).unwrap_err().kind, FeedErrorKind::Retryable);
1098 assert!(
1099 !park.park(Duration::ZERO),
1100 "a refused receive signalled the reader"
1101 );
1102 }
1103
1104 #[test]
1106 fn refusals_left_counts_unserved_publish_refusals() {
1107 let (feed, script) = scripted_feed();
1108 script.refuse_next_publish(FeedErrorKind::Refused);
1109 script.refuse_next_receive(FeedErrorKind::Retryable);
1110 assert_eq!(script.refusals_left(), 2);
1111 let mut refused = feed.publish(unit("a"));
1112 assert_eq!(
1113 refused.try_outcome().unwrap().unwrap_err().kind,
1114 FeedErrorKind::Refused
1115 );
1116 assert_eq!(script.refusals_left(), 1);
1117 }
1118
1119 #[test]
1120 #[should_panic(expected = "refuse_next_receive: Gone has no meaning for receive")]
1121 fn scripting_gone_panics_for_receive() {
1122 scripted_feed().1.refuse_next_receive(FeedErrorKind::Gone);
1123 }
1124
1125 #[test]
1126 #[should_panic(expected = "refuse_next_renew: the feed answers Gone")]
1127 fn scripting_gone_panics_for_renew() {
1128 scripted_feed().1.refuse_next_renew(FeedErrorKind::Gone);
1129 }
1130
1131 #[test]
1132 #[should_panic(expected = "refuse_next_acknowledge: the feed answers Gone")]
1133 fn scripting_gone_panics_for_acknowledge() {
1134 scripted_feed()
1135 .1
1136 .refuse_next_acknowledge(FeedErrorKind::Gone);
1137 }
1138
1139 #[test]
1140 #[should_panic(expected = "refuse_next_fail: the feed answers Gone")]
1141 fn scripting_gone_panics_for_fail() {
1142 scripted_feed().1.refuse_next_fail(FeedErrorKind::Gone);
1143 }
1144
1145 #[test]
1148 fn refusing_the_next_call_wakes_the_reader() {
1149 for c in CALLS {
1150 let (feed, script) = scripted_feed();
1151 let (waker, park) = wake_channel();
1152 feed.set_waker(waker);
1153 assert!(!park.park(Duration::ZERO));
1154 refuse(&script, c, FeedErrorKind::Retryable);
1155 assert!(
1156 park.park(Duration::ZERO),
1157 "refusing the next {c:?} did not wake the reader"
1158 );
1159 }
1160 }
1161
1162 #[test]
1165 fn a_later_set_waker_replaces_the_waker() {
1166 let (feed, script) = scripted_feed();
1167 let (first, first_park) = wake_channel();
1168 feed.set_waker(first);
1169 let (second, second_park) = wake_channel();
1170 feed.set_waker(second);
1171 script.deliver(unit("a"));
1172 assert!(
1173 second_park.park(Duration::ZERO),
1174 "deliver signalled the replaced waker"
1175 );
1176 assert!(!first_park.park(Duration::ZERO));
1177 }
1178}