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