1use crate::component_id_index::make_index_file;
6use crate::{
7 generate_storage_path, CheckUse, ExpectedResult, RoutingTestModel, RoutingTestModelBuilder,
8};
9use cm_config::{CapabilityAllowlistKey, CapabilityAllowlistSource};
10use cm_rust::*;
11use cm_rust_testing::*;
12use component_id_index::InstanceId;
13use moniker::{ExtendedMoniker, Moniker};
14use std::collections::HashSet;
15use std::marker::PhantomData;
16use {fidl_fuchsia_io as fio, zx_status};
17
18pub struct CommonStorageTest<T: RoutingTestModelBuilder> {
19 builder: PhantomData<T>,
20}
21
22impl<T: RoutingTestModelBuilder> CommonStorageTest<T> {
23 pub fn new() -> Self {
24 Self { builder: PhantomData }
25 }
26
27 pub async fn test_storage_dir_from_cm_namespace(&self) {
37 let components = vec![
38 (
39 "a",
40 ComponentDeclBuilder::new()
41 .offer(
42 OfferBuilder::storage()
43 .name("cache")
44 .source(OfferSource::Self_)
45 .target_static_child("b"),
46 )
47 .child_default("b")
48 .capability(
49 CapabilityBuilder::storage()
50 .name("cache")
51 .backing_dir("tmp")
52 .source(StorageDirectorySource::Parent)
53 .subdir("cache"),
54 )
55 .build(),
56 ),
57 (
58 "b",
59 ComponentDeclBuilder::new()
60 .use_(UseBuilder::storage().name("cache").path("/storage"))
61 .build(),
62 ),
63 ];
64 let namespace_capabilities = vec![CapabilityBuilder::directory()
65 .name("tmp")
66 .path("/tmp")
67 .rights(fio::RW_STAR_DIR)
68 .build()];
69 let mut builder = T::new("a", components);
70 builder.set_namespace_capabilities(namespace_capabilities);
71 let model = builder.build().await;
72
73 model
74 .check_use(
75 ["b"].try_into().unwrap(),
76 CheckUse::Storage {
77 path: "/storage".parse().unwrap(),
78 storage_relation: Some(Moniker::try_from(["b"]).unwrap()),
79 from_cm_namespace: true,
80 storage_subdir: Some("cache".to_string()),
81 expected_res: ExpectedResult::Ok,
82 },
83 )
84 .await;
85
86 model.check_namespace_subdir_contents("/tmp/cache", vec!["b:0".to_string()]).await;
87 }
88
89 pub async fn test_storage_from_void(&self) {
96 let components = vec![
97 (
98 "a",
99 ComponentDeclBuilder::new()
100 .offer(
101 OfferBuilder::storage()
102 .name("cache")
103 .source(OfferSource::Void)
104 .target_static_child("b")
105 .availability(Availability::Optional),
106 )
107 .child_default("b")
108 .build(),
109 ),
110 (
111 "b",
112 ComponentDeclBuilder::new()
113 .use_(UseBuilder::storage().name("cache").path("/storage"))
114 .build(),
115 ),
116 ];
117 let model = T::new("a", components).build().await;
118 model
119 .check_use(
120 ["b"].try_into().unwrap(),
121 CheckUse::Storage {
122 path: "/storage".parse().unwrap(),
123 storage_relation: Some(Moniker::try_from(["b"]).unwrap()),
124 from_cm_namespace: false,
125 storage_subdir: None,
126 expected_res: ExpectedResult::Err(zx_status::Status::NOT_FOUND),
127 },
128 )
129 .await;
130 }
131
132 pub async fn test_storage_and_dir_from_parent(&self) {
140 let components = vec![
141 (
142 "a",
143 ComponentDeclBuilder::new()
144 .capability(
145 CapabilityBuilder::directory()
146 .name("data")
147 .path("/data")
148 .rights(fio::RW_STAR_DIR),
149 )
150 .offer(
151 OfferBuilder::storage()
152 .name("cache")
153 .source(OfferSource::Self_)
154 .target_static_child("b"),
155 )
156 .child_default("b")
157 .capability(
158 CapabilityBuilder::storage()
159 .name("cache")
160 .backing_dir("data")
161 .source(StorageDirectorySource::Self_),
162 )
163 .build(),
164 ),
165 (
166 "b",
167 ComponentDeclBuilder::new()
168 .use_(UseBuilder::storage().name("cache").path("/storage"))
169 .build(),
170 ),
171 ];
172 let model = T::new("a", components).build().await;
173 model
174 .check_use(
175 ["b"].try_into().unwrap(),
176 CheckUse::Storage {
177 path: "/storage".parse().unwrap(),
178 storage_relation: Some(Moniker::try_from(["b"]).unwrap()),
179 from_cm_namespace: false,
180 storage_subdir: None,
181 expected_res: ExpectedResult::Ok,
182 },
183 )
184 .await;
185 model.check_test_subdir_contents(".", vec!["b:0".to_string(), "foo".to_string()]).await;
186 }
187
188 pub async fn test_storage_and_dir_from_parent_with_subdir(&self) {
197 let components = vec![
198 (
199 "a",
200 ComponentDeclBuilder::new()
201 .capability(
202 CapabilityBuilder::directory()
203 .name("data")
204 .path("/data")
205 .rights(fio::RW_STAR_DIR),
206 )
207 .offer(
208 OfferBuilder::storage()
209 .name("cache")
210 .source(OfferSource::Self_)
211 .target_static_child("b"),
212 )
213 .child_default("b")
214 .capability(
215 CapabilityBuilder::storage()
216 .name("cache")
217 .backing_dir("data")
218 .source(StorageDirectorySource::Self_)
219 .subdir("cache"),
220 )
221 .build(),
222 ),
223 (
224 "b",
225 ComponentDeclBuilder::new()
226 .use_(UseBuilder::storage().name("cache").path("/storage"))
227 .build(),
228 ),
229 ];
230 let model = T::new("a", components).build().await;
231 model
232 .check_use(
233 ["b"].try_into().unwrap(),
234 CheckUse::Storage {
235 path: "/storage".parse().unwrap(),
236 storage_relation: Some(Moniker::try_from(["b"]).unwrap()),
237 from_cm_namespace: false,
238 storage_subdir: Some("cache".to_string()),
239 expected_res: ExpectedResult::Ok,
240 },
241 )
242 .await;
243 model.check_test_subdir_contents(".", vec!["cache".to_string(), "foo".to_string()]).await;
244 }
245
246 pub async fn test_storage_and_dir_from_parent_rights_invalid(&self) {
255 let components = vec![
256 (
257 "a",
258 ComponentDeclBuilder::new()
259 .capability(CapabilityBuilder::directory().name("data").path("/data"))
260 .offer(
261 OfferBuilder::storage()
262 .name("cache")
263 .source(OfferSource::Self_)
264 .target_static_child("b"),
265 )
266 .child_default("b")
267 .capability(
268 CapabilityBuilder::storage()
269 .name("cache")
270 .backing_dir("data")
271 .source(StorageDirectorySource::Self_),
272 )
273 .build(),
274 ),
275 (
276 "b",
277 ComponentDeclBuilder::new()
278 .use_(UseBuilder::storage().name("cache").path("/storage"))
279 .build(),
280 ),
281 ];
282 let model = T::new("a", components).build().await;
283 model
284 .check_use(
285 ["b"].try_into().unwrap(),
286 CheckUse::Storage {
287 path: "/storage".parse().unwrap(),
288 storage_relation: None,
289 from_cm_namespace: false,
290 storage_subdir: None,
291 expected_res: ExpectedResult::Err(zx_status::Status::ACCESS_DENIED),
292 },
293 )
294 .await;
295 }
296
297 pub async fn test_storage_from_parent_dir_from_grandparent(&self) {
308 let components = vec![
309 (
310 "a",
311 ComponentDeclBuilder::new()
312 .capability(
313 CapabilityBuilder::directory()
314 .name("data")
315 .path("/data")
316 .rights(fio::RW_STAR_DIR),
317 )
318 .offer(
319 OfferBuilder::directory()
320 .name("data")
321 .target_name("minfs")
322 .source(OfferSource::Self_)
323 .target_static_child("b")
324 .rights(fio::RW_STAR_DIR),
325 )
326 .child_default("b")
327 .build(),
328 ),
329 (
330 "b",
331 ComponentDeclBuilder::new()
332 .offer(
333 OfferBuilder::storage()
334 .name("data")
335 .source(OfferSource::Self_)
336 .target_static_child("c"),
337 )
338 .child_default("c")
339 .capability(
340 CapabilityBuilder::storage()
341 .name("data")
342 .backing_dir("minfs")
343 .source(StorageDirectorySource::Parent),
344 )
345 .build(),
346 ),
347 (
348 "c",
349 ComponentDeclBuilder::new()
350 .use_(UseBuilder::storage().name("data").path("/storage"))
351 .build(),
352 ),
353 ];
354 let model = T::new("a", components).build().await;
355 model
356 .check_use(
357 ["b", "c"].try_into().unwrap(),
358 CheckUse::Storage {
359 path: "/storage".parse().unwrap(),
360 storage_relation: Some(Moniker::try_from(["c"]).unwrap()),
361 from_cm_namespace: false,
362 storage_subdir: None,
363 expected_res: ExpectedResult::Ok,
364 },
365 )
366 .await;
367 }
368
369 pub async fn test_storage_from_parent_dir_from_grandparent_with_subdirs(&self) {
381 let components = vec![
382 (
383 "a",
384 ComponentDeclBuilder::new()
385 .capability(
386 CapabilityBuilder::directory()
387 .name("data")
388 .path("/data")
389 .rights(fio::RW_STAR_DIR),
390 )
391 .offer(
392 OfferBuilder::directory()
393 .name("data")
394 .target_name("minfs")
395 .source(OfferSource::Self_)
396 .target_static_child("b")
397 .rights(fio::RW_STAR_DIR)
398 .subdir("subdir_1"),
399 )
400 .child_default("b")
401 .build(),
402 ),
403 (
404 "b",
405 ComponentDeclBuilder::new()
406 .offer(
407 OfferBuilder::storage()
408 .name("data")
409 .source(OfferSource::Self_)
410 .target_static_child("c"),
411 )
412 .child_default("c")
413 .capability(
414 CapabilityBuilder::storage()
415 .name("data")
416 .backing_dir("minfs")
417 .source(StorageDirectorySource::Parent)
418 .subdir("subdir_2"),
419 )
420 .build(),
421 ),
422 (
423 "c",
424 ComponentDeclBuilder::new()
425 .use_(UseBuilder::storage().name("data").path("/storage"))
426 .build(),
427 ),
428 ];
429 let model = T::new("a", components).build().await;
430 model.add_subdir_to_data_directory("subdir_1");
431 model
432 .check_use(
433 ["b", "c"].try_into().unwrap(),
434 CheckUse::Storage {
435 path: "/storage".parse().unwrap(),
436 storage_relation: Some(Moniker::try_from(["c"]).unwrap()),
437 from_cm_namespace: false,
438 storage_subdir: Some("subdir_1/subdir_2".to_string()),
439 expected_res: ExpectedResult::Ok,
440 },
441 )
442 .await;
443
444 model
445 .check_test_subdir_contents(".", vec!["foo".to_string(), "subdir_1".to_string()])
446 .await;
447 model.check_test_subdir_contents("subdir_1", vec!["subdir_2".to_string()]).await;
448 model.check_test_subdir_contents("subdir_1/subdir_2", vec!["c:0".to_string()]).await;
449 }
450
451 pub async fn test_storage_from_parent_dir_from_grandparent_with_subdir(&self) {
462 let components = vec![
463 (
464 "a",
465 ComponentDeclBuilder::new()
466 .capability(
467 CapabilityBuilder::directory()
468 .name("data")
469 .path("/data")
470 .rights(fio::RW_STAR_DIR)
471 .build(),
472 )
473 .offer(
474 OfferBuilder::directory()
475 .name("data")
476 .target_name("minfs")
477 .source(OfferSource::Self_)
478 .target_static_child("b")
479 .rights(fio::RW_STAR_DIR),
480 )
481 .child_default("b")
482 .build(),
483 ),
484 (
485 "b",
486 ComponentDeclBuilder::new()
487 .offer(
488 OfferBuilder::storage()
489 .name("data")
490 .source(OfferSource::Self_)
491 .target_static_child("c"),
492 )
493 .child_default("c")
494 .capability(
495 CapabilityBuilder::storage()
496 .name("data")
497 .backing_dir("minfs")
498 .source(StorageDirectorySource::Parent)
499 .subdir("bar"),
500 )
501 .build(),
502 ),
503 (
504 "c",
505 ComponentDeclBuilder::new()
506 .use_(UseBuilder::storage().name("data").path("/storage"))
507 .build(),
508 ),
509 ];
510 let model = T::new("a", components).build().await;
511 model
512 .check_use(
513 ["b", "c"].try_into().unwrap(),
514 CheckUse::Storage {
515 path: "/storage".parse().unwrap(),
516 storage_relation: Some(Moniker::try_from(["c"]).unwrap()),
517 from_cm_namespace: false,
518 storage_subdir: Some("bar".to_string()),
519 expected_res: ExpectedResult::Ok,
520 },
521 )
522 .await;
523 model.check_test_subdir_contents(".", vec!["bar".to_string(), "foo".to_string()]).await;
524 }
525
526 pub async fn test_storage_and_dir_from_grandparent(&self) {
537 let components = vec![
538 (
539 "a",
540 ComponentDeclBuilder::new()
541 .capability(
542 CapabilityBuilder::directory()
543 .name("data-root")
544 .path("/data")
545 .rights(fio::RW_STAR_DIR),
546 )
547 .offer(
548 OfferBuilder::storage()
549 .name("data")
550 .source(OfferSource::Self_)
551 .target_static_child("b"),
552 )
553 .child_default("b")
554 .capability(
555 CapabilityBuilder::storage()
556 .name("data")
557 .backing_dir("data-root")
558 .source(StorageDirectorySource::Self_),
559 )
560 .build(),
561 ),
562 (
563 "b",
564 ComponentDeclBuilder::new()
565 .offer(
566 OfferBuilder::storage()
567 .name("data")
568 .source(OfferSource::Parent)
569 .target_static_child("c"),
570 )
571 .child_default("c")
572 .build(),
573 ),
574 (
575 "c",
576 ComponentDeclBuilder::new()
577 .use_(UseBuilder::storage().name("data").path("/storage"))
578 .build(),
579 ),
580 ];
581 let model = T::new("a", components).build().await;
582 model
583 .check_use(
584 ["b", "c"].try_into().unwrap(),
585 CheckUse::Storage {
586 path: "/storage".parse().unwrap(),
587 storage_relation: Some(Moniker::try_from(["b", "c"]).unwrap()),
588 from_cm_namespace: false,
589 storage_subdir: None,
590 expected_res: ExpectedResult::Ok,
591 },
592 )
593 .await;
594 }
595
596 pub async fn test_storage_from_parent_dir_from_sibling(&self) {
605 let components = vec![
606 (
607 "a",
608 ComponentDeclBuilder::new()
609 .capability(
610 CapabilityBuilder::storage()
611 .name("cache")
612 .backing_dir("minfs")
613 .source(StorageDirectorySource::Child("b".into())),
614 )
615 .offer(
616 OfferBuilder::storage()
617 .name("cache")
618 .source(OfferSource::Self_)
619 .target_static_child("c"),
620 )
621 .child_default("b")
622 .child_default("c")
623 .build(),
624 ),
625 (
626 "b",
627 ComponentDeclBuilder::new()
628 .capability(
629 CapabilityBuilder::directory()
630 .name("data")
631 .path("/data")
632 .rights(fio::RW_STAR_DIR),
633 )
634 .expose(
635 ExposeBuilder::directory()
636 .name("data")
637 .source(ExposeSource::Self_)
638 .target_name("minfs")
639 .rights(fio::RW_STAR_DIR),
640 )
641 .build(),
642 ),
643 (
644 "c",
645 ComponentDeclBuilder::new()
646 .use_(UseBuilder::storage().name("cache").path("/storage"))
647 .build(),
648 ),
649 ];
650 let model = T::new("a", components).build().await;
651 model
652 .check_use(
653 ["c"].try_into().unwrap(),
654 CheckUse::Storage {
655 path: "/storage".parse().unwrap(),
656 storage_relation: Some(Moniker::try_from(["c"]).unwrap()),
657 from_cm_namespace: false,
658 storage_subdir: None,
659 expected_res: ExpectedResult::Ok,
660 },
661 )
662 .await;
663 }
664
665 pub async fn test_storage_from_parent_dir_from_sibling_with_subdir(&self) {
675 let components = vec![
676 (
677 "a",
678 ComponentDeclBuilder::new()
679 .capability(
680 CapabilityBuilder::storage()
681 .name("cache")
682 .backing_dir("minfs")
683 .source(StorageDirectorySource::Child("b".into()))
684 .subdir("subdir_2"),
685 )
686 .offer(
687 OfferBuilder::storage()
688 .name("cache")
689 .source(OfferSource::Self_)
690 .target_static_child("c"),
691 )
692 .child_default("b")
693 .child_default("c")
694 .build(),
695 ),
696 (
697 "b",
698 ComponentDeclBuilder::new()
699 .capability(
700 CapabilityBuilder::directory()
701 .name("data")
702 .path("/data")
703 .rights(fio::RW_STAR_DIR),
704 )
705 .expose(
706 ExposeBuilder::directory()
707 .name("data")
708 .source(ExposeSource::Self_)
709 .target_name("minfs")
710 .rights(fio::RW_STAR_DIR)
711 .subdir("subdir_1"),
712 )
713 .build(),
714 ),
715 (
716 "c",
717 ComponentDeclBuilder::new()
718 .use_(UseBuilder::storage().name("cache").path("/storage"))
719 .build(),
720 ),
721 ];
722 let model = T::new("a", components).build().await;
723 model.add_subdir_to_data_directory("subdir_1");
724 model
725 .check_use(
726 ["c"].try_into().unwrap(),
727 CheckUse::Storage {
728 path: "/storage".parse().unwrap(),
729 storage_relation: Some(Moniker::try_from(["c"]).unwrap()),
730 from_cm_namespace: false,
731 storage_subdir: Some("subdir_1/subdir_2".to_string()),
732 expected_res: ExpectedResult::Ok,
733 },
734 )
735 .await;
736 model
737 .check_test_subdir_contents(".", vec!["foo".to_string(), "subdir_1".to_string()])
738 .await;
739 model.check_test_subdir_contents("subdir_1", vec!["subdir_2".to_string()]).await;
740 model.check_test_subdir_contents("subdir_1/subdir_2", vec!["c:0".to_string()]).await;
741 }
742
743 pub async fn test_storage_multiple_types(&self) {
756 let components = vec![
757 (
758 "a",
759 ComponentDeclBuilder::new()
760 .capability(
761 CapabilityBuilder::storage()
762 .name("data")
763 .backing_dir("minfs")
764 .source(StorageDirectorySource::Child("b".into()))
765 .subdir("data"),
766 )
767 .capability(
768 CapabilityBuilder::storage()
769 .name("cache")
770 .backing_dir("minfs")
771 .source(StorageDirectorySource::Child("b".into()))
772 .subdir("cache"),
773 )
774 .offer(
775 OfferBuilder::storage()
776 .name("cache")
777 .source(OfferSource::Self_)
778 .target_static_child("c"),
779 )
780 .offer(
781 OfferBuilder::storage()
782 .name("data")
783 .source(OfferSource::Self_)
784 .target_static_child("c"),
785 )
786 .child_default("b")
787 .child_default("c")
788 .build(),
789 ),
790 (
791 "b",
792 ComponentDeclBuilder::new()
793 .capability(
794 CapabilityBuilder::directory()
795 .name("data")
796 .path("/data")
797 .rights(fio::RW_STAR_DIR),
798 )
799 .expose(
800 ExposeBuilder::directory()
801 .name("data")
802 .source(ExposeSource::Self_)
803 .target_name("minfs")
804 .rights(fio::RW_STAR_DIR),
805 )
806 .build(),
807 ),
808 (
809 "c",
810 ComponentDeclBuilder::new()
811 .offer(
812 OfferBuilder::storage()
813 .name("data")
814 .source(OfferSource::Parent)
815 .target_static_child("d"),
816 )
817 .offer(
818 OfferBuilder::storage()
819 .name("cache")
820 .source(OfferSource::Parent)
821 .target_static_child("d"),
822 )
823 .use_(UseBuilder::storage().name("data").path("/storage"))
824 .use_(UseBuilder::storage().name("cache").path("/cache"))
825 .child_default("d")
826 .build(),
827 ),
828 (
829 "d",
830 ComponentDeclBuilder::new()
831 .use_(UseBuilder::storage().name("data").path("/storage"))
832 .use_(UseBuilder::storage().name("cache").path("/cache"))
833 .build(),
834 ),
835 ];
836 let model = T::new("a", components).build().await;
837 model
838 .check_use(
839 ["c"].try_into().unwrap(),
840 CheckUse::Storage {
841 path: "/storage".parse().unwrap(),
842 storage_relation: Some(Moniker::try_from(["c"]).unwrap()),
843 from_cm_namespace: false,
844 storage_subdir: Some("data".to_string()),
845 expected_res: ExpectedResult::Ok,
846 },
847 )
848 .await;
849 model
850 .check_use(
851 ["c"].try_into().unwrap(),
852 CheckUse::Storage {
853 path: "/cache".parse().unwrap(),
854 storage_relation: Some(Moniker::try_from(["c"]).unwrap()),
855 from_cm_namespace: false,
856 storage_subdir: Some("cache".to_string()),
857 expected_res: ExpectedResult::Ok,
858 },
859 )
860 .await;
861 model
862 .check_use(
863 ["c", "d"].try_into().unwrap(),
864 CheckUse::Storage {
865 path: "/storage".parse().unwrap(),
866 storage_relation: Some(Moniker::try_from(["c", "d"]).unwrap()),
867 from_cm_namespace: false,
868 storage_subdir: Some("data".to_string()),
869 expected_res: ExpectedResult::Ok,
870 },
871 )
872 .await;
873 model
874 .check_use(
875 ["c", "d"].try_into().unwrap(),
876 CheckUse::Storage {
877 path: "/cache".parse().unwrap(),
878 storage_relation: Some(Moniker::try_from(["c", "d"]).unwrap()),
879 from_cm_namespace: false,
880 storage_subdir: Some("cache".to_string()),
881 expected_res: ExpectedResult::Ok,
882 },
883 )
884 .await;
885 }
886
887 pub async fn test_use_the_wrong_type_of_storage(&self) {
896 let components = vec![
897 (
898 "a",
899 ComponentDeclBuilder::new()
900 .capability(
901 CapabilityBuilder::directory()
902 .name("data")
903 .path("/data")
904 .rights(fio::RW_STAR_DIR),
905 )
906 .offer(
907 OfferBuilder::storage()
908 .name("cache")
909 .source(OfferSource::Self_)
910 .target_static_child("b"),
911 )
912 .child_default("b")
913 .capability(
914 CapabilityBuilder::storage()
915 .name("cache")
916 .backing_dir("minfs")
917 .source(StorageDirectorySource::Self_),
918 )
919 .build(),
920 ),
921 (
922 "b",
923 ComponentDeclBuilder::new()
924 .use_(UseBuilder::storage().name("data").path("/storage"))
925 .build(),
926 ),
927 ];
928 let model = T::new("a", components).build().await;
929 model
930 .check_use(
931 ["b"].try_into().unwrap(),
932 CheckUse::Storage {
933 path: "/storage".parse().unwrap(),
934 storage_relation: None,
935 from_cm_namespace: false,
936 storage_subdir: None,
937 expected_res: ExpectedResult::Err(zx_status::Status::NOT_FOUND),
938 },
939 )
940 .await;
941 }
942
943 pub async fn test_directories_are_not_storage(&self) {
950 let components = vec![
951 (
952 "a",
953 ComponentDeclBuilder::new()
954 .capability(
955 CapabilityBuilder::directory()
956 .name("data")
957 .path("/data")
958 .rights(fio::RW_STAR_DIR),
959 )
960 .offer(
961 OfferBuilder::directory()
962 .name("data")
963 .source(OfferSource::Self_)
964 .target_static_child("b")
965 .rights(fio::RW_STAR_DIR),
966 )
967 .child_default("b")
968 .build(),
969 ),
970 (
971 "b",
972 ComponentDeclBuilder::new()
973 .use_(UseBuilder::storage().name("data").path("/storage"))
974 .build(),
975 ),
976 ];
977 let model = T::new("a", components).build().await;
978 model
979 .check_use(
980 ["b"].try_into().unwrap(),
981 CheckUse::Storage {
982 path: "/storage".parse().unwrap(),
983 storage_relation: None,
984 from_cm_namespace: false,
985 storage_subdir: None,
986 expected_res: ExpectedResult::Err(zx_status::Status::NOT_FOUND),
987 },
988 )
989 .await;
990 }
991
992 pub async fn test_use_storage_when_not_offered(&self) {
1000 let components = vec![
1001 (
1002 "a",
1003 ComponentDeclBuilder::new()
1004 .child_default("b")
1005 .capability(
1006 CapabilityBuilder::directory()
1007 .name("minfs")
1008 .path("/data")
1009 .rights(fio::RW_STAR_DIR),
1010 )
1011 .capability(
1012 CapabilityBuilder::storage()
1013 .name("data")
1014 .backing_dir("minfs")
1015 .source(StorageDirectorySource::Self_),
1016 )
1017 .build(),
1018 ),
1019 (
1020 "b",
1021 ComponentDeclBuilder::new()
1022 .use_(UseBuilder::storage().name("data").path("/storage"))
1023 .build(),
1024 ),
1025 ];
1026 let model = T::new("a", components).build().await;
1027 model
1028 .check_use(
1029 ["b"].try_into().unwrap(),
1030 CheckUse::Storage {
1031 path: "/storage".parse().unwrap(),
1032 storage_relation: None,
1033 from_cm_namespace: false,
1034 storage_subdir: None,
1035 expected_res: ExpectedResult::Err(zx_status::Status::NOT_FOUND),
1036 },
1037 )
1038 .await;
1039 }
1040
1041 pub async fn test_dir_offered_from_nonexecutable(&self) {
1052 let components = vec![
1053 (
1054 "a",
1055 ComponentDeclBuilder::new_empty_component()
1056 .capability(
1057 CapabilityBuilder::directory()
1058 .name("data")
1059 .path("/data")
1060 .rights(fio::RW_STAR_DIR),
1061 )
1062 .offer(
1063 OfferBuilder::directory()
1064 .name("data")
1065 .target_name("minfs")
1066 .source(OfferSource::Self_)
1067 .target_static_child("b")
1068 .rights(fio::RW_STAR_DIR),
1069 )
1070 .child_default("b")
1071 .build(),
1072 ),
1073 (
1074 "b",
1075 ComponentDeclBuilder::new()
1076 .offer(
1077 OfferBuilder::storage()
1078 .name("data")
1079 .source(OfferSource::Self_)
1080 .target_static_child("c"),
1081 )
1082 .child_default("c")
1083 .capability(
1084 CapabilityBuilder::storage()
1085 .name("data")
1086 .backing_dir("minfs")
1087 .source(StorageDirectorySource::Parent),
1088 )
1089 .build(),
1090 ),
1091 (
1092 "c",
1093 ComponentDeclBuilder::new()
1094 .use_(UseBuilder::storage().name("data").path("/storage"))
1095 .build(),
1096 ),
1097 ];
1098 let model = T::new("a", components).build().await;
1099 model
1100 .check_use(
1101 ["b", "c"].try_into().unwrap(),
1102 CheckUse::Storage {
1103 path: "/storage".parse().unwrap(),
1104 storage_relation: None,
1105 from_cm_namespace: false,
1106 storage_subdir: None,
1107 expected_res: ExpectedResult::Err(zx_status::Status::NOT_FOUND),
1108 },
1109 )
1110 .await;
1111 }
1112
1113 pub async fn test_storage_dir_from_cm_namespace_prevented_by_policy(&self) {
1124 let components = vec![
1125 (
1126 "a",
1127 ComponentDeclBuilder::new()
1128 .offer(
1129 OfferBuilder::storage()
1130 .name("cache")
1131 .source(OfferSource::Self_)
1132 .target_static_child("b"),
1133 )
1134 .child_default("b")
1135 .capability(
1136 CapabilityBuilder::storage()
1137 .name("cache")
1138 .backing_dir("tmp")
1139 .source(StorageDirectorySource::Parent)
1140 .subdir("cache"),
1141 )
1142 .build(),
1143 ),
1144 (
1145 "b",
1146 ComponentDeclBuilder::new()
1147 .use_(UseBuilder::storage().name("cache").path("/storage"))
1148 .build(),
1149 ),
1150 ];
1151 let namespace_capabilities = vec![CapabilityBuilder::directory()
1152 .name("tmp")
1153 .path("/tmp")
1154 .rights(fio::RW_STAR_DIR)
1155 .build()];
1156 let mut builder = T::new("a", components);
1157 builder.set_namespace_capabilities(namespace_capabilities);
1158 builder.add_capability_policy(
1159 CapabilityAllowlistKey {
1160 source_moniker: ExtendedMoniker::ComponentInstance(Moniker::root()),
1161 source_name: "cache".parse().unwrap(),
1162 source: CapabilityAllowlistSource::Self_,
1163 capability: CapabilityTypeName::Storage,
1164 },
1165 HashSet::new(),
1166 );
1167 let model = builder.build().await;
1168
1169 model
1170 .check_use(
1171 ["b"].try_into().unwrap(),
1172 CheckUse::Storage {
1173 path: "/storage".parse().unwrap(),
1174 storage_relation: Some(Moniker::try_from(["b"]).unwrap()),
1175 from_cm_namespace: true,
1176 storage_subdir: Some("cache".to_string()),
1177 expected_res: ExpectedResult::Err(zx_status::Status::ACCESS_DENIED),
1178 },
1179 )
1180 .await;
1181 }
1182
1183 pub async fn test_instance_id_from_index(&self) {
1194 let b_instance_id = InstanceId::new_random(&mut rand::rng());
1195 let component_id_index = {
1196 let mut index = component_id_index::Index::default();
1197 index.insert(Moniker::parse_str("/b").unwrap(), b_instance_id.clone()).unwrap();
1198 index
1199 };
1200 let component_id_index_path = make_index_file(component_id_index).unwrap();
1201 let components = vec![
1202 (
1203 "a",
1204 ComponentDeclBuilder::new()
1205 .capability(
1206 CapabilityBuilder::directory()
1207 .name("data")
1208 .path("/data")
1209 .rights(fio::RW_STAR_DIR),
1210 )
1211 .offer(
1212 OfferBuilder::storage()
1213 .name("cache")
1214 .source(OfferSource::Self_)
1215 .target_static_child("b"),
1216 )
1217 .child_default("b")
1218 .capability(
1219 CapabilityBuilder::storage()
1220 .name("cache")
1221 .backing_dir("data")
1222 .source(StorageDirectorySource::Self_),
1223 )
1224 .build(),
1225 ),
1226 (
1227 "b",
1228 ComponentDeclBuilder::new()
1229 .use_(UseBuilder::storage().name("cache").path("/storage"))
1230 .offer(
1231 OfferBuilder::storage()
1232 .name("cache")
1233 .source(OfferSource::Parent)
1234 .target_static_child("c"),
1235 )
1236 .child_default("c")
1237 .build(),
1238 ),
1239 (
1240 "c",
1241 ComponentDeclBuilder::new()
1242 .use_(UseBuilder::storage().name("cache").path("/storage"))
1243 .build(),
1244 ),
1245 ];
1246 let mut builder = T::new("a", components);
1247 builder.set_component_id_index_path(
1248 component_id_index_path.path().to_owned().try_into().unwrap(),
1249 );
1250 let model = builder.build().await;
1251
1252 model
1254 .check_use(
1255 ["b"].try_into().unwrap(),
1256 CheckUse::Storage {
1257 path: "/storage".parse().unwrap(),
1258 storage_relation: Some(Moniker::try_from(["b"]).unwrap()),
1259 from_cm_namespace: false,
1260 storage_subdir: None,
1261 expected_res: ExpectedResult::Ok,
1262 },
1263 )
1264 .await;
1265 model.check_test_subdir_contains(".", b_instance_id.to_string()).await;
1266
1267 let storage_relation = Moniker::try_from(["b", "c"]).unwrap();
1269 model
1270 .check_use(
1271 ["b", "c"].try_into().unwrap(),
1272 CheckUse::Storage {
1273 path: "/storage".parse().unwrap(),
1274 storage_relation: Some(storage_relation.clone()),
1275 from_cm_namespace: false,
1276 storage_subdir: None,
1277 expected_res: ExpectedResult::Ok,
1278 },
1279 )
1280 .await;
1281
1282 let expected_storage_path =
1283 generate_storage_path(None, &storage_relation, None).to_str().unwrap().to_string();
1284 model.check_test_dir_tree_contains(expected_storage_path).await;
1285 }
1286}