Skip to main content

routing_test_helpers/
storage_admin.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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    ///    a
24    ///   / \
25    ///  b   c
26    ///
27    /// a: has storage decl with name "data" with a source of self at path /data
28    /// a: offers data storage to b
29    /// a: offers a storage admin protocol to c from the "data" storage capability
30    /// b: uses data storage as /storage.
31    /// c: uses the storage admin protocol to access b's storage
32    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    ///    a
92    ///    |
93    ///    b
94    ///    |
95    ///    c
96    ///
97    /// a: has directory decl with name "data" with a source of self at path /data subdir "foo"
98    /// a: offers data to b
99    /// b: has storage decl with name "storage" based on "data" from parent subdir "bar"
100    /// b: offers a storage admin protocol to c from the "storage" storage capability
101    /// c: uses the storage admin protocol to access its own storage
102    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    ///    a
164    ///   / \
165    ///  b   c
166    ///      |
167    ///      d
168    ///
169    /// c: has storage decl with name "data" with a source of self at path /data
170    /// c: has storage admin protocol from the "data" storage admin capability
171    /// c: offers data storage to d
172    /// d: uses data storage
173    /// a: offers storage admin protocol from c to b
174    /// b: uses the storage admin protocol
175    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    ///   a
245    ///  / \
246    ///  b c
247    ///
248    /// a: has storage decl with name "data" with a source of c's exposed "tmpfs" directory
249    /// a: offers data storage to b
250    /// a: uses a storage admin protocol from #data
251    /// b: uses data storage as /storage.
252    /// c: exposes directory "tmpfs" from self at path /data
253    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    ///    a
312    ///    |
313    ///    b
314    ///
315    /// a: has storage decl with name "data" with a source of self at path /data
316    /// a: declares a protocol "unrelated.protocol"
317    /// a: offers data storage to b
318    /// a: uses a storage admin protocol from "unrelated.protocol"
319    /// b: uses data storage as /storage.
320    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    ///    a
375    ///    |
376    ///    b
377    ///
378    /// a: has storage decl with name "data" with a source of self at path /data
379    /// a: declares a protocol "unrelated.protocol"
380    /// a: offers a storage admin protocol from "unrelated.protocol" to b
381    /// b: uses storage admin protocol
382    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    ///    a
432    ///   / \
433    ///  b   c
434    ///      |
435    ///      d
436    ///
437    /// c: has storage decl with name "data" with a source of self at path /data
438    /// c: has protocol decl with name "unrelated.protocol"
439    /// c: has storage admin protocol from the "unrelated.protocol" capability
440    /// c: offers data storage to d
441    /// d: uses data storage
442    /// a: offers storage admin protocol from c to b
443    /// b: uses the storage admin protocol
444    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    ///    a
518    ///    |
519    ///    b
520    ///
521    /// a: has storage decl with name "data" with a source of self at path /data
522    /// a: offers data storage to b
523    /// a: uses a "unrelated.protocol" protocol from "data"
524    /// b: uses data storage as /storage.
525    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    ///    a
581    ///    |
582    ///    b
583    ///
584    /// a: has storage decl with name "data" with a source of self at path /data
585    /// a: offers a storage admin protocol from "data" to b with a source name of "unrelated.protocol"
586    /// b: uses storage admin protocol
587    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    ///    a
635    ///   / \
636    ///  b   c
637    ///      |
638    ///      d
639    ///
640    /// c: has storage decl with name "data" with a source of self at path /data
641    /// c: exposes storage admin protocol from "data" with a source name of "unrelated.protocol"
642    /// c: offers data storage to d
643    /// d: uses data storage
644    /// a: offers storage admin protocol from c to b
645    /// b: uses the storage admin protocol
646    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}