1pub use camel_api::{LanguageExpressionDef, StreamSplitConfig, ValueSourceDef};
2
3use crate::route_ast::CredentialSourceDsl;
4
5#[derive(Default)]
6pub struct SecurityCompileContext {
7 pub authenticator: Option<std::sync::Arc<dyn camel_auth::TokenAuthenticator>>,
8 pub registry: Option<std::sync::Arc<camel_auth::SecurityPolicyRegistry>>,
9 pub evaluator_registry: Option<std::sync::Arc<camel_auth::PermissionEvaluatorRegistry>>,
10}
11
12impl Clone for SecurityCompileContext {
13 fn clone(&self) -> Self {
14 Self {
15 authenticator: self.authenticator.clone(),
16 registry: self.registry.clone(),
17 evaluator_registry: self.evaluator_registry.clone(),
18 }
19 }
20}
21
22impl SecurityCompileContext {
23 pub fn new(
24 authenticator: Option<std::sync::Arc<dyn camel_auth::TokenAuthenticator>>,
25 registry: Option<std::sync::Arc<camel_auth::SecurityPolicyRegistry>>,
26 ) -> Self {
27 Self {
28 authenticator,
29 registry,
30 evaluator_registry: None,
31 }
32 }
33
34 pub fn with_evaluator_registry(
35 mut self,
36 registry: std::sync::Arc<camel_auth::PermissionEvaluatorRegistry>,
37 ) -> Self {
38 self.evaluator_registry = Some(registry);
39 self
40 }
41
42 pub fn with_security_policy_registry(
43 mut self,
44 registry: std::sync::Arc<camel_auth::SecurityPolicyRegistry>,
45 ) -> Self {
46 self.registry = Some(registry);
47 self
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub enum DeclarativeConcurrency {
53 Sequential,
54 Concurrent { max: Option<usize> },
55}
56
57#[derive(Debug, Clone, PartialEq)]
58pub struct DeclarativeCircuitBreaker {
59 pub failure_threshold: u32,
60 pub open_duration_ms: u64,
61 pub fallback: Vec<DeclarativeStep>,
62}
63
64#[derive(Debug, Clone, PartialEq)]
65pub enum DeclarativeSecurityPolicy {
66 Roles {
67 roles: Vec<String>,
68 all_required: bool,
69 trust_upstream_principal: bool,
70 credential_sources: Option<Vec<CredentialSourceDsl>>,
71 },
72 Scopes {
73 scopes: Vec<String>,
74 all_required: bool,
75 trust_upstream_principal: bool,
76 credential_sources: Option<Vec<CredentialSourceDsl>>,
77 },
78 Ref {
79 name: String,
80 },
81 Wasm {
86 path: String,
88 config: std::collections::HashMap<String, String>,
90 },
91 Permission {
92 policy: String,
93 resource: camel_auth::PermissionValueSource,
94 action: camel_auth::PermissionValueSource,
95 scopes: Vec<String>,
96 context: camel_auth::PermissionContextConfig,
97 cache_ttl_secs: Option<u64>,
98 cache_negative_ttl_secs: Option<u64>,
99 },
100}
101
102#[derive(Debug, Clone, PartialEq)]
103pub struct DeclarativeRedeliveryPolicy {
104 pub max_attempts: u32,
105 pub initial_delay_ms: u64,
106 pub multiplier: f64,
107 pub max_delay_ms: u64,
108 pub jitter_factor: f64,
109 pub handled_by: Option<String>,
110}
111
112#[derive(Debug, Clone, PartialEq)]
113pub struct DeclarativeOnException {
114 pub kind: Option<String>,
115 pub message_contains: Option<String>,
116 pub retry: Option<DeclarativeRedeliveryPolicy>,
117 pub steps: Vec<DeclarativeStep>,
118 pub handled: Option<bool>,
119 pub continued: Option<bool>,
120}
121
122#[derive(Debug, Clone, PartialEq, Default)]
123pub struct DeclarativeErrorHandler {
124 pub dead_letter_channel: Option<String>,
125 pub retry: Option<DeclarativeRedeliveryPolicy>,
126 pub on_exceptions: Option<Vec<DeclarativeOnException>>,
127 pub use_original_message: bool,
128}
129
130#[derive(Debug, Clone)]
131pub struct DeclarativeRoute {
132 pub from: String,
133 pub route_id: String,
134 pub auto_startup: bool,
135 pub startup_order: i32,
136 pub concurrency: Option<DeclarativeConcurrency>,
137 pub error_handler: Option<DeclarativeErrorHandler>,
138 pub circuit_breaker: Option<DeclarativeCircuitBreaker>,
139 pub security_policy: Option<DeclarativeSecurityPolicy>,
140 pub unit_of_work: Option<camel_api::UnitOfWorkConfig>,
141 pub steps: Vec<DeclarativeStep>,
142}
143
144#[derive(Debug, Clone, PartialEq, Eq)]
145pub struct ToStepDef {
146 pub uri: String,
147}
148
149impl ToStepDef {
150 pub fn new(uri: impl Into<String>) -> Self {
151 Self { uri: uri.into() }
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub enum LogLevelDef {
157 Trace,
158 Debug,
159 Info,
160 Warn,
161 Error,
162}
163
164#[derive(Debug, Clone, PartialEq)]
167pub struct LogStepDef {
168 pub message: ValueSourceDef,
169 pub level: LogLevelDef,
170}
171
172impl LogStepDef {
173 pub fn info(message: impl Into<String>) -> Self {
174 Self {
175 message: ValueSourceDef::Literal(serde_json::Value::String(message.into())),
176 level: LogLevelDef::Info,
177 }
178 }
179}
180
181#[derive(Debug, Clone, PartialEq)]
182pub struct SetHeaderStepDef {
183 pub key: String,
184 pub value: ValueSourceDef,
185}
186
187impl SetHeaderStepDef {
188 pub fn literal(key: impl Into<String>, value: impl Into<String>) -> Self {
189 Self {
190 key: key.into(),
191 value: ValueSourceDef::Literal(serde_json::Value::String(value.into())),
192 }
193 }
194}
195
196#[derive(Debug, Clone, PartialEq, Eq)]
197pub struct RemoveHeaderStepDef {
198 pub key: String,
199}
200
201#[derive(Debug, Clone, PartialEq)]
202pub struct SetPropertyStepDef {
203 pub key: String,
204 pub value: ValueSourceDef,
205}
206
207impl SetPropertyStepDef {
208 pub fn literal(key: impl Into<String>, value: impl Into<String>) -> Self {
209 Self {
210 key: key.into(),
211 value: ValueSourceDef::Literal(serde_json::Value::String(value.into())),
212 }
213 }
214}
215
216#[derive(Debug, Clone, PartialEq)]
217pub struct SetBodyStepDef {
218 pub value: ValueSourceDef,
219}
220
221#[derive(Debug, Clone, PartialEq)]
222pub struct FilterStepDef {
223 pub predicate: LanguageExpressionDef,
224 pub steps: Vec<DeclarativeStep>,
225}
226
227#[derive(Debug, Clone, PartialEq, Eq)]
228pub struct FunctionStepDef {
229 pub runtime: String,
230 pub source: String,
231 pub timeout_ms: Option<u64>,
232}
233
234#[derive(Debug, Clone, PartialEq)]
235pub struct WhenStepDef {
236 pub predicate: LanguageExpressionDef,
237 pub steps: Vec<DeclarativeStep>,
238}
239
240#[derive(Debug, Clone, PartialEq)]
241pub struct ChoiceStepDef {
242 pub whens: Vec<WhenStepDef>,
243 pub otherwise: Option<Vec<DeclarativeStep>>,
244}
245
246#[derive(Debug, Clone, PartialEq)]
247pub enum SplitExpressionDef {
248 BodyLines,
249 BodyJsonArray,
250 Language(LanguageExpressionDef),
251 Stream(StreamSplitConfig),
252}
253
254#[derive(Debug, Clone, PartialEq, Eq)]
255pub enum SplitAggregationDef {
256 LastWins,
257 CollectAll,
258 Original,
259}
260
261#[derive(Debug, Clone, PartialEq)]
262pub struct SplitStepDef {
263 pub expression: SplitExpressionDef,
264 pub aggregation: SplitAggregationDef,
265 pub parallel: bool,
266 pub parallel_limit: Option<usize>,
267 pub stop_on_exception: bool,
268 pub steps: Vec<DeclarativeStep>,
269}
270
271#[derive(Debug, Clone, PartialEq, Eq)]
272pub enum AggregateStrategyDef {
273 CollectAll,
274}
275
276#[derive(Debug, Clone, PartialEq)]
277pub struct AggregateStepDef {
278 pub header: String,
279 pub correlation_key: Option<String>,
280 pub completion_size: Option<usize>,
281 pub completion_timeout_ms: Option<u64>,
282 pub completion_predicate: Option<LanguageExpressionDef>,
283 pub strategy: AggregateStrategyDef,
284 pub max_buckets: Option<usize>,
285 pub bucket_ttl_ms: Option<u64>,
286 pub force_completion_on_stop: Option<bool>,
287 pub discard_on_timeout: Option<bool>,
288}
289
290#[derive(Debug, Clone, PartialEq, Eq)]
291pub struct WireTapStepDef {
292 pub uri: String,
293}
294
295#[derive(Debug, Clone, PartialEq, Eq)]
296pub struct BeanStepDef {
297 pub name: String,
298 pub method: String,
299}
300
301impl BeanStepDef {
302 pub fn new(name: impl Into<String>, method: impl Into<String>) -> Self {
303 Self {
304 name: name.into(),
305 method: method.into(),
306 }
307 }
308}
309
310#[derive(Debug, Clone, PartialEq, Eq, Default)]
311pub enum ThrottleStrategyDef {
312 #[default]
313 Delay,
314 Reject,
315 Drop,
316}
317
318#[derive(Debug, Clone, PartialEq)]
319pub struct ThrottleStepDef {
320 pub max_requests: usize,
321 pub period_ms: u64,
322 pub strategy: ThrottleStrategyDef,
323 pub steps: Vec<DeclarativeStep>,
324}
325
326#[derive(Debug, Clone, PartialEq, Eq, Default)]
327pub enum LoadBalanceStrategyDef {
328 #[default]
329 RoundRobin,
330 Random,
331 Failover,
332 Weighted {
333 distribution_ratio: String,
334 },
335}
336
337#[derive(Debug, Clone, PartialEq)]
338pub struct LoadBalanceStepDef {
339 pub strategy: LoadBalanceStrategyDef,
340 pub steps: Vec<DeclarativeStep>,
341}
342
343#[derive(Debug, Clone, PartialEq, Eq)]
344pub struct DynamicRouterStepDef {
345 pub expression: LanguageExpressionDef,
346 pub uri_delimiter: String,
347 pub cache_size: i32,
348 pub ignore_invalid_endpoints: bool,
349 pub max_iterations: usize,
350}
351
352#[derive(Debug, Clone, PartialEq, Eq)]
353pub struct RoutingSlipStepDef {
354 pub expression: LanguageExpressionDef,
355 pub uri_delimiter: String,
356 pub cache_size: i32,
357 pub ignore_invalid_endpoints: bool,
358}
359
360#[derive(Debug, Clone, PartialEq, Eq)]
361pub struct RecipientListStepDef {
362 pub expression: LanguageExpressionDef,
363 pub delimiter: String,
364 pub parallel: bool,
365 pub parallel_limit: Option<usize>,
366 pub stop_on_exception: bool,
367 pub aggregation: MulticastAggregationDef,
368}
369
370#[derive(Debug, Clone, PartialEq, Eq)]
371pub enum MulticastAggregationDef {
372 LastWins,
373 CollectAll,
374 Original,
375}
376
377#[derive(Debug, Clone, PartialEq)]
378pub struct MulticastStepDef {
379 pub steps: Vec<DeclarativeStep>,
380 pub parallel: bool,
381 pub parallel_limit: Option<usize>,
382 pub stop_on_exception: bool,
383 pub timeout_ms: Option<u64>,
384 pub aggregation: MulticastAggregationDef,
385}
386
387#[derive(Debug, Clone, PartialEq, Eq)]
388pub struct ScriptStepDef {
389 pub expression: LanguageExpressionDef,
390}
391
392#[derive(Debug, Clone, PartialEq, Eq)]
393pub enum BodyTypeDef {
394 Text,
395 Json,
396 Bytes,
397 Xml,
398 Empty,
399}
400
401#[derive(Debug, Clone, PartialEq)]
402pub struct DataFormatDef {
403 pub format: String,
404 pub schema: Option<serde_json::Value>,
408 pub config: Option<serde_json::Value>,
411}
412
413#[derive(Debug, Clone, PartialEq, Eq)]
414pub struct DelayStepDef {
415 pub delay_ms: u64,
416 pub dynamic_header: Option<String>,
417}
418
419#[derive(Debug, Clone, PartialEq)]
420pub struct LoopStepDef {
421 pub count: Option<usize>,
422 pub while_predicate: Option<LanguageExpressionDef>,
423 pub steps: Vec<DeclarativeStep>,
424 pub max_iterations: Option<usize>,
425}
426
427#[derive(Debug, Clone, PartialEq, Eq)]
428pub struct StreamCacheStepDef {
429 pub threshold: Option<usize>,
430}
431
432#[derive(Debug, Clone, PartialEq, Eq)]
433pub struct ValidateStepDef {
434 pub predicate: LanguageExpressionDef,
435}
436
437#[derive(Debug, Clone, PartialEq, Eq)]
441pub struct ClaimCheckStepDef {
442 pub repository: String,
444 pub operation: String,
446 pub key: LanguageExpressionDef,
448 pub filter: Option<String>,
450}
451
452#[derive(Debug, Clone, PartialEq)]
457pub struct IdempotentConsumerStepDef {
458 pub repository: String,
460 pub expression: LanguageExpressionDef,
462 pub steps: Vec<DeclarativeStep>,
464 pub eager: Option<bool>,
467 pub remove_on_failure: Option<bool>,
470}
471
472#[derive(Debug, Clone, PartialEq)]
477pub struct CacheStepDef {
478 pub repository: Option<String>,
480 pub key: LanguageExpressionDef,
482 pub ttl: Option<String>,
484 pub max_entry_bytes: Option<usize>,
486 pub on_miss: Vec<DeclarativeStep>,
488}
489
490#[derive(Debug, Clone, PartialEq, Eq)]
494pub struct CacheInvalidateStepDef {
495 pub repository: Option<String>,
497 pub key: LanguageExpressionDef,
499}
500
501#[derive(Debug, Clone, PartialEq, Eq)]
505pub struct CachePeekStaleStepDef {
506 pub repository: Option<String>,
508 pub key: LanguageExpressionDef,
510 pub on_miss: Option<String>,
512}
513
514#[derive(Debug, Clone, PartialEq, Eq)]
518pub struct SamplingStepDef {
519 pub period: usize,
521}
522
523#[derive(Debug, Clone, PartialEq, Eq)]
528pub struct SortStepDef {
529 pub expression: LanguageExpressionDef,
531 pub reverse: bool,
533}
534
535#[derive(Debug, Clone, PartialEq, Eq)]
539pub struct ResequenceStepDef {
540 pub mode: ResequenceModeDef,
541}
542
543#[derive(Debug, Clone, PartialEq, Eq)]
545pub enum ResequenceModeDef {
546 Batch {
547 correlation: String,
548 sort: String,
549 completion: camel_api::resequencer::BatchCompletion,
550 },
551 Stream {
552 sequence: String,
553 capacity: usize,
554 gap_timeout: u64,
555 on_gap: camel_api::resequencer::GapPolicy,
556 on_capacity_exceeded: camel_api::resequencer::CapacityPolicy,
557 dedup: bool,
558 },
559}
560
561#[derive(Debug, Clone, PartialEq, Eq)]
562pub struct EnrichStepDef {
563 pub uri: String,
564 pub strategy: Option<String>,
565 pub timeout_ms: Option<u64>,
566}
567
568#[derive(Debug, Clone, PartialEq)]
569pub struct DoTryCatchClauseDef {
570 pub exception: Option<Vec<String>>,
571 pub when: Option<LanguageExpressionDef>,
572 pub on_when: Option<LanguageExpressionDef>,
573 pub disposition: camel_api::error_handler::ExceptionDisposition,
574 pub steps: Vec<DeclarativeStep>,
575}
576
577#[derive(Debug, Clone, PartialEq)]
578pub struct DoTryFinallyDef {
579 pub on_when: Option<LanguageExpressionDef>,
580 pub steps: Vec<DeclarativeStep>,
581}
582
583#[derive(Debug, Clone, PartialEq)]
584pub enum DeclarativeStep {
585 To(ToStepDef),
586 SetHeader(SetHeaderStepDef),
587 SetHeaderIfAbsent(SetHeaderStepDef),
588 RemoveHeader(RemoveHeaderStepDef),
589 SetProperty(SetPropertyStepDef),
590 SetBody(SetBodyStepDef),
591 ConvertBodyTo(BodyTypeDef),
592 DynamicRouter(DynamicRouterStepDef),
593 Filter(FilterStepDef),
594 Function(FunctionStepDef),
595 LoadBalance(LoadBalanceStepDef),
596 Log(LogStepDef),
597 Choice(ChoiceStepDef),
598 Split(SplitStepDef),
599 Aggregate(AggregateStepDef),
600 WireTap(WireTapStepDef),
601 Multicast(MulticastStepDef),
602 RoutingSlip(RoutingSlipStepDef),
603 RecipientList(RecipientListStepDef),
604 Stop,
605 Throttle(ThrottleStepDef),
606 Script(ScriptStepDef),
607 StreamCache(StreamCacheStepDef),
608 Marshal(DataFormatDef),
609 Unmarshal(DataFormatDef),
610 Validate(ValidateStepDef),
611 Bean(BeanStepDef),
612 Delay(DelayStepDef),
613 Loop(LoopStepDef),
614 Enrich(EnrichStepDef),
615 PollEnrich(EnrichStepDef),
616 IdempotentConsumer(IdempotentConsumerStepDef),
617 Cache(CacheStepDef),
618 CacheInvalidate(CacheInvalidateStepDef),
619 CachePeekStale(CachePeekStaleStepDef),
620 ClaimCheck(ClaimCheckStepDef),
621 Sampling(SamplingStepDef),
622 Sort(SortStepDef),
623 Resequence(ResequenceStepDef),
624 DoTry {
625 steps: Vec<DeclarativeStep>,
626 catch: Vec<DoTryCatchClauseDef>,
627 finally: Option<DoTryFinallyDef>,
628 },
629}
630
631impl DeclarativeStep {
632 pub fn kind(&self) -> crate::contract::DeclarativeStepKind {
633 match self {
634 DeclarativeStep::To(_) => crate::contract::DeclarativeStepKind::To,
635 DeclarativeStep::Log(_) => crate::contract::DeclarativeStepKind::Log,
636 DeclarativeStep::SetHeader(_) => crate::contract::DeclarativeStepKind::SetHeader,
637 DeclarativeStep::SetHeaderIfAbsent(_) => {
638 crate::contract::DeclarativeStepKind::SetHeaderIfAbsent
639 }
640 DeclarativeStep::RemoveHeader(_) => crate::contract::DeclarativeStepKind::RemoveHeader,
641 DeclarativeStep::SetProperty(_) => crate::contract::DeclarativeStepKind::SetProperty,
642 DeclarativeStep::SetBody(_) => crate::contract::DeclarativeStepKind::SetBody,
643 DeclarativeStep::ConvertBodyTo(_) => {
644 crate::contract::DeclarativeStepKind::ConvertBodyTo
645 }
646 DeclarativeStep::DynamicRouter(_) => {
647 crate::contract::DeclarativeStepKind::DynamicRouter
648 }
649 DeclarativeStep::Filter(_) => crate::contract::DeclarativeStepKind::Filter,
650 DeclarativeStep::Function(_) => crate::contract::DeclarativeStepKind::Function,
651 DeclarativeStep::LoadBalance(_) => crate::contract::DeclarativeStepKind::LoadBalance,
652 DeclarativeStep::Choice(_) => crate::contract::DeclarativeStepKind::Choice,
653 DeclarativeStep::Split(_) => crate::contract::DeclarativeStepKind::Split,
654 DeclarativeStep::Aggregate(_) => crate::contract::DeclarativeStepKind::Aggregate,
655 DeclarativeStep::WireTap(_) => crate::contract::DeclarativeStepKind::WireTap,
656 DeclarativeStep::Multicast(_) => crate::contract::DeclarativeStepKind::Multicast,
657 DeclarativeStep::RoutingSlip(_) => crate::contract::DeclarativeStepKind::RoutingSlip,
658 DeclarativeStep::RecipientList(_) => {
659 crate::contract::DeclarativeStepKind::RecipientList
660 }
661 DeclarativeStep::Stop => crate::contract::DeclarativeStepKind::Stop,
662 DeclarativeStep::Throttle(_) => crate::contract::DeclarativeStepKind::Throttle,
663 DeclarativeStep::Script(_) => crate::contract::DeclarativeStepKind::Script,
664 DeclarativeStep::StreamCache(_) => crate::contract::DeclarativeStepKind::StreamCache,
665 DeclarativeStep::Marshal(_) => crate::contract::DeclarativeStepKind::Marshal,
666 DeclarativeStep::Unmarshal(_) => crate::contract::DeclarativeStepKind::Unmarshal,
667 DeclarativeStep::Validate(_) => crate::contract::DeclarativeStepKind::Validate,
668 DeclarativeStep::Bean(_) => crate::contract::DeclarativeStepKind::Bean,
669 DeclarativeStep::Delay(_) => crate::contract::DeclarativeStepKind::Delay,
670 DeclarativeStep::Loop(_) => crate::contract::DeclarativeStepKind::Loop,
671 DeclarativeStep::Enrich(_) => crate::contract::DeclarativeStepKind::Enrich,
672 DeclarativeStep::PollEnrich(_) => crate::contract::DeclarativeStepKind::PollEnrich,
673 DeclarativeStep::IdempotentConsumer(_) => {
674 crate::contract::DeclarativeStepKind::IdempotentConsumer
675 }
676 DeclarativeStep::Cache(_) => crate::contract::DeclarativeStepKind::Cache,
677 DeclarativeStep::CacheInvalidate(_) => {
678 crate::contract::DeclarativeStepKind::CacheInvalidate
679 }
680 DeclarativeStep::CachePeekStale(_) => {
681 crate::contract::DeclarativeStepKind::CachePeekStale
682 }
683 DeclarativeStep::ClaimCheck(_) => crate::contract::DeclarativeStepKind::ClaimCheck,
684 DeclarativeStep::Sampling(_) => crate::contract::DeclarativeStepKind::Sampling,
685 DeclarativeStep::Sort(_) => crate::contract::DeclarativeStepKind::Sort,
686 DeclarativeStep::Resequence(_) => crate::contract::DeclarativeStepKind::Resequence,
687 DeclarativeStep::DoTry { .. } => crate::contract::DeclarativeStepKind::DoTry,
688 }
689 }
690}
691
692#[cfg(test)]
693mod tests {
694 use super::*;
695
696 #[test]
697 fn to_step_def_new() {
698 let def = ToStepDef::new("direct:a");
699 assert_eq!(def.uri, "direct:a");
700 }
701
702 #[test]
703 fn log_step_def_info() {
704 let def = LogStepDef::info("hello");
705 assert_eq!(def.level, LogLevelDef::Info);
706 match def.message {
707 ValueSourceDef::Literal(v) => assert_eq!(v, serde_json::Value::String("hello".into())),
708 _ => panic!("expected literal"),
709 }
710 }
711
712 #[test]
713 fn set_header_literal() {
714 let def = SetHeaderStepDef::literal("key", "value");
715 assert_eq!(def.key, "key");
716 match def.value {
717 ValueSourceDef::Literal(v) => assert_eq!(v, serde_json::Value::String("value".into())),
718 _ => panic!("expected literal"),
719 }
720 }
721
722 #[test]
723 fn remove_header_kind_returns_correct_variant() {
724 let step = DeclarativeStep::RemoveHeader(RemoveHeaderStepDef {
725 key: "X-Foo".into(),
726 });
727 assert_eq!(
728 step.kind(),
729 crate::contract::DeclarativeStepKind::RemoveHeader
730 );
731 }
732
733 #[test]
734 fn bean_step_def_new() {
735 let def = BeanStepDef::new("myBean", "process");
736 assert_eq!(def.name, "myBean");
737 assert_eq!(def.method, "process");
738 }
739
740 #[test]
741 fn throttle_strategy_default() {
742 assert_eq!(ThrottleStrategyDef::default(), ThrottleStrategyDef::Delay);
743 }
744
745 #[test]
746 fn load_balance_strategy_default() {
747 assert_eq!(
748 LoadBalanceStrategyDef::default(),
749 LoadBalanceStrategyDef::RoundRobin
750 );
751 }
752
753 #[test]
754 fn concurrency_variants_equality() {
755 assert_eq!(
756 DeclarativeConcurrency::Sequential,
757 DeclarativeConcurrency::Sequential
758 );
759 assert_ne!(
760 DeclarativeConcurrency::Sequential,
761 DeclarativeConcurrency::Concurrent { max: None }
762 );
763 }
764
765 #[test]
766 fn body_type_variants() {
767 assert_eq!(BodyTypeDef::Text, BodyTypeDef::Text);
768 assert_ne!(BodyTypeDef::Text, BodyTypeDef::Json);
769 }
770
771 #[test]
772 fn data_format_def() {
773 let def = DataFormatDef {
774 format: "protobuf".into(),
775 schema: None,
776 config: None,
777 };
778 assert_eq!(def.format, "protobuf");
779 assert!(def.schema.is_none());
780 }
781
782 #[test]
783 fn stream_cache_step_def() {
784 let def = StreamCacheStepDef {
785 threshold: Some(1024),
786 };
787 assert_eq!(def.threshold, Some(1024));
788 }
789
790 #[test]
791 fn delay_step_def() {
792 let def = DelayStepDef {
793 delay_ms: 500,
794 dynamic_header: Some("X-Delay".into()),
795 };
796 assert_eq!(def.delay_ms, 500);
797 assert_eq!(def.dynamic_header.as_deref(), Some("X-Delay"));
798 }
799
800 #[test]
801 fn circuit_breaker_def() {
802 let cb = DeclarativeCircuitBreaker {
803 failure_threshold: 3,
804 open_duration_ms: 5000,
805 fallback: vec![],
806 };
807 assert_eq!(cb.failure_threshold, 3);
808 assert_eq!(cb.open_duration_ms, 5000);
809 }
810}