1use crate::{CheckUse, ExpectedResult, RoutingTestModel, RoutingTestModelBuilder};
6use cm_rust::*;
7use cm_rust_testing::*;
8use fidl_fuchsia_io as fio;
9use moniker::Moniker;
10use std::marker::PhantomData;
11use zx_status::Status;
12
13pub struct CommonStorageAdminTest<T: RoutingTestModelBuilder> {
14 builder: PhantomData<T>,
15}
16
17impl<T: RoutingTestModelBuilder> CommonStorageAdminTest<T> {
18 pub fn new() -> Self {
19 Self { builder: PhantomData }
20 }
21
22 pub async fn test_storage_to_one_child_admin_to_another(&self) {
32 let components = vec![
33 (
34 "a",
35 ComponentDeclBuilder::new()
36 .capability(
37 CapabilityBuilder::directory()
38 .name("tmpfs")
39 .path("/data")
40 .rights(fio::RW_STAR_DIR),
41 )
42 .capability(
43 CapabilityBuilder::storage()
44 .name("data")
45 .backing_dir("tmpfs")
46 .source(StorageDirectorySource::Self_),
47 )
48 .offer(
49 OfferBuilder::storage()
50 .name("data")
51 .source(OfferSource::Self_)
52 .target_static_child("b"),
53 )
54 .offer(
55 OfferBuilder::protocol()
56 .name("fuchsia.sys2.StorageAdmin")
57 .source(OfferSource::Capability("data".parse().unwrap()))
58 .target_static_child("c"),
59 )
60 .child_default("b")
61 .child_default("c")
62 .build(),
63 ),
64 (
65 "b",
66 ComponentDeclBuilder::new()
67 .use_(UseBuilder::storage().name("data").path("/storage"))
68 .build(),
69 ),
70 (
71 "c",
72 ComponentDeclBuilder::new()
73 .use_(UseBuilder::protocol().name("fuchsia.sys2.StorageAdmin"))
74 .build(),
75 ),
76 ];
77 let model = T::new("a", components).build().await;
78 model
79 .check_use(
80 vec!["c"].try_into().unwrap(),
81 CheckUse::StorageAdmin {
82 storage_relation: Moniker::try_from(vec!["b"]).unwrap(),
83 storage_subdir: None,
84 expected_res: ExpectedResult::Ok,
85 },
86 )
87 .await;
88 }
89
90 pub async fn test_directory_from_grandparent_storage_and_admin_from_parent(&self) {
102 let components = vec![
103 (
104 "a",
105 ComponentDeclBuilder::new()
106 .capability(
107 CapabilityBuilder::directory()
108 .name("data")
109 .path("/data")
110 .rights(fio::RW_STAR_DIR),
111 )
112 .offer(
113 OfferBuilder::directory()
114 .name("data")
115 .source(OfferSource::Self_)
116 .target_static_child("b")
117 .rights(fio::RW_STAR_DIR)
118 .subdir("foo"),
119 )
120 .child_default("b")
121 .build(),
122 ),
123 (
124 "b",
125 ComponentDeclBuilder::new()
126 .capability(
127 CapabilityBuilder::storage()
128 .name("storage")
129 .backing_dir("data")
130 .source(StorageDirectorySource::Parent)
131 .subdir("bar"),
132 )
133 .offer(
134 OfferBuilder::protocol()
135 .name("fuchsia.sys2.StorageAdmin")
136 .source(OfferSource::Capability("storage".parse().unwrap()))
137 .target_static_child("c"),
138 )
139 .child_default("c")
140 .build(),
141 ),
142 (
143 "c",
144 ComponentDeclBuilder::new()
145 .use_(UseBuilder::protocol().name("fuchsia.sys2.StorageAdmin"))
146 .build(),
147 ),
148 ];
149 let model = T::new("a", components).build().await;
150 model
151 .check_use(
152 vec!["b", "c"].try_into().unwrap(),
153 CheckUse::StorageAdmin {
154 storage_relation: Moniker::try_from(vec!["c"]).unwrap(),
155 storage_subdir: Some("foo/bar".to_string()),
156 expected_res: ExpectedResult::Ok,
157 },
158 )
159 .await;
160 }
161
162 pub async fn test_storage_admin_from_sibling(&self) {
175 let components = vec![
176 (
177 "a",
178 ComponentDeclBuilder::new()
179 .offer(
180 OfferBuilder::protocol()
181 .name("fuchsia.sys2.StorageAdmin")
182 .source_static_child("c")
183 .target_static_child("b"),
184 )
185 .child_default("b")
186 .child_default("c")
187 .build(),
188 ),
189 (
190 "b",
191 ComponentDeclBuilder::new()
192 .use_(UseBuilder::protocol().name("fuchsia.sys2.StorageAdmin"))
193 .build(),
194 ),
195 (
196 "c",
197 ComponentDeclBuilder::new()
198 .capability(
199 CapabilityBuilder::directory()
200 .name("tmpfs")
201 .path("/data")
202 .rights(fio::RW_STAR_DIR),
203 )
204 .capability(
205 CapabilityBuilder::storage()
206 .name("data")
207 .backing_dir("tmpfs")
208 .source(StorageDirectorySource::Self_),
209 )
210 .offer(
211 OfferBuilder::storage()
212 .name("data")
213 .source(OfferSource::Self_)
214 .target_static_child("d"),
215 )
216 .expose(
217 ExposeBuilder::protocol()
218 .name("fuchsia.sys2.StorageAdmin")
219 .source(ExposeSource::Capability("data".parse().unwrap())),
220 )
221 .child_default("d")
222 .build(),
223 ),
224 (
225 "d",
226 ComponentDeclBuilder::new()
227 .use_(UseBuilder::storage().name("data").path("/storage"))
228 .build(),
229 ),
230 ];
231 let test = T::new("a", components).build().await;
232 test.check_use(
233 vec!["b"].try_into().unwrap(),
234 CheckUse::StorageAdmin {
235 storage_relation: Moniker::try_from(vec!["d"]).unwrap(),
236 storage_subdir: None,
237 expected_res: ExpectedResult::Ok,
238 },
239 )
240 .await;
241 }
242
243 pub async fn test_admin_protocol_used_in_the_same_place_storage_is_declared(&self) {
253 let components = vec![
254 (
255 "a",
256 ComponentDeclBuilder::new()
257 .capability(
258 CapabilityBuilder::storage()
259 .name("data")
260 .backing_dir("tmpfs")
261 .source(StorageDirectorySource::Child("c".to_string())),
262 )
263 .offer(
264 OfferBuilder::storage()
265 .name("data")
266 .source(OfferSource::Self_)
267 .target_static_child("b"),
268 )
269 .use_(
270 UseBuilder::protocol()
271 .source(UseSource::Capability("data".parse().unwrap()))
272 .name("fuchsia.sys2.StorageAdmin"),
273 )
274 .child_default("b")
275 .child_default("c")
276 .build(),
277 ),
278 (
279 "b",
280 ComponentDeclBuilder::new()
281 .use_(UseBuilder::storage().name("data").path("/storage"))
282 .build(),
283 ),
284 (
285 "c",
286 ComponentDeclBuilder::new()
287 .capability(
288 CapabilityBuilder::directory()
289 .name("tmpfs")
290 .path("/data")
291 .rights(fio::RW_STAR_DIR),
292 )
293 .expose(ExposeBuilder::directory().name("tmpfs").source(ExposeSource::Self_))
294 .build(),
295 ),
296 ];
297 let model = T::new("a", components).build().await;
298 model
299 .check_use(
300 Moniker::root(),
301 CheckUse::StorageAdmin {
302 storage_relation: Moniker::try_from(vec!["b"]).unwrap(),
303 storage_subdir: None,
304 expected_res: ExpectedResult::Ok,
305 },
306 )
307 .await;
308 }
309
310 pub async fn test_storage_admin_from_protocol_on_self(&self) {
320 let components = vec![
321 (
322 "a",
323 ComponentDeclBuilder::new()
324 .capability(
325 CapabilityBuilder::directory()
326 .name("tmpfs")
327 .path("/data")
328 .rights(fio::RW_STAR_DIR),
329 )
330 .capability(
331 CapabilityBuilder::protocol().name("unrelated.protocol").path("/svc/foo"),
332 )
333 .capability(
334 CapabilityBuilder::storage()
335 .name("data")
336 .backing_dir("tmpfs")
337 .source(StorageDirectorySource::Self_),
338 )
339 .offer(
340 OfferBuilder::storage()
341 .name("data")
342 .source(OfferSource::Self_)
343 .target_static_child("b"),
344 )
345 .use_(
346 UseBuilder::protocol()
347 .source(UseSource::Capability("unrelated.protocol".parse().unwrap()))
348 .name("fuchsia.sys2.StorageAdmin"),
349 )
350 .child_default("b")
351 .build(),
352 ),
353 (
354 "b",
355 ComponentDeclBuilder::new()
356 .use_(UseBuilder::storage().name("data").path("/storage"))
357 .build(),
358 ),
359 ];
360 let model = T::new("a", components).build().await;
361 model
362 .check_use(
363 Moniker::root(),
364 CheckUse::StorageAdmin {
365 storage_relation: Moniker::try_from(vec!["b"]).unwrap(),
366 storage_subdir: None,
367 expected_res: ExpectedResult::Err(Status::NOT_FOUND),
368 },
369 )
370 .await;
371 }
372
373 pub async fn test_storage_admin_from_protocol_from_parent(&self) {
382 let components = vec![
383 (
384 "a",
385 ComponentDeclBuilder::new()
386 .capability(
387 CapabilityBuilder::directory()
388 .name("tmpfs")
389 .path("/data")
390 .rights(fio::RW_STAR_DIR),
391 )
392 .capability(
393 CapabilityBuilder::protocol().name("unrelated.protocol").path("/svc/foo"),
394 )
395 .capability(
396 CapabilityBuilder::storage()
397 .name("data")
398 .backing_dir("tmpfs")
399 .source(StorageDirectorySource::Self_),
400 )
401 .offer(
402 OfferBuilder::protocol()
403 .name("fuchsia.sys2.StorageAdmin")
404 .source(OfferSource::Capability("unrelated.protocol".parse().unwrap()))
405 .target_static_child("b"),
406 )
407 .child_default("b")
408 .build(),
409 ),
410 (
411 "b",
412 ComponentDeclBuilder::new()
413 .use_(UseBuilder::protocol().name("fuchsia.sys2.StorageAdmin"))
414 .build(),
415 ),
416 ];
417 let model = T::new("a", components).build().await;
418 model
419 .check_use(
420 vec!["b"].try_into().unwrap(),
421 CheckUse::StorageAdmin {
422 storage_relation: Moniker::try_from(vec!["b"]).unwrap(),
423 storage_subdir: None,
424 expected_res: ExpectedResult::Err(Status::NOT_FOUND),
425 },
426 )
427 .await;
428 }
429
430 pub async fn test_storage_admin_from_protocol_on_sibling(&self) {
444 let components = vec![
445 (
446 "a",
447 ComponentDeclBuilder::new()
448 .offer(
449 OfferBuilder::protocol()
450 .name("fuchsia.sys2.StorageAdmin")
451 .source_static_child("c")
452 .target_static_child("b"),
453 )
454 .child_default("b")
455 .child_default("c")
456 .build(),
457 ),
458 (
459 "b",
460 ComponentDeclBuilder::new()
461 .use_(UseBuilder::protocol().name("fuchsia.sys2.StorageAdmin"))
462 .build(),
463 ),
464 (
465 "c",
466 ComponentDeclBuilder::new()
467 .capability(
468 CapabilityBuilder::directory()
469 .name("tmpfs")
470 .path("/data")
471 .rights(fio::RW_STAR_DIR),
472 )
473 .capability(
474 CapabilityBuilder::storage()
475 .name("data")
476 .backing_dir("tmpfs")
477 .source(StorageDirectorySource::Self_),
478 )
479 .capability(
480 CapabilityBuilder::protocol().name("unrelated.protocol").path("/svc/foo"),
481 )
482 .offer(
483 OfferBuilder::storage()
484 .name("data")
485 .source(OfferSource::Self_)
486 .target_static_child("d"),
487 )
488 .expose(
489 ExposeBuilder::protocol().name("fuchsia.sys2.StorageAdmin").source(
490 ExposeSource::Capability("unrelated.protocol".parse().unwrap()),
491 ),
492 )
493 .child_default("d")
494 .build(),
495 ),
496 (
497 "d",
498 ComponentDeclBuilder::new()
499 .use_(UseBuilder::storage().name("data").path("/storage"))
500 .build(),
501 ),
502 ];
503 let model = T::new("a", components).build().await;
504 model
505 .check_use(
506 vec!["b"].try_into().unwrap(),
507 CheckUse::StorageAdmin {
508 storage_relation: Moniker::try_from(vec!["d"]).unwrap(),
509 storage_subdir: None,
510 expected_res: ExpectedResult::Err(Status::NOT_FOUND),
511 },
512 )
513 .await;
514 }
515
516 pub async fn test_storage_admin_from_storage_on_self_bad_protocol_name(&self) {
525 let components = vec![
526 (
527 "a",
528 ComponentDeclBuilder::new()
529 .capability(
530 CapabilityBuilder::directory()
531 .name("tmpfs")
532 .path("/data")
533 .rights(fio::RW_STAR_DIR),
534 )
535 .capability(
536 CapabilityBuilder::protocol().name("unrelated.protocol").path("/svc/foo"),
537 )
538 .capability(
539 CapabilityBuilder::storage()
540 .name("data")
541 .backing_dir("tmpfs")
542 .source(StorageDirectorySource::Self_),
543 )
544 .offer(
545 OfferBuilder::storage()
546 .name("data")
547 .source(OfferSource::Self_)
548 .target_static_child("b"),
549 )
550 .use_(
551 UseBuilder::protocol()
552 .source(UseSource::Capability("unrelated.protocol".parse().unwrap()))
553 .name("unrelated.protocol")
554 .path("/svc/fuchsia.sys2.StorageAdmin"),
555 )
556 .child_default("b")
557 .build(),
558 ),
559 (
560 "b",
561 ComponentDeclBuilder::new()
562 .use_(UseBuilder::storage().name("data").path("/storage"))
563 .build(),
564 ),
565 ];
566 let model = T::new("a", components).build().await;
567 model
568 .check_use(
569 Moniker::root(),
570 CheckUse::StorageAdmin {
571 storage_relation: Moniker::try_from(vec!["b"]).unwrap(),
572 storage_subdir: None,
573 expected_res: ExpectedResult::Err(Status::NOT_FOUND),
574 },
575 )
576 .await;
577 }
578
579 pub async fn test_storage_admin_from_storage_on_parent_bad_protocol_name(&self) {
587 let components = vec![
588 (
589 "a",
590 ComponentDeclBuilder::new()
591 .capability(
592 CapabilityBuilder::directory()
593 .name("tmpfs")
594 .path("/data")
595 .rights(fio::RW_STAR_DIR),
596 )
597 .capability(
598 CapabilityBuilder::storage()
599 .name("data")
600 .backing_dir("tmpfs")
601 .source(StorageDirectorySource::Self_),
602 )
603 .offer(
604 OfferBuilder::protocol()
605 .name("unrelated.protocol")
606 .target_name("fuchsia.sys2.StorageAdmin")
607 .source(OfferSource::Capability("data".parse().unwrap()))
608 .target_static_child("b"),
609 )
610 .child_default("b")
611 .build(),
612 ),
613 (
614 "b",
615 ComponentDeclBuilder::new()
616 .use_(UseBuilder::protocol().name("fuchsia.sys2.StorageAdmin"))
617 .build(),
618 ),
619 ];
620 let model = T::new("a", components).build().await;
621 model
622 .check_use(
623 vec!["b"].try_into().unwrap(),
624 CheckUse::StorageAdmin {
625 storage_relation: Moniker::try_from(vec!["b"]).unwrap(),
626 storage_subdir: None,
627 expected_res: ExpectedResult::Err(Status::NOT_FOUND),
628 },
629 )
630 .await;
631 }
632
633 pub async fn test_storage_admin_from_protocol_on_sibling_bad_protocol_name(&self) {
646 let components = vec![
647 (
648 "a",
649 ComponentDeclBuilder::new()
650 .offer(
651 OfferBuilder::protocol()
652 .name("fuchsia.sys2.StorageAdmin")
653 .source_static_child("c")
654 .target_static_child("b"),
655 )
656 .child_default("b")
657 .child_default("c")
658 .build(),
659 ),
660 (
661 "b",
662 ComponentDeclBuilder::new()
663 .use_(UseBuilder::protocol().name("fuchsia.sys2.StorageAdmin"))
664 .build(),
665 ),
666 (
667 "c",
668 ComponentDeclBuilder::new()
669 .capability(
670 CapabilityBuilder::directory()
671 .name("tmpfs")
672 .path("/data")
673 .rights(fio::RW_STAR_DIR),
674 )
675 .capability(
676 CapabilityBuilder::storage()
677 .name("data")
678 .backing_dir("tmpfs")
679 .source(StorageDirectorySource::Self_),
680 )
681 .offer(
682 OfferBuilder::storage()
683 .name("data")
684 .source(OfferSource::Self_)
685 .target_static_child("d"),
686 )
687 .expose(
688 ExposeBuilder::protocol()
689 .name("unrelated.protocol")
690 .target_name("fuchsia.sys2.StorageAdmin")
691 .source(ExposeSource::Capability("data".parse().unwrap())),
692 )
693 .child_default("d")
694 .build(),
695 ),
696 (
697 "d",
698 ComponentDeclBuilder::new()
699 .use_(UseBuilder::storage().name("data").path("/storage"))
700 .build(),
701 ),
702 ];
703 let model = T::new("a", components).build().await;
704 model
705 .check_use(
706 vec!["b"].try_into().unwrap(),
707 CheckUse::StorageAdmin {
708 storage_relation: Moniker::try_from(vec!["d"]).unwrap(),
709 storage_subdir: None,
710 expected_res: ExpectedResult::Err(Status::NOT_FOUND),
711 },
712 )
713 .await;
714 }
715}