1use std::marker::PhantomData;
5
6use slim_auth::traits::{TokenProvider, Verifier};
7use slim_datapath::messages::Name;
8
9use crate::{
10 Direction,
11 common::SessionMessage,
12 errors::SessionError,
13 session_config::SessionConfig,
14 session_controller::SessionController,
15 session_moderator::SessionModerator,
16 session_participant::SessionParticipant,
17 session_settings::SessionSettings,
18 subscription_manager::{SubscriptionManager, SubscriptionOps},
19 traits::MessageHandler,
20 transmitter::SessionTransmitter,
21};
22
23pub struct NotReady;
25pub struct Ready;
26
27pub struct ForController;
29pub struct ForParticipant;
30pub struct ForModerator;
31
32pub struct SessionBuilder<P, V, Target, State = NotReady, M = SubscriptionManager>
114where
115 P: TokenProvider + Send + Sync + Clone + 'static,
116 V: Verifier + Send + Sync + Clone + 'static,
117 M: SubscriptionOps,
118{
119 id: Option<u32>,
120 source: Option<Name>,
121 destination: Option<Name>,
122 config: Option<SessionConfig>,
123 identity_provider: Option<P>,
124 identity_verifier: Option<V>,
125 tx: Option<SessionTransmitter>,
126 tx_to_session_layer: Option<tokio::sync::mpsc::Sender<Result<SessionMessage, SessionError>>>,
127 graceful_shutdown_timeout: Option<std::time::Duration>,
128 direction: Direction,
129 subscription_manager: Option<M>,
130 service_id: Option<String>,
131 _target: PhantomData<Target>,
132 _state: PhantomData<State>,
133}
134
135impl<P, V, Target, M> SessionBuilder<P, V, Target, NotReady, M>
137where
138 P: TokenProvider + Send + Sync + Clone + 'static,
139 V: Verifier + Send + Sync + Clone + 'static,
140 M: SubscriptionOps,
141{
142 fn new() -> Self {
143 Self {
144 id: None,
145 source: None,
146 destination: None,
147 config: None,
148 identity_provider: None,
149 identity_verifier: None,
150 tx: None,
151 tx_to_session_layer: None,
152 graceful_shutdown_timeout: None,
153 direction: Direction::Bidirectional,
154 subscription_manager: None,
155 service_id: None,
156 _target: PhantomData,
157 _state: PhantomData,
158 }
159 }
160
161 pub fn with_id(mut self, id: u32) -> Self {
162 self.id = Some(id);
163 self
164 }
165
166 pub fn with_source(mut self, source: Name) -> Self {
167 self.source = Some(source);
168 self
169 }
170
171 pub fn with_destination(mut self, destination: Name) -> Self {
172 self.destination = Some(destination);
173 self
174 }
175
176 pub fn with_config(mut self, config: SessionConfig) -> Self {
177 self.config = Some(config);
178 self
179 }
180
181 pub fn with_identity_provider(mut self, identity_provider: P) -> Self {
182 self.identity_provider = Some(identity_provider);
183 self
184 }
185
186 pub fn with_identity_verifier(mut self, identity_verifier: V) -> Self {
187 self.identity_verifier = Some(identity_verifier);
188 self
189 }
190
191 pub fn with_tx(mut self, tx: SessionTransmitter) -> Self {
192 self.tx = Some(tx);
193 self
194 }
195
196 pub fn with_tx_to_session_layer(
197 mut self,
198 tx_to_session_layer: tokio::sync::mpsc::Sender<Result<SessionMessage, SessionError>>,
199 ) -> Self {
200 self.tx_to_session_layer = Some(tx_to_session_layer);
201 self
202 }
203
204 pub fn with_graceful_shutdown_timeout(mut self, timeout: std::time::Duration) -> Self {
205 self.graceful_shutdown_timeout = Some(timeout);
206 self
207 }
208
209 pub fn with_direction(mut self, direction: Direction) -> Self {
210 self.direction = direction;
211 self
212 }
213
214 pub fn with_subscription_manager<N: SubscriptionOps>(
218 self,
219 manager: N,
220 ) -> SessionBuilder<P, V, Target, NotReady, N> {
221 SessionBuilder {
222 id: self.id,
223 source: self.source,
224 destination: self.destination,
225 config: self.config,
226 identity_provider: self.identity_provider,
227 identity_verifier: self.identity_verifier,
228 tx: self.tx,
229 tx_to_session_layer: self.tx_to_session_layer,
230 graceful_shutdown_timeout: self.graceful_shutdown_timeout,
231 direction: self.direction,
232 subscription_manager: Some(manager),
233 service_id: self.service_id,
234 _target: PhantomData,
235 _state: PhantomData,
236 }
237 }
238
239 pub fn with_service_id(mut self, service_id: String) -> Self {
240 self.service_id = Some(service_id);
241 self
242 }
243
244 pub fn ready(self) -> Result<SessionBuilder<P, V, Target, Ready, M>, SessionError> {
245 if self.id.is_none()
247 || self.source.is_none()
248 || self.destination.is_none()
249 || self.config.is_none()
250 || self.identity_provider.is_none()
251 || self.identity_verifier.is_none()
252 || self.tx.is_none()
253 || self.tx_to_session_layer.is_none()
254 {
255 return Err(SessionError::SessionBuilderIncomplete);
256 }
257
258 Ok(SessionBuilder {
259 id: self.id,
260 source: self.source,
261 destination: self.destination,
262 config: self.config,
263 identity_provider: self.identity_provider,
264 identity_verifier: self.identity_verifier,
265 tx: self.tx,
266 tx_to_session_layer: self.tx_to_session_layer,
267 graceful_shutdown_timeout: self.graceful_shutdown_timeout,
268 direction: self.direction,
269 subscription_manager: self.subscription_manager,
270 service_id: self.service_id,
271 _target: PhantomData,
272 _state: PhantomData,
273 })
274 }
275}
276
277impl<P, V, M> SessionBuilder<P, V, ForController, NotReady, M>
279where
280 P: TokenProvider + Send + Sync + Clone + 'static,
281 V: Verifier + Send + Sync + Clone + 'static,
282 M: SubscriptionOps,
283{
284 pub fn for_controller() -> Self {
286 Self::new()
287 }
288}
289
290impl<P, V, M> SessionBuilder<P, V, ForParticipant, NotReady, M>
291where
292 P: TokenProvider + Send + Sync + Clone + 'static,
293 V: Verifier + Send + Sync + Clone + 'static,
294 M: SubscriptionOps,
295{
296 pub fn for_participant() -> Self {
298 Self::new()
299 }
300}
301
302impl<P, V, M> SessionBuilder<P, V, ForModerator, NotReady, M>
303where
304 P: TokenProvider + Send + Sync + Clone + 'static,
305 V: Verifier + Send + Sync + Clone + 'static,
306 M: SubscriptionOps,
307{
308 pub fn for_moderator() -> Self {
310 Self::new()
311 }
312}
313
314impl<P, V, M> SessionBuilder<P, V, ForController, Ready, M>
316where
317 P: TokenProvider + Send + Sync + Clone + 'static,
318 V: Verifier + Send + Sync + Clone + 'static,
319 M: SubscriptionOps,
320{
321 pub fn build(self) -> Result<SessionController, SessionError> {
326 let id = self.id.unwrap();
327 let source = self.source.clone().unwrap();
328 let destination = self.destination.clone().unwrap();
329 let config = self.config.clone().unwrap();
330
331 let role = if config.initiator {
332 "Moderator"
333 } else {
334 "Participant"
335 };
336 tracing::debug!(%role, "Building SessionController");
337
338 let session_controller = if config.initiator {
339 let (inner, tx, rx, settings) = self.build_session_stack(SessionModerator::new)?;
340 SessionController::from_parts(
341 id,
342 source,
343 destination,
344 config.clone(),
345 settings,
346 tx,
347 rx,
348 inner,
349 )
350 } else {
351 let (inner, tx, rx, settings) = self.build_session_stack(SessionParticipant::new)?;
352 SessionController::from_parts(id, source, destination, config, settings, tx, rx, inner)
353 };
354
355 Ok(session_controller)
356 }
357
358 fn build_session_stack<W>(
361 self,
362 wrapper_constructor: impl FnOnce(crate::session::Session, SessionSettings<P, V, M>) -> W,
363 ) -> Result<
364 (
365 W,
366 tokio::sync::mpsc::Sender<SessionMessage>,
367 tokio::sync::mpsc::Receiver<SessionMessage>,
368 SessionSettings<P, V, M>,
369 ),
370 SessionError,
371 >
372 where
373 W: MessageHandler,
374 {
375 let (tx_session, rx_session) = tokio::sync::mpsc::channel(256);
376
377 let inner = crate::session::Session::new(
379 self.id.unwrap(),
380 self.config.clone().unwrap(),
381 &self.source.clone().unwrap(),
382 self.tx.clone().unwrap(),
383 tx_session.clone(),
384 self.direction,
385 );
386
387 let tx = self.tx.unwrap();
388 let subscription_manager = self
389 .subscription_manager
390 .or_else(|| M::from_slim_tx(&tx.slim_tx))
391 .expect("subscription_manager must be provided or M must implement from_slim_tx");
392 let settings = SessionSettings {
393 id: self.id.unwrap(),
394 source: self.source.unwrap(),
395 destination: self.destination.unwrap(),
396 config: self.config.unwrap(),
397 tx,
398 tx_session: tx_session.clone(),
399 tx_to_session_layer: self.tx_to_session_layer.unwrap(),
400 identity_provider: self.identity_provider.unwrap(),
401 identity_verifier: self.identity_verifier.unwrap(),
402 graceful_shutdown_timeout: self.graceful_shutdown_timeout,
403 subscription_manager,
404 service_id: self.service_id.unwrap_or_default(),
405 };
406
407 let wrapper = wrapper_constructor(inner, settings.clone());
408
409 Ok((wrapper, tx_session, rx_session, settings))
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416 use crate::{
417 SessionError,
418 test_utils::{MockTokenProvider, MockVerifier},
419 transmitter::SessionTransmitter,
420 };
421 use slim_datapath::{api::ProtoSessionType, messages::Name};
422 use std::collections::HashMap;
423 use tokio::sync::mpsc;
424
425 fn create_test_config(initiator: bool) -> SessionConfig {
426 SessionConfig {
427 session_type: ProtoSessionType::PointToPoint,
428 max_retries: Some(3),
429 interval: Some(std::time::Duration::from_secs(1)),
430 mls_enabled: false,
431 initiator,
432 metadata: HashMap::new(),
433 }
434 }
435
436 fn create_test_name(prefix: &str) -> Name {
437 Name::from_strings([prefix, "test", "name"]).with_id(1)
438 }
439
440 fn create_test_transmitter() -> SessionTransmitter {
441 let (slim_tx, _) = mpsc::channel(10);
442 let (app_tx, _) = mpsc::unbounded_channel();
443 SessionTransmitter::new(slim_tx, app_tx)
444 }
445
446 #[test]
447 fn test_builder_for_controller_creation() {
448 let builder =
449 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller();
450 assert!(builder.id.is_none());
451 assert!(builder.source.is_none());
452 assert!(builder.destination.is_none());
453 }
454
455 #[test]
456 fn test_builder_for_participant_creation() {
457 let builder =
458 SessionBuilder::<MockTokenProvider, MockVerifier, ForParticipant, NotReady>::for_participant();
459 assert!(builder.id.is_none());
460 assert!(builder.source.is_none());
461 assert!(builder.destination.is_none());
462 }
463
464 #[test]
465 fn test_builder_for_moderator_creation() {
466 let builder =
467 SessionBuilder::<MockTokenProvider, MockVerifier, ForModerator, NotReady>::for_moderator();
468 assert!(builder.id.is_none());
469 assert!(builder.source.is_none());
470 assert!(builder.destination.is_none());
471 }
472
473 #[test]
474 fn test_builder_with_id() {
475 let builder =
476 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
477 .with_id(42);
478 assert_eq!(builder.id, Some(42));
479 }
480
481 #[test]
482 fn test_builder_with_source() {
483 let source = create_test_name("source");
484 let builder =
485 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
486 .with_source(source.clone());
487 assert_eq!(builder.source, Some(source));
488 }
489
490 #[test]
491 fn test_builder_with_destination() {
492 let destination = create_test_name("dest");
493 let builder =
494 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
495 .with_destination(destination.clone());
496 assert_eq!(builder.destination, Some(destination));
497 }
498
499 #[test]
500 fn test_builder_with_config() {
501 let config = create_test_config(true);
502 let builder =
503 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
504 .with_config(config.clone());
505 assert!(builder.config.is_some());
506 assert!(builder.config.unwrap().initiator);
507 }
508
509 #[test]
510 fn test_builder_with_identity_provider() {
511 let provider = MockTokenProvider;
512 let builder =
513 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
514 .with_identity_provider(provider);
515 assert!(builder.identity_provider.is_some());
516 }
517
518 #[test]
519 fn test_builder_with_identity_verifier() {
520 let verifier = MockVerifier;
521 let builder =
522 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
523 .with_identity_verifier(verifier);
524 assert!(builder.identity_verifier.is_some());
525 }
526
527 #[test]
528 fn test_builder_with_tx() {
529 let tx = create_test_transmitter();
530 let builder =
531 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
532 .with_tx(tx);
533 assert!(builder.tx.is_some());
534 }
535
536 #[test]
537 fn test_builder_with_tx_to_session_layer() {
538 let (tx, _) = mpsc::channel(10);
539 let builder =
540 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
541 .with_tx_to_session_layer(tx);
542 assert!(builder.tx_to_session_layer.is_some());
543 }
544
545 #[test]
546 fn test_builder_ready_with_all_fields() {
547 let (tx_to_session, _) = mpsc::channel(10);
548 let builder =
549 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
550 .with_id(1)
551 .with_source(create_test_name("source"))
552 .with_destination(create_test_name("dest"))
553 .with_config(create_test_config(true))
554 .with_identity_provider(MockTokenProvider)
555 .with_identity_verifier(MockVerifier)
556 .with_tx(create_test_transmitter())
557 .with_tx_to_session_layer(tx_to_session);
558
559 let ready_result = builder.ready();
560 assert!(ready_result.is_ok());
561 }
562
563 #[test]
564 fn test_builder_ready_missing_id() {
565 let (tx_to_session, _) = mpsc::channel(10);
566 let builder =
567 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
568 .with_source(create_test_name("source"))
569 .with_destination(create_test_name("dest"))
570 .with_config(create_test_config(true))
571 .with_identity_provider(MockTokenProvider)
572 .with_identity_verifier(MockVerifier)
573 .with_tx(create_test_transmitter())
574 .with_tx_to_session_layer(tx_to_session);
575
576 let ready_result = builder.ready();
577 assert!(ready_result.is_err_and(|e| matches!(e, SessionError::SessionBuilderIncomplete)));
578 }
579
580 #[test]
581 fn test_builder_ready_missing_source() {
582 let (tx_to_session, _) = mpsc::channel(10);
583 let builder =
584 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
585 .with_id(1)
586 .with_destination(create_test_name("dest"))
587 .with_config(create_test_config(true))
588 .with_identity_provider(MockTokenProvider)
589 .with_identity_verifier(MockVerifier)
590 .with_tx(create_test_transmitter())
591 .with_tx_to_session_layer(tx_to_session);
592 let ready_result = builder.ready();
593 assert!(ready_result.is_err());
594 }
595
596 #[test]
597 fn test_builder_ready_missing_destination() {
598 let (tx_to_session, _) = mpsc::channel(10);
599 let builder =
600 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
601 .with_id(1)
602 .with_source(create_test_name("source"))
603 .with_config(create_test_config(true))
604 .with_identity_provider(MockTokenProvider)
605 .with_identity_verifier(MockVerifier)
606 .with_tx(create_test_transmitter())
607 .with_tx_to_session_layer(tx_to_session);
608
609 let ready_result = builder.ready();
610 assert!(ready_result.is_err());
611 }
612
613 #[test]
614 fn test_builder_ready_missing_config() {
615 let (tx_to_session, _) = mpsc::channel(10);
616 let builder =
617 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
618 .with_id(1)
619 .with_source(create_test_name("source"))
620 .with_destination(create_test_name("dest"))
621 .with_identity_provider(MockTokenProvider)
622 .with_identity_verifier(MockVerifier)
623 .with_tx(create_test_transmitter())
624 .with_tx_to_session_layer(tx_to_session);
625
626 let ready_result = builder.ready();
627 assert!(ready_result.is_err());
628 }
629
630 #[test]
631 fn test_builder_ready_missing_identity_provider() {
632 let (tx_to_session, _) = mpsc::channel(10);
633 let builder =
634 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
635 .with_id(1)
636 .with_source(create_test_name("source"))
637 .with_destination(create_test_name("dest"))
638 .with_config(create_test_config(true))
639 .with_identity_verifier(MockVerifier)
640 .with_tx(create_test_transmitter())
641 .with_tx_to_session_layer(tx_to_session);
642
643 let ready_result = builder.ready();
644 assert!(ready_result.is_err());
645 }
646
647 #[test]
648 fn test_builder_ready_missing_identity_verifier() {
649 let (tx_to_session, _) = mpsc::channel(10);
650 let builder =
651 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
652 .with_id(1)
653 .with_source(create_test_name("source"))
654 .with_destination(create_test_name("dest"))
655 .with_config(create_test_config(true))
656 .with_identity_provider(MockTokenProvider)
657 .with_tx(create_test_transmitter())
658 .with_tx_to_session_layer(tx_to_session);
659
660 let ready_result = builder.ready();
661 assert!(ready_result.is_err());
662 }
663
664 #[test]
665 fn test_builder_ready_missing_tx() {
666 let (tx_to_session, _) = mpsc::channel(10);
667 let builder =
668 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
669 .with_id(1)
670 .with_source(create_test_name("source"))
671 .with_destination(create_test_name("dest"))
672 .with_config(create_test_config(true))
673 .with_identity_provider(MockTokenProvider)
674 .with_identity_verifier(MockVerifier)
675 .with_tx_to_session_layer(tx_to_session);
676
677 let ready_result = builder.ready();
678 assert!(ready_result.is_err());
679 }
680
681 #[test]
682 fn test_builder_ready_missing_tx_to_session_layer() {
683 let builder =
684 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
685 .with_id(1)
686 .with_source(create_test_name("source"))
687 .with_destination(create_test_name("dest"))
688 .with_config(create_test_config(true))
689 .with_identity_provider(MockTokenProvider)
690 .with_identity_verifier(MockVerifier)
691 .with_tx(create_test_transmitter());
692
693 let ready_result = builder.ready();
694 assert!(ready_result.is_err());
695 }
696
697 #[test]
698 fn test_builder_chaining() {
699 let (tx_to_session, _) = mpsc::channel(10);
700 let builder =
701 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
702 .with_id(123)
703 .with_source(create_test_name("src"))
704 .with_destination(create_test_name("dst"))
705 .with_config(create_test_config(false))
706 .with_identity_provider(MockTokenProvider)
707 .with_identity_verifier(MockVerifier)
708 .with_tx(create_test_transmitter())
709 .with_tx_to_session_layer(tx_to_session);
710
711 assert_eq!(builder.id, Some(123));
712 assert!(builder.source.is_some());
713 assert!(builder.destination.is_some());
714 assert!(builder.config.is_some());
715 assert!(builder.identity_provider.is_some());
716 assert!(builder.identity_verifier.is_some());
717 assert!(builder.tx.is_some());
718 assert!(builder.tx_to_session_layer.is_some());
719 }
720
721 #[test]
722 fn test_builder_ready_state_transition() {
723 let (tx_to_session, _) = mpsc::channel(10);
724 let builder =
725 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
726 .with_id(1)
727 .with_source(create_test_name("source"))
728 .with_destination(create_test_name("dest"))
729 .with_config(create_test_config(true))
730 .with_identity_provider(MockTokenProvider)
731 .with_identity_verifier(MockVerifier)
732 .with_tx(create_test_transmitter())
733 .with_tx_to_session_layer(tx_to_session);
734
735 let ready_builder = builder.ready().unwrap();
736
737 assert_eq!(ready_builder.id, Some(1));
739 assert!(ready_builder.source.is_some());
740 assert!(ready_builder.destination.is_some());
741 assert!(ready_builder.config.is_some());
742 assert!(ready_builder.identity_provider.is_some());
743 assert!(ready_builder.identity_verifier.is_some());
744 assert!(ready_builder.tx.is_some());
745 assert!(ready_builder.tx_to_session_layer.is_some());
746 }
747
748 #[test]
749 fn test_builder_different_target_types() {
750 let _controller_builder = SessionBuilder::<
752 MockTokenProvider,
753 MockVerifier,
754 ForController,
755 NotReady,
756 >::for_controller();
757 let _participant_builder = SessionBuilder::<
758 MockTokenProvider,
759 MockVerifier,
760 ForParticipant,
761 NotReady,
762 >::for_participant();
763 let _moderator_builder = SessionBuilder::<
764 MockTokenProvider,
765 MockVerifier,
766 ForModerator,
767 NotReady,
768 >::for_moderator();
769 }
770
771 #[test]
772 fn test_builder_with_different_config_types() {
773 let config_initiator = create_test_config(true);
774 let config_participant = create_test_config(false);
775
776 let builder1 =
777 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
778 .with_config(config_initiator);
779 assert!(builder1.config.unwrap().initiator);
780
781 let builder2 =
782 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
783 .with_config(config_participant);
784 assert!(!builder2.config.unwrap().initiator);
785 }
786
787 #[test]
788 fn test_builder_with_multicast_session_config() {
789 let mut config = create_test_config(true);
790 config.session_type = ProtoSessionType::Multicast;
791
792 let builder =
793 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
794 .with_config(config);
795
796 assert_eq!(
797 builder.config.unwrap().session_type,
798 ProtoSessionType::Multicast
799 );
800 }
801
802 #[test]
803 fn test_builder_with_mls_enabled() {
804 let mut config = create_test_config(true);
805 config.mls_enabled = true;
806
807 let builder =
808 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
809 .with_config(config);
810
811 assert!(builder.config.unwrap().mls_enabled);
812 }
813
814 #[test]
815 fn test_builder_with_custom_retry_settings() {
816 let mut config = create_test_config(true);
817 config.max_retries = Some(10);
818 config.interval = Some(std::time::Duration::from_secs(5));
819
820 let builder =
821 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
822 .with_config(config.clone());
823
824 let stored_config = builder.config.unwrap();
825 assert_eq!(stored_config.max_retries, Some(10));
826 assert_eq!(
827 stored_config.interval,
828 Some(std::time::Duration::from_secs(5))
829 );
830 }
831
832 #[test]
833 fn test_builder_with_metadata() {
834 let mut config = create_test_config(true);
835 let mut metadata = HashMap::new();
836 metadata.insert("key1".to_string(), "value1".to_string());
837 metadata.insert("key2".to_string(), "value2".to_string());
838 config.metadata = metadata.clone();
839
840 let builder =
841 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
842 .with_config(config);
843
844 let stored_config = builder.config.unwrap();
845 assert_eq!(
846 stored_config.metadata.get("key1"),
847 Some(&"value1".to_string())
848 );
849 assert_eq!(
850 stored_config.metadata.get("key2"),
851 Some(&"value2".to_string())
852 );
853 }
854
855 #[test]
856 fn test_builder_overwrites_previous_values() {
857 let builder =
859 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
860 .with_id(1)
861 .with_id(2)
862 .with_id(3);
863
864 assert_eq!(builder.id, Some(3));
865
866 let source1 = create_test_name("first");
867 let source2 = create_test_name("second");
868 let builder = SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
869 .with_source(source1)
870 .with_source(source2.clone());
871
872 assert_eq!(builder.source, Some(source2));
873 }
874
875 #[test]
876 fn test_builder_partial_configuration() {
877 let builder =
880 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
881 .with_id(42);
882
883 assert_eq!(builder.id, Some(42));
884 assert!(builder.source.is_none());
885
886 let (tx_to_session, _) = mpsc::channel(10);
888 let builder = builder
889 .with_source(create_test_name("source"))
890 .with_destination(create_test_name("dest"))
891 .with_config(create_test_config(true))
892 .with_identity_provider(MockTokenProvider)
893 .with_identity_verifier(MockVerifier)
894 .with_tx(create_test_transmitter())
895 .with_tx_to_session_layer(tx_to_session);
896
897 assert!(builder.ready().is_ok());
898 }
899
900 #[test]
901 fn test_builder_ready_validation_comprehensive() {
902 let (tx_to_session, _) = mpsc::channel(10);
904
905 let mut builder =
907 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller();
908
909 builder.id = Some(1);
910 builder.source = Some(create_test_name("source"));
911 builder.destination = Some(create_test_name("dest"));
912 builder.config = Some(create_test_config(true));
913 builder.identity_provider = Some(MockTokenProvider);
914 builder.identity_verifier = Some(MockVerifier);
915 builder.tx = Some(create_test_transmitter());
916 builder.tx_to_session_layer = Some(tx_to_session);
917
918 assert!(builder.ready().is_ok());
920 }
921
922 #[test]
923 fn test_builder_with_empty_metadata() {
924 let config = create_test_config(true);
925 assert!(config.metadata.is_empty());
926
927 let builder =
928 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
929 .with_config(config);
930
931 assert!(builder.config.unwrap().metadata.is_empty());
932 }
933
934 #[test]
935 fn test_builder_with_none_retries() {
936 let mut config = create_test_config(true);
937 config.max_retries = None;
938 config.interval = None;
939
940 let builder =
941 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
942 .with_config(config);
943
944 let stored = builder.config.unwrap();
945 assert_eq!(stored.max_retries, None);
946 assert_eq!(stored.interval, None);
947 }
948
949 #[test]
950 fn test_builder_with_zero_duration() {
951 let mut config = create_test_config(true);
952 config.interval = Some(std::time::Duration::from_secs(0));
953
954 let builder =
955 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
956 .with_config(config);
957
958 assert_eq!(
959 builder.config.unwrap().interval,
960 Some(std::time::Duration::from_secs(0))
961 );
962 }
963
964 #[test]
965 fn test_builder_with_large_id() {
966 let builder =
967 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
968 .with_id(u32::MAX);
969
970 assert_eq!(builder.id, Some(u32::MAX));
971 }
972
973 #[test]
974 fn test_builder_type_states() {
975 let not_ready =
977 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller();
978
979 let not_ready = not_ready.with_id(1);
981 assert_eq!(not_ready.id, Some(1));
982
983 assert_eq!(
985 std::mem::size_of::<
986 SessionBuilder<MockTokenProvider, MockVerifier, ForController, NotReady>,
987 >(),
988 std::mem::size_of::<
989 SessionBuilder<MockTokenProvider, MockVerifier, ForController, Ready>,
990 >()
991 );
992 }
993
994 #[test]
995 fn test_builder_clone_safe_types() {
996 let provider1 = MockTokenProvider;
998 let provider2 = provider1.clone();
999
1000 let builder1 =
1001 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1002 .with_identity_provider(provider1);
1003
1004 let builder2 =
1005 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1006 .with_identity_provider(provider2);
1007
1008 assert!(builder1.identity_provider.is_some());
1009 assert!(builder2.identity_provider.is_some());
1010 }
1011
1012 #[test]
1013 fn test_builder_error_message_content() {
1014 let builder =
1015 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1016 .with_id(1);
1017
1018 let res = builder.ready();
1019 assert!(res.is_err_and(|e| matches!(e, SessionError::SessionBuilderIncomplete)));
1020 }
1021
1022 #[test]
1023 fn test_builder_with_all_session_types() {
1024 let config_p2p = SessionConfig {
1026 session_type: ProtoSessionType::PointToPoint,
1027 max_retries: None,
1028 interval: None,
1029 mls_enabled: false,
1030 initiator: true,
1031 metadata: HashMap::new(),
1032 };
1033
1034 let builder_p2p =
1035 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1036 .with_config(config_p2p);
1037 assert_eq!(
1038 builder_p2p.config.unwrap().session_type,
1039 ProtoSessionType::PointToPoint
1040 );
1041
1042 let config_multicast = SessionConfig {
1044 session_type: ProtoSessionType::Multicast,
1045 max_retries: None,
1046 interval: None,
1047 mls_enabled: false,
1048 initiator: true,
1049 metadata: HashMap::new(),
1050 };
1051
1052 let builder_multicast = SessionBuilder::<
1053 MockTokenProvider,
1054 MockVerifier,
1055 ForController,
1056 NotReady,
1057 >::for_controller()
1058 .with_config(config_multicast);
1059 assert_eq!(
1060 builder_multicast.config.unwrap().session_type,
1061 ProtoSessionType::Multicast
1062 );
1063
1064 let config_unspecified = SessionConfig {
1066 session_type: ProtoSessionType::Unspecified,
1067 max_retries: None,
1068 interval: None,
1069 mls_enabled: false,
1070 initiator: false,
1071 metadata: HashMap::new(),
1072 };
1073
1074 let builder_unspecified = SessionBuilder::<
1075 MockTokenProvider,
1076 MockVerifier,
1077 ForController,
1078 NotReady,
1079 >::for_controller()
1080 .with_config(config_unspecified);
1081 assert_eq!(
1082 builder_unspecified.config.unwrap().session_type,
1083 ProtoSessionType::Unspecified
1084 );
1085 }
1086
1087 #[tokio::test]
1090 async fn test_builder_build_as_participant() {
1091 let (tx_to_session, _rx_from_session) = mpsc::channel(10);
1092 let config = create_test_config(false); let builder =
1095 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1096 .with_id(1)
1097 .with_source(create_test_name("participant"))
1098 .with_destination(create_test_name("moderator"))
1099 .with_config(config)
1100 .with_identity_provider(MockTokenProvider)
1101 .with_identity_verifier(MockVerifier)
1102 .with_tx(create_test_transmitter())
1103 .with_tx_to_session_layer(tx_to_session);
1104
1105 let controller = builder.ready().unwrap().build();
1106
1107 assert!(controller.is_ok());
1109 let controller = controller.unwrap();
1110 assert_eq!(controller.id(), 1);
1111 assert!(!controller.is_initiator());
1112 }
1113
1114 #[tokio::test]
1115 async fn test_builder_build_as_moderator_p2p() {
1116 let (tx_to_session, _rx_from_session) = mpsc::channel(10);
1117 let (slim_tx, mut slim_rx) = mpsc::channel(10);
1118 let (app_tx, _app_rx) = mpsc::unbounded_channel();
1119 let tx = SessionTransmitter::new(slim_tx, app_tx);
1120
1121 let mut config = create_test_config(true); config.session_type = ProtoSessionType::PointToPoint;
1123
1124 let builder =
1125 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1126 .with_id(2)
1127 .with_source(create_test_name("moderator"))
1128 .with_destination(create_test_name("participant"))
1129 .with_config(config)
1130 .with_identity_provider(MockTokenProvider)
1131 .with_identity_verifier(MockVerifier)
1132 .with_tx(tx)
1133 .with_tx_to_session_layer(tx_to_session);
1134
1135 let controller = builder.ready().unwrap().build();
1136
1137 assert!(controller.is_ok());
1138 let controller = controller.unwrap();
1139 assert_eq!(controller.id(), 2);
1140 assert!(controller.is_initiator());
1141 assert_eq!(controller.session_type(), ProtoSessionType::PointToPoint);
1142
1143 tokio::time::timeout(std::time::Duration::from_millis(100), slim_rx.recv())
1146 .await
1147 .ok();
1148 }
1149
1150 #[tokio::test]
1151 async fn test_builder_build_as_moderator_multicast() {
1152 let (tx_to_session, _rx_from_session) = mpsc::channel(10);
1153 let (slim_tx, mut slim_rx) = mpsc::channel(10);
1154 let (app_tx, _app_rx) = mpsc::unbounded_channel();
1155 let tx = SessionTransmitter::new(slim_tx, app_tx);
1156
1157 let mut config = create_test_config(true); config.session_type = ProtoSessionType::Multicast;
1159
1160 let builder =
1161 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1162 .with_id(3)
1163 .with_source(create_test_name("moderator"))
1164 .with_destination(create_test_name("group"))
1165 .with_config(config)
1166 .with_identity_provider(MockTokenProvider)
1167 .with_identity_verifier(MockVerifier)
1168 .with_tx(tx)
1169 .with_tx_to_session_layer(tx_to_session);
1170
1171 let controller = builder.ready().unwrap().build();
1172
1173 assert!(controller.is_ok());
1174 let controller = controller.unwrap();
1175 assert_eq!(controller.id(), 3);
1176 assert!(controller.is_initiator());
1177 assert_eq!(controller.session_type(), ProtoSessionType::Multicast);
1178
1179 let result =
1182 tokio::time::timeout(std::time::Duration::from_millis(50), slim_rx.recv()).await;
1183 assert!(result.is_err() || result.unwrap().is_none());
1185 }
1186
1187 #[tokio::test]
1188 async fn test_builder_build_with_mls_disabled() {
1189 let (tx_to_session, _) = mpsc::channel(10);
1190 let mut config = create_test_config(false);
1191 config.mls_enabled = false;
1192
1193 let builder =
1194 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1195 .with_id(4)
1196 .with_source(create_test_name("source"))
1197 .with_destination(create_test_name("dest"))
1198 .with_config(config)
1199 .with_identity_provider(MockTokenProvider)
1200 .with_identity_verifier(MockVerifier)
1201 .with_tx(create_test_transmitter())
1202 .with_tx_to_session_layer(tx_to_session);
1203
1204 let controller = builder.ready().unwrap().build();
1205 assert!(controller.is_ok());
1206 }
1207
1208 #[tokio::test]
1209 async fn test_builder_build_with_custom_retry_settings() {
1210 let (tx_to_session, _) = mpsc::channel(10);
1211 let mut config = create_test_config(true);
1212 config.max_retries = Some(5);
1213 config.interval = Some(std::time::Duration::from_millis(500));
1214
1215 let builder =
1216 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1217 .with_id(5)
1218 .with_source(create_test_name("source"))
1219 .with_destination(create_test_name("dest"))
1220 .with_config(config.clone())
1221 .with_identity_provider(MockTokenProvider)
1222 .with_identity_verifier(MockVerifier)
1223 .with_tx(create_test_transmitter())
1224 .with_tx_to_session_layer(tx_to_session);
1225
1226 let controller = builder.ready().unwrap().build();
1227 assert!(controller.is_ok());
1228
1229 let controller = controller.unwrap();
1230 let retrieved_config = controller.session_config();
1231 assert_eq!(retrieved_config.max_retries, Some(5));
1232 assert_eq!(
1233 retrieved_config.interval,
1234 Some(std::time::Duration::from_millis(500))
1235 );
1236 }
1237
1238 #[tokio::test]
1239 async fn test_builder_build_with_metadata() {
1240 let (tx_to_session, _) = mpsc::channel(10);
1241 let mut config = create_test_config(false);
1242 let mut metadata = HashMap::new();
1243 metadata.insert("app_name".to_string(), "test_app".to_string());
1244 metadata.insert("version".to_string(), "1.0".to_string());
1245 config.metadata = metadata.clone();
1246
1247 let builder =
1248 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1249 .with_id(6)
1250 .with_source(create_test_name("source"))
1251 .with_destination(create_test_name("dest"))
1252 .with_config(config)
1253 .with_identity_provider(MockTokenProvider)
1254 .with_identity_verifier(MockVerifier)
1255 .with_tx(create_test_transmitter())
1256 .with_tx_to_session_layer(tx_to_session);
1257
1258 let controller = builder.ready().unwrap().build();
1259 assert!(controller.is_ok());
1260
1261 let controller = controller.unwrap();
1262 let retrieved_metadata = controller.metadata();
1263 assert_eq!(
1264 retrieved_metadata.get("app_name"),
1265 Some(&"test_app".to_string())
1266 );
1267 assert_eq!(retrieved_metadata.get("version"), Some(&"1.0".to_string()));
1268 }
1269
1270 #[tokio::test]
1271 async fn test_builder_build_verifies_session_source_and_destination() {
1272 let (tx_to_session, _) = mpsc::channel(10);
1273 let source = create_test_name("my_source");
1274 let destination = create_test_name("my_dest");
1275
1276 let builder =
1277 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1278 .with_id(7)
1279 .with_source(source.clone())
1280 .with_destination(destination.clone())
1281 .with_config(create_test_config(false))
1282 .with_identity_provider(MockTokenProvider)
1283 .with_identity_verifier(MockVerifier)
1284 .with_tx(create_test_transmitter())
1285 .with_tx_to_session_layer(tx_to_session);
1286
1287 let controller = builder.ready().unwrap().build();
1288 assert!(controller.is_ok());
1289
1290 let controller = controller.unwrap();
1291 assert_eq!(controller.source(), &source);
1292 assert_eq!(controller.dst(), &destination);
1293 }
1294
1295 #[tokio::test]
1296 async fn test_builder_build_multiple_sessions_different_ids() {
1297 let (tx_to_session1, _) = mpsc::channel(10);
1298 let (tx_to_session2, _) = mpsc::channel(10);
1299
1300 let builder1 =
1301 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1302 .with_id(100)
1303 .with_source(create_test_name("source1"))
1304 .with_destination(create_test_name("dest1"))
1305 .with_config(create_test_config(false))
1306 .with_identity_provider(MockTokenProvider)
1307 .with_identity_verifier(MockVerifier)
1308 .with_tx(create_test_transmitter())
1309 .with_tx_to_session_layer(tx_to_session1);
1310
1311 let builder2 =
1312 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1313 .with_id(200)
1314 .with_source(create_test_name("source2"))
1315 .with_destination(create_test_name("dest2"))
1316 .with_config(create_test_config(true))
1317 .with_identity_provider(MockTokenProvider)
1318 .with_identity_verifier(MockVerifier)
1319 .with_tx(create_test_transmitter())
1320 .with_tx_to_session_layer(tx_to_session2);
1321
1322 let controller1 = builder1.ready().unwrap().build();
1323 let controller2 = builder2.ready().unwrap().build();
1324
1325 assert!(controller1.is_ok());
1326 assert!(controller2.is_ok());
1327
1328 let controller1 = controller1.unwrap();
1329 let controller2 = controller2.unwrap();
1330
1331 assert_eq!(controller1.id(), 100);
1332 assert_eq!(controller2.id(), 200);
1333 assert_ne!(controller1.id(), controller2.id());
1334 }
1335
1336 #[tokio::test]
1337 async fn test_builder_build_with_unspecified_session_type() {
1338 let (tx_to_session, _) = mpsc::channel(10);
1339 let mut config = create_test_config(false);
1340 config.session_type = ProtoSessionType::Unspecified;
1341
1342 let builder =
1343 SessionBuilder::<MockTokenProvider, MockVerifier, ForController, NotReady>::for_controller()
1344 .with_id(8)
1345 .with_source(create_test_name("source"))
1346 .with_destination(create_test_name("dest"))
1347 .with_config(config)
1348 .with_identity_provider(MockTokenProvider)
1349 .with_identity_verifier(MockVerifier)
1350 .with_tx(create_test_transmitter())
1351 .with_tx_to_session_layer(tx_to_session);
1352
1353 let controller = builder.ready().unwrap().build();
1354 assert!(controller.is_ok());
1355
1356 let controller = controller.unwrap();
1357 assert_eq!(controller.session_type(), ProtoSessionType::Unspecified);
1358 }
1359}