1use dyn_clone::{DynClone, clone_trait_object};
2use erased_serde::serialize_trait_object;
3use indexmap::IndexMap;
4use serde::Serialize;
5#[derive(Default, Debug, Clone, PartialEq)]
6pub struct Inventory {
7 pub name: String,
8 pub root: InventoryRoot,
9}
10
11#[derive(Default, Debug, Clone, PartialEq, Serialize)]
12pub struct InventoryRoot {
13 pub all: Child,
14}
15
16#[derive(Default, Debug, Clone, PartialEq, Serialize)]
17pub struct Child {
18 #[serde(skip_serializing_if = "OptU::is_unset")]
19 pub hosts: OptU<IndexMap<String, Option<IndexMap<String, serde_json::Value>>>>,
20 #[serde(skip_serializing_if = "OptU::is_unset")]
21 pub children: OptU<IndexMap<String, Child>>,
22 #[serde(skip_serializing_if = "OptU::is_unset")]
23 pub vars: OptU<IndexMap<String, serde_json::Value>>,
24}
25
26#[derive(Clone, Debug)]
27pub struct Playbook {
28 pub name: String,
31 pub plays: Vec<Play>,
32}
33
34#[derive(Clone, Debug, PartialEq, Default, Serialize)]
45#[serde(untagged)]
46pub enum OptU<T: Serialize> {
47 Some(T),
48 #[default]
49 Unset,
50}
51
52impl<T: Serialize> OptU<T> {
54 pub fn is_unset(&self) -> bool {
55 matches!(self, OptU::Unset)
56 }
57}
58
59#[derive(Serialize, Clone, Debug)]
62pub struct Play {
63 pub name: String,
65 pub hosts: StringOrVecString,
67 #[serde(flatten)]
68 pub options: PlayOptions,
69 pub tasks: Vec<Task>,
71}
72
73#[derive(Serialize, Default, Clone, Debug)]
75pub struct PlayOptions {
76 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
78 pub any_errors_fatal: OptU<bool>,
79 #[serde(
82 rename = "become",
83 default = "OptU::default",
84 skip_serializing_if = "OptU::is_unset"
85 )]
86 pub become_: OptU<bool>,
87 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
89 pub become_exe: OptU<String>,
90 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
92 pub become_flags: OptU<String>,
93 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
95 pub become_method: OptU<String>,
96 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
98 pub become_user: OptU<String>,
99 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
101 pub check_mode: OptU<bool>,
102 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
104 pub collections: OptU<Vec<String>>,
105 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
107 pub connection: OptU<String>,
108 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
110 pub debugger: OptU<bool>,
111 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
113 pub diff: OptU<bool>,
114 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
119 pub environment: OptU<IndexMap<String, String>>,
120 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
122 pub fact_path: OptU<String>,
123 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
126 pub force_handlers: OptU<bool>,
127 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
129 pub gather_facts: OptU<bool>,
130 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
132 pub gather_subset: OptU<Vec<String>>,
133 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
135 pub gather_timeout: OptU<i64>,
136 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
140 pub handlers: OptU<Vec<Task>>,
141 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
143 pub ignore_errors: OptU<bool>,
144 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
147 pub ignore_unreachable: OptU<bool>,
148 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
151 pub max_fail_percentage: OptU<i64>,
152 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
154 pub module_defaults: OptU<IndexMap<String, serde_json::Value>>,
155 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
157 pub no_log: OptU<bool>,
158 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
161 pub order: OptU<String>,
162 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
164 pub port: OptU<i64>,
165 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
167 pub post_tasks: OptU<Vec<Task>>,
168 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
170 pub pre_tasks: OptU<Vec<Task>>,
171 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
173 pub remote_user: OptU<String>,
174 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
176 pub roles: OptU<Vec<String>>,
177 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
180 pub run_once: OptU<bool>,
181 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
183 pub serial: OptU<i64>,
184 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
186 pub strategy: OptU<String>,
187 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
189 pub tags: OptU<Vec<String>>,
190 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
192 pub throttle: OptU<i64>,
193 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
195 pub timeout: OptU<i64>,
196 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
198 pub vars: OptU<IndexMap<String, serde_json::Value>>,
199 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
201 pub vars_files: OptU<Vec<String>>,
202 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
204 pub vars_prompt: OptU<Vec<String>>,
205}
206
207#[derive(Serialize, Clone, Debug)]
208pub struct Task {
209 pub name: String,
211 #[serde(flatten)]
212 pub options: TaskOptions,
213 #[serde(flatten)]
214 pub command: Box<dyn TaskModule>,
215}
216
217pub trait TaskModule: erased_serde::Serialize + DynClone + std::fmt::Debug {}
233
234serialize_trait_object!(TaskModule);
235clone_trait_object!(TaskModule);
236
237#[derive(Serialize, Default, Clone, Debug, PartialEq)]
239pub struct TaskOptions {
240 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
242 pub action: OptU<String>,
243 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
245 pub any_errors_fatal: OptU<bool>,
246 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
248 pub args: OptU<IndexMap<String, serde_json::Value>>,
249 #[serde(
251 rename = "async",
252 default = "OptU::default",
253 skip_serializing_if = "OptU::is_unset"
254 )]
255 pub async_: OptU<i64>,
256 #[serde(
259 rename = "become",
260 default = "OptU::default",
261 skip_serializing_if = "OptU::is_unset"
262 )]
263 pub become_: OptU<bool>,
264 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
266 pub become_exe: OptU<String>,
267 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
269 pub become_flags: OptU<String>,
270 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
272 pub become_method: OptU<String>,
273 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
275 pub become_user: OptU<String>,
276 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
281 pub changed_when: OptU<BoolOrStringOrVecString>,
282 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
284 pub check_mode: OptU<bool>,
285 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
287 pub collections: OptU<Vec<String>>,
288 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
290 pub connection: OptU<String>,
291 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
293 pub debugger: OptU<bool>,
294 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
298 pub delay: OptU<i64>,
299 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
303 pub delegate_facts: OptU<bool>,
304 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
307 pub delegate_to: OptU<String>,
308
309 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
311 pub diff: OptU<bool>,
312
313 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
318 pub environment: OptU<IndexMap<String, String>>,
319 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
321 pub failed_when: OptU<BoolOrStringOrVecString>,
322
323 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
325 pub ignore_errors: OptU<bool>,
326
327 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
330 pub ignore_unreachable: OptU<bool>,
331
332 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
334 pub local_action: OptU<String>,
335 #[serde(
337 rename = "loop",
338 default = "OptU::default",
339 skip_serializing_if = "OptU::is_unset"
340 )]
341 pub loop_: OptU<Vec<serde_json::Value>>,
342
343 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
345 pub loop_control: OptU<IndexMap<String, serde_json::Value>>,
346
347 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
349 pub module_defaults: OptU<IndexMap<String, serde_json::Value>>,
350
351 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
353 pub no_log: OptU<bool>,
354 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
356 pub notify: OptU<Vec<String>>,
357
358 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
360 pub poll: OptU<i64>,
361
362 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
364 pub port: OptU<i64>,
365
366 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
368 pub register: OptU<String>,
369
370 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
372 pub remote_user: OptU<String>,
373
374 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
376 pub retries: OptU<i64>,
377 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
380 pub run_once: OptU<bool>,
381
382 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
384 pub tags: OptU<Vec<String>>,
385
386 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
390 pub throttle: OptU<i64>,
391
392 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
395 pub timeout: OptU<i64>,
396
397 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
399 pub until: OptU<String>,
400
401 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
403 pub vars: OptU<IndexMap<String, serde_json::Value>>,
404
405 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
407 pub when: OptU<BoolOrStringOrVecString>,
408 }
412
413#[derive(Serialize, Clone, Debug, PartialEq)]
415#[serde(untagged)]
416pub enum BoolOrString {
417 Bool(bool),
418 String(String),
419}
420
421impl From<bool> for BoolOrString {
422 fn from(value: bool) -> Self {
423 Self::Bool(value)
424 }
425}
426
427impl From<String> for BoolOrString {
428 fn from(value: String) -> Self {
429 Self::String(value)
430 }
431}
432
433#[derive(Serialize, Clone, Debug, PartialEq)]
435#[serde(untagged)]
436pub enum StringOrVecString {
437 String(String),
438 VecString(Vec<String>),
439}
440
441impl From<String> for StringOrVecString {
442 fn from(value: String) -> Self {
443 Self::String(value)
444 }
445}
446
447impl From<Vec<String>> for StringOrVecString {
448 fn from(value: Vec<String>) -> Self {
449 Self::VecString(value)
450 }
451}
452
453#[derive(Serialize, Clone, Debug, PartialEq)]
455#[serde(untagged)]
456pub enum BoolOrStringOrVecString {
457 Bool(bool),
458 String(String),
459 VecString(Vec<String>),
460}
461
462impl From<bool> for BoolOrStringOrVecString {
463 fn from(value: bool) -> Self {
464 Self::Bool(value)
465 }
466}
467
468impl From<String> for BoolOrStringOrVecString {
469 fn from(value: String) -> Self {
470 Self::String(value)
471 }
472}
473
474impl From<Vec<String>> for BoolOrStringOrVecString {
475 fn from(value: Vec<String>) -> Self {
476 Self::VecString(value)
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483
484 #[derive(Serialize, Clone, Debug, PartialEq)]
485 struct SampleTaskModule {
486 x1: String,
487 }
488
489 impl TaskModule for SampleTaskModule {}
490
491 #[test]
492 fn test_play_minimum() {
493 assert_eq!(
494 serde_json::to_string(&Play {
495 name: "play1".to_string(),
496 hosts: vec!["host1".to_string()].into(),
497 tasks: vec![Task {
498 name: "task1".to_string(),
499 options: TaskOptions::default(),
500 command: Box::new(SampleTaskModule {
501 x1: "x1".to_string(),
502 }),
503 }],
504 options: PlayOptions::default(),
505 })
506 .expect("failed to serialize"),
507 r#"{"name":"play1","hosts":["host1"],"tasks":[{"name":"task1","x1":"x1"}]}"#
508 );
509 }
510
511 #[test]
512 fn test_play_with_all_fields() {
513 assert_eq!(
514 serde_json::to_string(&Play {
515 name: "play1".to_string(),
516 hosts: vec!["host1".to_string()].into(),
517 tasks: vec![Task {
518 name: "task1".to_string(),
519 options: TaskOptions::default(),
520 command: Box::new(SampleTaskModule {
521 x1: "x1".to_string(),
522 }),
523 }],
524 options: PlayOptions {
525 any_errors_fatal: OptU::Some(true),
526 become_: OptU::Some(true),
527 become_exe: OptU::Some("become_exe".to_string()),
528 become_flags: OptU::Some("become_flags".to_string()),
529 become_method: OptU::Some("become_method".to_string()),
530 become_user: OptU::Some("become_user".to_string()),
531 check_mode: OptU::Some(true),
532 collections: OptU::Some(vec!["collection1".to_string()]),
533 connection: OptU::Some("connection1".to_string()),
534 debugger: OptU::Some(true),
535 diff: OptU::Some(true),
536 environment: OptU::Some(IndexMap::from([(
537 "env1".to_string(),
538 "value1".to_string()
539 )])),
540 fact_path: OptU::Some("fact_path".to_string()),
541 force_handlers: OptU::Some(true),
542 gather_facts: OptU::Some(true),
543 gather_subset: OptU::Some(vec!["gather_subset1".to_string()]),
544 gather_timeout: OptU::Some(10),
545 handlers: OptU::Some(vec![Task {
546 name: "handler1".to_string(),
547 options: TaskOptions::default(),
548 command: Box::new(SampleTaskModule {
549 x1: "x1".to_string(),
550 }),
551 }]),
552 ignore_errors: OptU::Some(true),
553 ignore_unreachable: OptU::Some(true),
554 max_fail_percentage: OptU::Some(10),
555 module_defaults: OptU::Some(IndexMap::from([(
556 "module1".to_string(),
557 serde_json::Value::String("value1".to_string())
558 )])),
559 no_log: OptU::Some(true),
560 order: OptU::Some("order".to_string()),
561 port: OptU::Some(10),
562 post_tasks: OptU::Some(vec![Task {
563 name: "post_task1".to_string(),
564 options: TaskOptions::default(),
565 command: Box::new(SampleTaskModule {
566 x1: "x1".to_string(),
567 }),
568 }]),
569 pre_tasks: OptU::Some(vec![Task {
570 name: "pre_task1".to_string(),
571 options: TaskOptions::default(),
572 command: Box::new(SampleTaskModule {
573 x1: "x1".to_string(),
574 }),
575 }]),
576 remote_user: OptU::Some("remote_user".to_string()),
577 roles: OptU::Some(vec!["role1".to_string()]),
578 run_once: OptU::Some(true),
579 serial: OptU::Some(10),
580 strategy: OptU::Some("strategy".to_string()),
581 tags: OptU::Some(vec!["tag1".to_string()]),
582 throttle: OptU::Some(10),
583 timeout: OptU::Some(10),
584 vars: OptU::Some(IndexMap::from([(
585 "var1".to_string(),
586 serde_json::Value::String("value1".to_string())
587 )])),
588 vars_files: OptU::Some(vec!["vars_file1".to_string()]),
589 vars_prompt: OptU::Some(vec!["vars_prompt1".to_string()]),
590 }
591 })
592 .expect("failed to serialize"),
593 String::new()
594 + "{"
595 + r#""name":"play1","#
596 + r#""hosts":["host1"],"#
597 + r#""any_errors_fatal":true,"#
598 + r#""become":true,"#
599 + r#""become_exe":"become_exe","#
600 + r#""become_flags":"become_flags","#
601 + r#""become_method":"become_method","#
602 + r#""become_user":"become_user","#
603 + r#""check_mode":true,"#
604 + r#""collections":["collection1"],"#
605 + r#""connection":"connection1","#
606 + r#""debugger":true,"#
607 + r#""diff":true,"#
608 + r#""environment":{"env1":"value1"},"#
609 + r#""fact_path":"fact_path","#
610 + r#""force_handlers":true,"#
611 + r#""gather_facts":true,"#
612 + r#""gather_subset":["gather_subset1"],"#
613 + r#""gather_timeout":10,"#
614 + r#""handlers":[{"name":"handler1","x1":"x1"}],"#
615 + r#""ignore_errors":true,"#
616 + r#""ignore_unreachable":true,"#
617 + r#""max_fail_percentage":10,"#
618 + r#""module_defaults":{"module1":"value1"},"#
619 + r#""no_log":true,"#
620 + r#""order":"order","#
621 + r#""port":10,"#
622 + r#""post_tasks":[{"name":"post_task1","x1":"x1"}],"#
623 + r#""pre_tasks":[{"name":"pre_task1","x1":"x1"}],"#
624 + r#""remote_user":"remote_user","#
625 + r#""roles":["role1"],"#
626 + r#""run_once":true,"#
627 + r#""serial":10,"#
628 + r#""strategy":"strategy","#
629 + r#""tags":["tag1"],"#
630 + r#""throttle":10,"#
631 + r#""timeout":10,"#
632 + r#""vars":{"var1":"value1"},"#
633 + r#""vars_files":["vars_file1"],"#
634 + r#""vars_prompt":["vars_prompt1"],"#
635 + r#""tasks":[{"name":"task1","x1":"x1"}]"#
636 + r#"}"#
637 );
638 }
639
640 #[test]
641 fn test_task_options_with_all_fields() {
643 assert_eq!(
644 serde_json::to_string(&TaskOptions {
645 action: OptU::Some("action1".to_string()),
646 any_errors_fatal: OptU::Some(true),
647 args: OptU::Some(IndexMap::from([(
648 "arg1".to_string(),
649 serde_json::Value::String("value1".to_string())
650 )])),
651 async_: OptU::Some(10),
652 become_: OptU::Some(true),
653 become_exe: OptU::Some("become_exe".to_string()),
654 become_flags: OptU::Some("become_flags".to_string()),
655 become_method: OptU::Some("become_method".to_string()),
656 become_user: OptU::Some("become_user".to_string()),
657 changed_when: OptU::Some("changed_when".to_string().into()),
658 check_mode: OptU::Some(true),
659 collections: OptU::Some(vec!["collection1".to_string()]),
660 connection: OptU::Some("connection1".to_string()),
661 debugger: OptU::Some(true),
662 delay: OptU::Some(10),
663 delegate_facts: OptU::Some(true),
664 delegate_to: OptU::Some("delegate_to".to_string()),
665 diff: OptU::Some(true),
666 environment: OptU::Some(IndexMap::from([(
667 "env1".to_string(),
668 "value1".to_string()
669 )])),
670 failed_when: OptU::Some("failed_when".to_string().into()),
671 ignore_errors: OptU::Some(true),
672 ignore_unreachable: OptU::Some(true),
673 local_action: OptU::Some("local_action".to_string()),
674 loop_: OptU::Some(vec![serde_json::Value::String("loop1".to_string())]),
675 loop_control: OptU::Some(IndexMap::from([(
676 "loop_control1".to_string(),
677 serde_json::Value::String("value1".to_string())
678 )])),
679 module_defaults: OptU::Some(IndexMap::from([(
680 "module1".to_string(),
681 serde_json::Value::String("value1".to_string())
682 )])),
683 no_log: OptU::Some(true),
684 notify: OptU::Some(vec!["notify1".to_string()]),
685 poll: OptU::Some(10),
686 port: OptU::Some(10),
687 register: OptU::Some("register".to_string()),
688 remote_user: OptU::Some("remote_user".to_string()),
689 retries: OptU::Some(10),
690 run_once: OptU::Some(true),
691 tags: OptU::Some(vec!["tag1".to_string()]),
692 throttle: OptU::Some(10),
693 timeout: OptU::Some(10),
694 until: OptU::Some("until".to_string()),
695 vars: OptU::Some(IndexMap::from([(
696 "var1".to_string(),
697 serde_json::Value::String("value1".to_string())
698 )])),
699 when: OptU::Some("when".to_string().into()),
700 })
701 .expect("failed to serialize"),
702 String::new()
703 + r#"{""#
704 + r#"action":"action1","#
705 + r#""any_errors_fatal":true,"#
706 + r#""args":{"arg1":"value1"},"#
707 + r#""async":10,"#
708 + r#""become":true,"#
709 + r#""become_exe":"become_exe","#
710 + r#""become_flags":"become_flags","#
711 + r#""become_method":"become_method","#
712 + r#""become_user":"become_user","#
713 + r#""changed_when":"changed_when","#
714 + r#""check_mode":true,"#
715 + r#""collections":["collection1"],"#
716 + r#""connection":"connection1","#
717 + r#""debugger":true,"#
718 + r#""delay":10,"#
719 + r#""delegate_facts":true,"#
720 + r#""delegate_to":"delegate_to","#
721 + r#""diff":true,"#
722 + r#""environment":{"env1":"value1"},"#
723 + r#""failed_when":"failed_when","#
724 + r#""ignore_errors":true,"#
725 + r#""ignore_unreachable":true,"#
726 + r#""local_action":"local_action","#
727 + r#""loop":["loop1"],"#
728 + r#""loop_control":{"loop_control1":"value1"},"#
729 + r#""module_defaults":{"module1":"value1"},"#
730 + r#""no_log":true,"#
731 + r#""notify":["notify1"],"#
732 + r#""poll":10,"#
733 + r#""port":10,"#
734 + r#""register":"register","#
735 + r#""remote_user":"remote_user","#
736 + r#""retries":10,"#
737 + r#""run_once":true,"#
738 + r#""tags":["tag1"],"#
739 + r#""throttle":10,"#
740 + r#""timeout":10,"#
741 + r#""until":"until","#
742 + r#""vars":{"var1":"value1"},"#
743 + r#""when":"when""#
744 + r#"}"#
745 );
746 }
747
748 #[test]
749 fn test_changed_when_bool() {
750 assert_eq!(
751 serde_json::to_string(&TaskOptions {
752 changed_when: OptU::Some(true.into()),
753 ..Default::default()
754 })
755 .expect("failed to serialize"),
756 String::new() + r#"{"changed_when":true}"#
757 );
758 }
759
760 #[test]
761 fn test_changed_when_string() {
762 assert_eq!(
763 serde_json::to_string(&TaskOptions {
764 changed_when: OptU::Some("changed_when".to_string().into()),
765 ..Default::default()
766 })
767 .expect("failed to serialize"),
768 String::new() + r#"{"changed_when":"changed_when"}"#
769 );
770 }
771 #[test]
772 fn test_changed_when_vec_string() {
773 assert_eq!(
774 serde_json::to_string(&TaskOptions {
775 changed_when: OptU::Some(
776 vec!["changed_when1".to_string(), "changed_when2".to_string()].into()
777 ),
778 ..Default::default()
779 })
780 .expect("failed to serialize"),
781 String::new() + r#"{"changed_when":["changed_when1","changed_when2"]}"#
782 );
783 }
784
785 #[test]
786 fn test_failed_when_bool() {
787 assert_eq!(
788 serde_json::to_string(&TaskOptions {
789 failed_when: OptU::Some(true.into()),
790 ..Default::default()
791 })
792 .expect("failed to serialize"),
793 String::new() + r#"{"failed_when":true}"#
794 );
795 }
796
797 #[test]
798 fn test_failed_when_string() {
799 assert_eq!(
800 serde_json::to_string(&TaskOptions {
801 failed_when: OptU::Some("failed_when".to_string().into()),
802 ..Default::default()
803 })
804 .expect("failed to serialize"),
805 String::new() + r#"{"failed_when":"failed_when"}"#
806 );
807 }
808
809 #[test]
810 fn test_failed_when_vec_string() {
811 assert_eq!(
812 serde_json::to_string(&TaskOptions {
813 failed_when: OptU::Some(
814 vec!["failed_when1".to_string(), "failed_when2".to_string()].into()
815 ),
816 ..Default::default()
817 })
818 .expect("failed to serialize"),
819 String::new() + r#"{"failed_when":["failed_when1","failed_when2"]}"#
820 );
821 }
822
823 #[test]
824 fn test_when_bool() {
825 assert_eq!(
826 serde_json::to_string(&TaskOptions {
827 when: OptU::Some(true.into()),
828 ..Default::default()
829 })
830 .expect("failed to serialize"),
831 String::new() + r#"{"when":true}"#
832 );
833 }
834
835 #[test]
836 fn test_when_string() {
837 assert_eq!(
838 serde_json::to_string(&TaskOptions {
839 when: OptU::Some("1 == 1".to_string().into()),
840 ..Default::default()
841 })
842 .expect("failed to serialize"),
843 String::new() + r#"{"when":"1 == 1"}"#
844 );
845 }
846
847 #[test]
848 fn test_when_vec_string() {
849 assert_eq!(
850 serde_json::to_string(&TaskOptions {
851 when: OptU::Some(vec!["1 == 1".to_string(), "2 == 2".to_string()].into()),
852 ..Default::default()
853 })
854 .expect("failed to serialize"),
855 String::new() + r#"{"when":["1 == 1","2 == 2"]}"#
856 );
857 }
858}