Skip to main content

routing_test_helpers/
dictionary.rs

1// Copyright 2025 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::*;
7use cm_rust_testing::*;
8use fidl_fuchsia_io as fio;
9use moniker::Moniker;
10use std::marker::PhantomData;
11use std::path::PathBuf;
12use zx_status::Status;
13
14pub struct CommonDictionaryTest<T: RoutingTestModelBuilder> {
15    builder: PhantomData<T>,
16}
17
18impl<T: RoutingTestModelBuilder> CommonDictionaryTest<T> {
19    pub fn new() -> Self {
20        Self { builder: PhantomData }
21    }
22
23    pub async fn test_use_protocol_from_dictionary(&self) {
24        // Test extracting a protocol from a dictionary with source parent, self and child.
25        let components = vec![
26            (
27                "root",
28                ComponentDeclBuilder::new()
29                    .protocol_default("foo")
30                    .dictionary_default("parent_dict")
31                    .offer(
32                        OfferBuilder::protocol()
33                            .name("foo")
34                            .target_name("B")
35                            .source(OfferSource::Self_)
36                            .target(OfferTarget::Capability("parent_dict".parse().unwrap())),
37                    )
38                    .offer(
39                        OfferBuilder::dictionary()
40                            .name("parent_dict")
41                            .source(OfferSource::Self_)
42                            .target_static_child("mid"),
43                    )
44                    .child_default("mid")
45                    .build(),
46            ),
47            (
48                "mid",
49                ComponentDeclBuilder::new()
50                    .protocol_default("foo")
51                    .dictionary_default("self_dict")
52                    .offer(
53                        OfferBuilder::protocol()
54                            .name("foo")
55                            .target_name("A")
56                            .source(OfferSource::Self_)
57                            .target(OfferTarget::Capability("self_dict".parse().unwrap())),
58                    )
59                    .use_(
60                        UseBuilder::protocol()
61                            .source(UseSource::Self_)
62                            .name("A")
63                            .from_dictionary("self_dict"),
64                    )
65                    .use_(UseBuilder::protocol().name("B").from_dictionary("parent_dict"))
66                    .use_(
67                        UseBuilder::protocol()
68                            .source_static_child("leaf")
69                            .name("C")
70                            .from_dictionary("child_dict"),
71                    )
72                    .child_default("leaf")
73                    .build(),
74            ),
75            (
76                "leaf",
77                ComponentDeclBuilder::new()
78                    .protocol_default("foo")
79                    .dictionary_default("child_dict")
80                    .offer(
81                        OfferBuilder::protocol()
82                            .name("foo")
83                            .target_name("C")
84                            .source(OfferSource::Self_)
85                            .target(OfferTarget::Capability("child_dict".parse().unwrap())),
86                    )
87                    .expose(
88                        ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_),
89                    )
90                    .build(),
91            ),
92        ];
93
94        let test = T::new("root", components).build().await;
95        for path in ["/svc/A", "/svc/B", "/svc/C"] {
96            test.check_use(
97                "mid".try_into().unwrap(),
98                CheckUse::Protocol {
99                    path: path.parse().unwrap(),
100                    expected_res: ExpectedResult::Ok,
101                },
102            )
103            .await;
104        }
105    }
106
107    pub async fn test_use_protocol_from_dictionary_not_a_dictionary(&self) {
108        // Test extracting a protocol from a dictionary, but the dictionary is not actually a
109        // dictionary so it should fail with a type error.
110        let components = vec![
111            (
112                "root",
113                ComponentDeclBuilder::new()
114                    .protocol_default("parent_not_dict")
115                    .offer(
116                        OfferBuilder::protocol()
117                            .name("parent_not_dict")
118                            .source(OfferSource::Self_)
119                            .target_static_child("mid"),
120                    )
121                    .child_default("mid")
122                    .build(),
123            ),
124            (
125                "mid",
126                ComponentDeclBuilder::new()
127                    // We don't test "self_not_dict" here because the manifest schema forbids such a
128                    // manifest from existing.
129                    .use_(UseBuilder::protocol().name("A").from_dictionary("parent_not_dict"))
130                    .use_(
131                        UseBuilder::protocol()
132                            .source_static_child("leaf")
133                            .name("B")
134                            .from_dictionary("child_not_dict"),
135                    )
136                    .child_default("leaf")
137                    .build(),
138            ),
139            (
140                "leaf",
141                ComponentDeclBuilder::new()
142                    .protocol_default("child_not_dict")
143                    .expose(
144                        ExposeBuilder::protocol()
145                            .name("child_not_dict")
146                            .source(ExposeSource::Self_),
147                    )
148                    .build(),
149            ),
150        ];
151
152        let test = T::new("root", components).build().await;
153        for path in ["/svc/A", "/svc/B"] {
154            test.check_use(
155                "mid".try_into().unwrap(),
156                CheckUse::Protocol {
157                    path: path.parse().unwrap(),
158                    expected_res: ExpectedResult::Err(Status::NOT_FOUND),
159                },
160            )
161            .await;
162        }
163    }
164
165    pub async fn test_use_protocol_from_dictionary_not_used(&self) {
166        // Create a dictionary with two protocols. `use` one of the protocols, but not the other.
167        // Only the protocol that is `use`d should be accessible.
168        let components = vec![
169            (
170                "root",
171                ComponentDeclBuilder::new()
172                    .protocol_default("foo")
173                    .protocol_default("bar")
174                    .dictionary_default("parent_dict")
175                    .offer(
176                        OfferBuilder::protocol()
177                            .name("foo")
178                            .target_name("A")
179                            .source(OfferSource::Self_)
180                            .target(OfferTarget::Capability("parent_dict".parse().unwrap())),
181                    )
182                    .offer(
183                        OfferBuilder::protocol()
184                            .name("bar")
185                            .target_name("B")
186                            .source(OfferSource::Self_)
187                            .target(OfferTarget::Capability("parent_dict".parse().unwrap())),
188                    )
189                    .offer(
190                        OfferBuilder::dictionary()
191                            .name("parent_dict")
192                            .source(OfferSource::Self_)
193                            .target_static_child("leaf"),
194                    )
195                    .child_default("leaf")
196                    .build(),
197            ),
198            (
199                "leaf",
200                ComponentDeclBuilder::new()
201                    .use_(UseBuilder::protocol().name("A").from_dictionary("parent_dict"))
202                    .build(),
203            ),
204        ];
205
206        let test = T::new("root", components).build().await;
207        test.check_use(
208            "leaf".try_into().unwrap(),
209            CheckUse::Protocol {
210                path: "/svc/A".parse().unwrap(),
211                expected_res: ExpectedResult::Ok,
212            },
213        )
214        .await;
215        test.check_use(
216            "leaf".try_into().unwrap(),
217            CheckUse::Protocol {
218                path: "/svc/B".parse().unwrap(),
219                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
220            },
221        )
222        .await;
223    }
224
225    pub async fn test_use_protocol_from_dictionary_not_found(&self) {
226        // Test extracting a protocol from a dictionary, but the protocol is missing from the
227        // dictionary.
228        let components = vec![
229            (
230                "root",
231                ComponentDeclBuilder::new()
232                    .protocol_default("foo")
233                    .dictionary_default("dict")
234                    .offer(
235                        OfferBuilder::protocol()
236                            .name("foo")
237                            .target_name("B")
238                            .source(OfferSource::Self_)
239                            .target(OfferTarget::Capability("dict".parse().unwrap())),
240                    )
241                    .offer(
242                        OfferBuilder::dictionary()
243                            .name("dict")
244                            .source(OfferSource::Self_)
245                            .target_static_child("leaf"),
246                    )
247                    .child_default("leaf")
248                    .build(),
249            ),
250            (
251                "leaf",
252                ComponentDeclBuilder::new()
253                    .use_(UseBuilder::protocol().name("A").from_dictionary("dict"))
254                    .build(),
255            ),
256        ];
257
258        let test = T::new("root", components).build().await;
259        test.check_use(
260            "leaf".try_into().unwrap(),
261            CheckUse::Protocol {
262                path: "/svc/A".parse().unwrap(),
263                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
264            },
265        )
266        .await;
267
268        // Test extracting a protocol from a dictionary, but the dictionary is not routed to the
269        // target.
270        let components = vec![
271            (
272                "root",
273                ComponentDeclBuilder::new()
274                    .protocol_default("foo")
275                    .dictionary_default("dict")
276                    .offer(
277                        OfferBuilder::protocol()
278                            .name("foo")
279                            .target_name("A")
280                            .source(OfferSource::Self_)
281                            .target(OfferTarget::Capability("dict".parse().unwrap())),
282                    )
283                    .offer(
284                        OfferBuilder::dictionary()
285                            .name("dict")
286                            .target_name("other_dict")
287                            .source(OfferSource::Self_)
288                            .target_static_child("leaf"),
289                    )
290                    .child_default("leaf")
291                    .build(),
292            ),
293            (
294                "leaf",
295                ComponentDeclBuilder::new()
296                    .use_(UseBuilder::protocol().name("A").from_dictionary("dict"))
297                    .build(),
298            ),
299        ];
300
301        let test = T::new("root", components).build().await;
302        test.check_use(
303            "leaf".try_into().unwrap(),
304            CheckUse::Protocol {
305                path: "/svc/A".parse().unwrap(),
306                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
307            },
308        )
309        .await;
310    }
311
312    pub async fn test_use_directory_from_dictionary(&self) {
313        // Routing a directory into a dictionary isn't supported yet, it should fail.
314        let components = vec![
315            (
316                "root",
317                ComponentDeclBuilder::new()
318                    .capability(CapabilityBuilder::directory().name("bar_data").path("/data/foo"))
319                    .dictionary_default("parent_dict")
320                    .offer(
321                        OfferBuilder::dictionary()
322                            .name("parent_dict")
323                            .source(OfferSource::Self_)
324                            .target_static_child("leaf"),
325                    )
326                    .offer(
327                        OfferBuilder::directory()
328                            .name("bar_data")
329                            .target_name("B")
330                            .source(OfferSource::Self_)
331                            .target(OfferTarget::Capability("parent_dict".parse().unwrap()))
332                            .rights(fio::R_STAR_DIR),
333                    )
334                    .child_default("leaf")
335                    .build(),
336            ),
337            (
338                "leaf",
339                ComponentDeclBuilder::new()
340                    .capability(CapabilityBuilder::directory().name("foo_data").path("/data/foo"))
341                    .dictionary_default("self_dict")
342                    .offer(
343                        OfferBuilder::directory()
344                            .name("foo_data")
345                            .target_name("A")
346                            .source(OfferSource::Self_)
347                            .target(OfferTarget::Capability("self_dict".parse().unwrap()))
348                            .rights(fio::R_STAR_DIR),
349                    )
350                    .use_(
351                        UseBuilder::directory()
352                            .source(UseSource::Self_)
353                            .name("A")
354                            .from_dictionary("self_dict")
355                            .path("/A"),
356                    )
357                    .use_(
358                        UseBuilder::directory().name("B").from_dictionary("parent_dict").path("/B"),
359                    )
360                    .build(),
361            ),
362        ];
363
364        let test = T::new("root", components).build().await;
365        test.check_use(
366            "leaf".try_into().unwrap(),
367            CheckUse::Directory {
368                path: "/A".parse().unwrap(),
369                file: PathBuf::from("hippo"),
370                expected_res: ExpectedResult::Ok,
371            },
372        )
373        .await;
374        test.check_use(
375            "leaf".try_into().unwrap(),
376            CheckUse::Directory {
377                path: "/B".parse().unwrap(),
378                file: PathBuf::from("hippo"),
379                expected_res: ExpectedResult::Ok,
380            },
381        )
382        .await;
383    }
384
385    pub async fn test_expose_directory_from_dictionary(&self) {
386        // Routing a directory into a dictionary isn't supported yet, it should fail.
387        let components = vec![
388            (
389                "root",
390                ComponentDeclBuilder::new()
391                    .use_(UseBuilder::directory().source_static_child("mid").name("A").path("/A"))
392                    .use_(UseBuilder::directory().source_static_child("mid").name("B").path("/B"))
393                    .child_default("mid")
394                    .build(),
395            ),
396            (
397                "mid",
398                ComponentDeclBuilder::new()
399                    .capability(CapabilityBuilder::directory().name("foo_data").path("/data/foo"))
400                    .dictionary_default("self_dict")
401                    .offer(
402                        OfferBuilder::directory()
403                            .name("foo_data")
404                            .target_name("A")
405                            .source(OfferSource::Self_)
406                            .target(OfferTarget::Capability("self_dict".parse().unwrap()))
407                            .rights(fio::R_STAR_DIR),
408                    )
409                    .expose(
410                        ExposeBuilder::directory()
411                            .name("A")
412                            .source(ExposeSource::Self_)
413                            .from_dictionary("self_dict"),
414                    )
415                    .expose(
416                        ExposeBuilder::directory()
417                            .name("B")
418                            .source_static_child("leaf")
419                            .from_dictionary("child_dict"),
420                    )
421                    .child_default("leaf")
422                    .build(),
423            ),
424            (
425                "leaf",
426                ComponentDeclBuilder::new()
427                    .capability(CapabilityBuilder::directory().name("bar_data").path("/data/foo"))
428                    .dictionary_default("child_dict")
429                    .expose(
430                        ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_),
431                    )
432                    .offer(
433                        OfferBuilder::directory()
434                            .name("bar_data")
435                            .target_name("B")
436                            .source(OfferSource::Self_)
437                            .target(OfferTarget::Capability("child_dict".parse().unwrap()))
438                            .rights(fio::R_STAR_DIR),
439                    )
440                    .build(),
441            ),
442        ];
443
444        let test = T::new("root", components).build().await;
445        test.check_use(
446            ".".try_into().unwrap(),
447            CheckUse::Directory {
448                path: "/A".parse().unwrap(),
449                file: PathBuf::from("hippo"),
450                expected_res: ExpectedResult::Ok,
451            },
452        )
453        .await;
454        test.check_use(
455            ".".try_into().unwrap(),
456            CheckUse::Directory {
457                path: "/B".parse().unwrap(),
458                file: PathBuf::from("hippo"),
459                expected_res: ExpectedResult::Ok,
460            },
461        )
462        .await;
463    }
464
465    pub async fn test_use_protocol_from_nested_dictionary(&self) {
466        // Test extracting a protocol from a dictionary nested in another dictionary with source
467        // parent, self and child.
468        let components = vec![
469            (
470                "root",
471                ComponentDeclBuilder::new()
472                    .protocol_default("foo")
473                    .dictionary_default("nested")
474                    .dictionary_default("parent_dict")
475                    .offer(
476                        OfferBuilder::protocol()
477                            .name("foo")
478                            .target_name("B")
479                            .source(OfferSource::Self_)
480                            .target(OfferTarget::Capability("nested".parse().unwrap())),
481                    )
482                    .offer(
483                        OfferBuilder::dictionary()
484                            .name("nested")
485                            .source(OfferSource::Self_)
486                            .target(OfferTarget::Capability("parent_dict".parse().unwrap())),
487                    )
488                    .offer(
489                        OfferBuilder::dictionary()
490                            .name("parent_dict")
491                            .source(OfferSource::Self_)
492                            .target_static_child("mid"),
493                    )
494                    .child_default("mid")
495                    .build(),
496            ),
497            (
498                "mid",
499                ComponentDeclBuilder::new()
500                    .protocol_default("foo")
501                    .dictionary_default("nested")
502                    .dictionary_default("self_dict")
503                    .offer(
504                        OfferBuilder::protocol()
505                            .name("foo")
506                            .target_name("A")
507                            .source(OfferSource::Self_)
508                            .target(OfferTarget::Capability("nested".parse().unwrap())),
509                    )
510                    .offer(
511                        OfferBuilder::dictionary()
512                            .name("nested")
513                            .source(OfferSource::Self_)
514                            .target(OfferTarget::Capability("self_dict".parse().unwrap())),
515                    )
516                    .use_(
517                        UseBuilder::protocol()
518                            .source(UseSource::Self_)
519                            .name("A")
520                            .from_dictionary("self_dict/nested"),
521                    )
522                    .use_(UseBuilder::protocol().name("B").from_dictionary("parent_dict/nested"))
523                    .use_(
524                        UseBuilder::protocol()
525                            .source_static_child("leaf")
526                            .name("C")
527                            .from_dictionary("child_dict/nested"),
528                    )
529                    .child_default("leaf")
530                    .build(),
531            ),
532            (
533                "leaf",
534                ComponentDeclBuilder::new()
535                    .protocol_default("foo")
536                    .dictionary_default("nested")
537                    .dictionary_default("child_dict")
538                    .offer(
539                        OfferBuilder::protocol()
540                            .name("foo")
541                            .target_name("C")
542                            .source(OfferSource::Self_)
543                            .target(OfferTarget::Capability("nested".parse().unwrap())),
544                    )
545                    .offer(
546                        OfferBuilder::dictionary()
547                            .name("nested")
548                            .source(OfferSource::Self_)
549                            .target(OfferTarget::Capability("child_dict".parse().unwrap())),
550                    )
551                    .expose(
552                        ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_),
553                    )
554                    .build(),
555            ),
556        ];
557
558        let test = T::new("root", components).build().await;
559        for path in ["/svc/A", "/svc/B", "/svc/C"] {
560            test.check_use(
561                "mid".try_into().unwrap(),
562                CheckUse::Protocol {
563                    path: path.parse().unwrap(),
564                    expected_res: ExpectedResult::Ok,
565                },
566            )
567            .await;
568        }
569    }
570
571    pub async fn test_offer_protocol_from_dictionary(&self) {
572        // Test extracting a protocol from a dictionary with source parent, self, and child.
573        let components = vec![
574            (
575                "root",
576                ComponentDeclBuilder::new()
577                    .protocol_default("foo")
578                    .dictionary_default("parent_dict")
579                    .offer(
580                        OfferBuilder::protocol()
581                            .name("foo")
582                            .target_name("B")
583                            .source(OfferSource::Self_)
584                            .target(OfferTarget::Capability("parent_dict".parse().unwrap())),
585                    )
586                    .offer(
587                        OfferBuilder::dictionary()
588                            .name("parent_dict")
589                            .source(OfferSource::Self_)
590                            .target_static_child("mid"),
591                    )
592                    .child_default("mid")
593                    .build(),
594            ),
595            (
596                "mid",
597                ComponentDeclBuilder::new()
598                    .protocol_default("foo")
599                    .dictionary_default("self_dict")
600                    .offer(
601                        OfferBuilder::protocol()
602                            .name("A")
603                            .target_name("A_svc")
604                            .source(OfferSource::Self_)
605                            .target_static_child("leaf")
606                            .from_dictionary("self_dict"),
607                    )
608                    .offer(
609                        OfferBuilder::protocol()
610                            .name("foo")
611                            .target_name("A")
612                            .source(OfferSource::Self_)
613                            .target(OfferTarget::Capability("self_dict".parse().unwrap())),
614                    )
615                    .offer(
616                        OfferBuilder::protocol()
617                            .name("B")
618                            .target_name("B_svc")
619                            .source(OfferSource::Parent)
620                            .target_static_child("leaf")
621                            .from_dictionary("parent_dict"),
622                    )
623                    .offer(
624                        OfferBuilder::protocol()
625                            .name("C")
626                            .target_name("C_svc")
627                            .source_static_child("provider")
628                            .target_static_child("leaf")
629                            .from_dictionary("child_dict"),
630                    )
631                    .child_default("provider")
632                    .child_default("leaf")
633                    .build(),
634            ),
635            (
636                "provider",
637                ComponentDeclBuilder::new()
638                    .protocol_default("foo")
639                    .dictionary_default("child_dict")
640                    .offer(
641                        OfferBuilder::protocol()
642                            .name("foo")
643                            .target_name("C")
644                            .source(OfferSource::Self_)
645                            .target(OfferTarget::Capability("child_dict".parse().unwrap())),
646                    )
647                    .expose(
648                        ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_),
649                    )
650                    .build(),
651            ),
652            (
653                "leaf",
654                ComponentDeclBuilder::new()
655                    .use_(UseBuilder::protocol().name("A_svc").path("/svc/A"))
656                    .use_(UseBuilder::protocol().name("B_svc").path("/svc/B"))
657                    .use_(UseBuilder::protocol().name("C_svc").path("/svc/C"))
658                    .build(),
659            ),
660        ];
661
662        let test = T::new("root", components).build().await;
663        for path in ["/svc/A", "/svc/B", "/svc/C"] {
664            test.check_use(
665                "mid/leaf".try_into().unwrap(),
666                CheckUse::Protocol {
667                    path: path.parse().unwrap(),
668                    expected_res: ExpectedResult::Ok,
669                },
670            )
671            .await;
672        }
673    }
674
675    pub async fn test_offer_protocol_from_dictionary_not_found(&self) {
676        // Test extracting a protocol from a dictionary, but the protocol is missing from the
677        // dictionary.
678        let components = vec![
679            (
680                "root",
681                ComponentDeclBuilder::new()
682                    .protocol_default("foo")
683                    .dictionary_default("dict")
684                    .offer(
685                        OfferBuilder::protocol()
686                            .name("foo")
687                            .target_name("B")
688                            .source(OfferSource::Self_)
689                            .target(OfferTarget::Capability("dict".parse().unwrap())),
690                    )
691                    .offer(
692                        OfferBuilder::dictionary()
693                            .name("dict")
694                            .source(OfferSource::Self_)
695                            .target_static_child("mid"),
696                    )
697                    .child_default("mid")
698                    .build(),
699            ),
700            (
701                "mid",
702                ComponentDeclBuilder::new()
703                    .offer(
704                        OfferBuilder::protocol()
705                            .name("A")
706                            .target_name("A_svc")
707                            .source(OfferSource::Parent)
708                            .target_static_child("leaf")
709                            .from_dictionary("dict"),
710                    )
711                    .child_default("leaf")
712                    .build(),
713            ),
714            (
715                "leaf",
716                ComponentDeclBuilder::new()
717                    .use_(UseBuilder::protocol().name("A_svc").path("/svc/A"))
718                    .build(),
719            ),
720        ];
721
722        let test = T::new("root", components).build().await;
723        test.check_use(
724            "mid/leaf".try_into().unwrap(),
725            CheckUse::Protocol {
726                path: "/svc/A".parse().unwrap(),
727                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
728            },
729        )
730        .await;
731    }
732
733    pub async fn test_offer_protocol_from_dictionary_to_dictionary(&self) {
734        let components = vec![
735            (
736                "root",
737                ComponentDeclBuilder::new()
738                    .dictionary_default("dict1")
739                    .dictionary_default("dict2")
740                    .offer(
741                        OfferBuilder::protocol()
742                            .name("foo")
743                            .target_name("A")
744                            .source_static_child("provider")
745                            .target(OfferTarget::Capability("dict1".parse().unwrap())),
746                    )
747                    .offer(
748                        OfferBuilder::protocol()
749                            .name("A")
750                            .target_name("A")
751                            .from_dictionary("dict1")
752                            .source(OfferSource::Self_)
753                            .target(OfferTarget::Capability("dict2".parse().unwrap())),
754                    )
755                    .offer(
756                        OfferBuilder::dictionary()
757                            .name("dict2")
758                            .source(OfferSource::Self_)
759                            .target_static_child("leaf"),
760                    )
761                    .child_default("provider")
762                    .child_default("leaf")
763                    .build(),
764            ),
765            (
766                "provider",
767                ComponentDeclBuilder::new()
768                    .protocol_default("foo")
769                    .expose(ExposeBuilder::protocol().name("foo").source(ExposeSource::Self_))
770                    .build(),
771            ),
772            (
773                "leaf",
774                ComponentDeclBuilder::new()
775                    .use_(UseBuilder::protocol().name("A").from_dictionary("dict2").path("/svc/A"))
776                    .build(),
777            ),
778        ];
779
780        let test = T::new("root", components).build().await;
781        test.check_use(
782            "leaf".try_into().unwrap(),
783            CheckUse::Protocol {
784                path: "/svc/A".parse().unwrap(),
785                expected_res: ExpectedResult::Ok,
786            },
787        )
788        .await;
789    }
790
791    pub async fn test_offer_protocol_from_nested_dictionary(&self) {
792        // Test extracting a protocol from a dictionary nested in another dictionary with source
793        // parent, self, and child.
794        let components = vec![
795            (
796                "root",
797                ComponentDeclBuilder::new()
798                    .protocol_default("foo")
799                    .dictionary_default("nested")
800                    .dictionary_default("parent_dict")
801                    .offer(
802                        OfferBuilder::protocol()
803                            .name("foo")
804                            .target_name("B")
805                            .source(OfferSource::Self_)
806                            .target(OfferTarget::Capability("nested".parse().unwrap())),
807                    )
808                    .offer(
809                        OfferBuilder::dictionary()
810                            .name("nested")
811                            .source(OfferSource::Self_)
812                            .target(OfferTarget::Capability("parent_dict".parse().unwrap())),
813                    )
814                    .offer(
815                        OfferBuilder::dictionary()
816                            .name("parent_dict")
817                            .source(OfferSource::Self_)
818                            .target_static_child("mid"),
819                    )
820                    .child_default("mid")
821                    .build(),
822            ),
823            (
824                "mid",
825                ComponentDeclBuilder::new()
826                    .protocol_default("foo")
827                    .dictionary_default("self_dict")
828                    .dictionary_default("nested")
829                    .offer(
830                        OfferBuilder::protocol()
831                            .name("A")
832                            .target_name("A_svc")
833                            .source(OfferSource::Self_)
834                            .target_static_child("leaf")
835                            .from_dictionary("self_dict/nested"),
836                    )
837                    .offer(
838                        OfferBuilder::protocol()
839                            .name("foo")
840                            .target_name("A")
841                            .source(OfferSource::Self_)
842                            .target(OfferTarget::Capability("nested".parse().unwrap())),
843                    )
844                    .offer(
845                        OfferBuilder::dictionary()
846                            .name("nested")
847                            .source(OfferSource::Self_)
848                            .target(OfferTarget::Capability("self_dict".parse().unwrap())),
849                    )
850                    .offer(
851                        OfferBuilder::protocol()
852                            .name("B")
853                            .target_name("B_svc")
854                            .source(OfferSource::Parent)
855                            .target_static_child("leaf")
856                            .from_dictionary("parent_dict/nested"),
857                    )
858                    .offer(
859                        OfferBuilder::protocol()
860                            .name("C")
861                            .target_name("C_svc")
862                            .source_static_child("provider")
863                            .target_static_child("leaf")
864                            .from_dictionary("child_dict/nested"),
865                    )
866                    .child_default("provider")
867                    .child_default("leaf")
868                    .build(),
869            ),
870            (
871                "provider",
872                ComponentDeclBuilder::new()
873                    .protocol_default("foo")
874                    .dictionary_default("child_dict")
875                    .dictionary_default("nested")
876                    .offer(
877                        OfferBuilder::protocol()
878                            .name("foo")
879                            .target_name("C")
880                            .source(OfferSource::Self_)
881                            .target(OfferTarget::Capability("nested".parse().unwrap())),
882                    )
883                    .offer(
884                        OfferBuilder::dictionary()
885                            .name("nested")
886                            .source(OfferSource::Self_)
887                            .target(OfferTarget::Capability("child_dict".parse().unwrap())),
888                    )
889                    .expose(
890                        ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_),
891                    )
892                    .build(),
893            ),
894            (
895                "leaf",
896                ComponentDeclBuilder::new()
897                    .use_(UseBuilder::protocol().name("A_svc").path("/svc/A"))
898                    .use_(UseBuilder::protocol().name("B_svc").path("/svc/B"))
899                    .use_(UseBuilder::protocol().name("C_svc").path("/svc/C"))
900                    .build(),
901            ),
902        ];
903
904        let test = T::new("root", components).build().await;
905        for path in ["/svc/A", "/svc/B", "/svc/C"] {
906            test.check_use(
907                "mid/leaf".try_into().unwrap(),
908                CheckUse::Protocol {
909                    path: path.parse().unwrap(),
910                    expected_res: ExpectedResult::Ok,
911                },
912            )
913            .await;
914        }
915    }
916
917    pub async fn test_expose_protocol_from_dictionary(&self) {
918        // Test extracting a protocol from a dictionary with source self and child.
919        let components = vec![
920            (
921                "root",
922                ComponentDeclBuilder::new()
923                    .use_(
924                        UseBuilder::protocol()
925                            .source_static_child("mid")
926                            .name("A_svc")
927                            .path("/svc/A"),
928                    )
929                    .use_(
930                        UseBuilder::protocol()
931                            .source_static_child("mid")
932                            .name("B_svc")
933                            .path("/svc/B"),
934                    )
935                    .child_default("mid")
936                    .build(),
937            ),
938            (
939                "mid",
940                ComponentDeclBuilder::new()
941                    .protocol_default("foo")
942                    .dictionary_default("self_dict")
943                    .expose(
944                        ExposeBuilder::protocol()
945                            .name("A")
946                            .target_name("A_svc")
947                            .from_dictionary("self_dict")
948                            .source(ExposeSource::Self_),
949                    )
950                    .expose(
951                        ExposeBuilder::protocol()
952                            .name("B")
953                            .target_name("B_svc")
954                            .from_dictionary("child_dict")
955                            .source_static_child("leaf"),
956                    )
957                    .offer(
958                        OfferBuilder::protocol()
959                            .name("foo")
960                            .target_name("A")
961                            .source(OfferSource::Self_)
962                            .target(OfferTarget::Capability("self_dict".parse().unwrap())),
963                    )
964                    .child_default("leaf")
965                    .build(),
966            ),
967            (
968                "leaf",
969                ComponentDeclBuilder::new()
970                    .protocol_default("foo")
971                    .dictionary_default("child_dict")
972                    .offer(
973                        OfferBuilder::protocol()
974                            .name("foo")
975                            .target_name("B")
976                            .source(OfferSource::Self_)
977                            .target(OfferTarget::Capability("child_dict".parse().unwrap())),
978                    )
979                    .expose(
980                        ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_),
981                    )
982                    .build(),
983            ),
984        ];
985
986        let test = T::new("root", components).build().await;
987        for path in ["/svc/A", "/svc/B"] {
988            test.check_use(
989                ".".try_into().unwrap(),
990                CheckUse::Protocol {
991                    path: path.parse().unwrap(),
992                    expected_res: ExpectedResult::Ok,
993                },
994            )
995            .await;
996        }
997    }
998
999    pub async fn test_expose_protocol_from_dictionary_not_found(&self) {
1000        // Test extracting a protocol from a dictionary, but the protocol is missing.
1001        let components = vec![
1002            (
1003                "root",
1004                ComponentDeclBuilder::new()
1005                    .use_(
1006                        UseBuilder::protocol()
1007                            .source_static_child("mid")
1008                            .name("A_svc")
1009                            .path("/svc/A"),
1010                    )
1011                    .child_default("mid")
1012                    .build(),
1013            ),
1014            (
1015                "mid",
1016                ComponentDeclBuilder::new()
1017                    .expose(
1018                        ExposeBuilder::protocol()
1019                            .name("A")
1020                            .target_name("A_svc")
1021                            .source(ExposeSource::Self_)
1022                            .from_dictionary("dict")
1023                            .build(),
1024                    )
1025                    .child_default("leaf")
1026                    .build(),
1027            ),
1028            (
1029                "leaf",
1030                ComponentDeclBuilder::new()
1031                    .protocol_default("foo")
1032                    .dictionary_default("dict")
1033                    .offer(
1034                        OfferBuilder::protocol()
1035                            .name("foo")
1036                            .target_name("B")
1037                            .source(OfferSource::Self_)
1038                            .target(OfferTarget::Capability("dict".parse().unwrap())),
1039                    )
1040                    .expose(ExposeBuilder::dictionary().name("dict").source(ExposeSource::Self_))
1041                    .build(),
1042            ),
1043        ];
1044
1045        let test = T::new("root", components).build().await;
1046        test.check_use(
1047            ".".try_into().unwrap(),
1048            CheckUse::Protocol {
1049                path: "/svc/A".parse().unwrap(),
1050                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1051            },
1052        )
1053        .await;
1054    }
1055
1056    pub async fn test_expose_protocol_from_nested_dictionary(&self) {
1057        // Test extracting a protocol from a dictionary nested in a dictionary with source self and
1058        // child.
1059        let components = vec![
1060            (
1061                "root",
1062                ComponentDeclBuilder::new()
1063                    .use_(
1064                        UseBuilder::protocol()
1065                            .source_static_child("mid")
1066                            .name("A_svc")
1067                            .path("/svc/A"),
1068                    )
1069                    .use_(
1070                        UseBuilder::protocol()
1071                            .source_static_child("mid")
1072                            .name("B_svc")
1073                            .path("/svc/B"),
1074                    )
1075                    .child_default("mid")
1076                    .build(),
1077            ),
1078            (
1079                "mid",
1080                ComponentDeclBuilder::new()
1081                    .protocol_default("foo")
1082                    .dictionary_default("self_dict")
1083                    .dictionary_default("nested")
1084                    .expose(
1085                        ExposeBuilder::protocol()
1086                            .name("A")
1087                            .target_name("A_svc")
1088                            .from_dictionary("self_dict/nested")
1089                            .source(ExposeSource::Self_),
1090                    )
1091                    .expose(
1092                        ExposeBuilder::protocol()
1093                            .name("B")
1094                            .target_name("B_svc")
1095                            .from_dictionary("child_dict/nested")
1096                            .source_static_child("leaf"),
1097                    )
1098                    .offer(
1099                        OfferBuilder::protocol()
1100                            .name("foo")
1101                            .target_name("A")
1102                            .source(OfferSource::Self_)
1103                            .target(OfferTarget::Capability("nested".parse().unwrap())),
1104                    )
1105                    .offer(
1106                        OfferBuilder::dictionary()
1107                            .name("nested")
1108                            .source(OfferSource::Self_)
1109                            .target(OfferTarget::Capability("self_dict".parse().unwrap())),
1110                    )
1111                    .child_default("leaf")
1112                    .build(),
1113            ),
1114            (
1115                "leaf",
1116                ComponentDeclBuilder::new()
1117                    .protocol_default("foo")
1118                    .dictionary_default("child_dict")
1119                    .dictionary_default("nested")
1120                    .offer(
1121                        OfferBuilder::dictionary()
1122                            .name("nested")
1123                            .source(OfferSource::Self_)
1124                            .target(OfferTarget::Capability("child_dict".parse().unwrap())),
1125                    )
1126                    .offer(
1127                        OfferBuilder::protocol()
1128                            .name("foo")
1129                            .target_name("B")
1130                            .source(OfferSource::Self_)
1131                            .target(OfferTarget::Capability("nested".parse().unwrap())),
1132                    )
1133                    .expose(
1134                        ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_),
1135                    )
1136                    .build(),
1137            ),
1138        ];
1139
1140        let test = T::new("root", components).build().await;
1141        for path in ["/svc/A", "/svc/B"] {
1142            test.check_use(
1143                ".".try_into().unwrap(),
1144                CheckUse::Protocol {
1145                    path: path.parse().unwrap(),
1146                    expected_res: ExpectedResult::Ok,
1147                },
1148            )
1149            .await;
1150        }
1151    }
1152
1153    pub async fn test_dictionary_in_exposed_dir(&self) {
1154        // Test extracting a protocol from a dictionary with source self and child.
1155        let components = vec![
1156            (
1157                "root",
1158                ComponentDeclBuilder::new()
1159                    .protocol_default("foo")
1160                    .dictionary_default("self_dict")
1161                    .expose(
1162                        ExposeBuilder::dictionary().name("self_dict").source(ExposeSource::Self_),
1163                    )
1164                    .expose(
1165                        ExposeBuilder::dictionary().name("child_dict").source_static_child("leaf"),
1166                    )
1167                    .offer(
1168                        OfferBuilder::protocol()
1169                            .name("foo")
1170                            .target_name("A")
1171                            .source(OfferSource::Self_)
1172                            .target(OfferTarget::Capability("self_dict".parse().unwrap())),
1173                    )
1174                    .child_default("leaf")
1175                    .build(),
1176            ),
1177            (
1178                "leaf",
1179                ComponentDeclBuilder::new()
1180                    .protocol_default("foo")
1181                    .dictionary_default("nested")
1182                    .dictionary_default("child_dict")
1183                    .offer(
1184                        OfferBuilder::dictionary()
1185                            .name("nested")
1186                            .source(OfferSource::Self_)
1187                            .target(OfferTarget::Capability("child_dict".parse().unwrap())),
1188                    )
1189                    .offer(
1190                        OfferBuilder::protocol()
1191                            .name("foo")
1192                            .target_name("B")
1193                            .source(OfferSource::Self_)
1194                            .target(OfferTarget::Capability("nested".parse().unwrap())),
1195                    )
1196                    .expose(
1197                        ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_),
1198                    )
1199                    .build(),
1200            ),
1201        ];
1202
1203        let test = T::new("root", components).build().await;
1204        // The dictionaries in the exposed dir will be converted to subdirectories.
1205        for path in ["/self_dict/A", "/child_dict/nested/B"] {
1206            test.check_use_exposed_dir(
1207                ".".try_into().unwrap(),
1208                CheckUse::Protocol {
1209                    path: path.parse().unwrap(),
1210                    expected_res: ExpectedResult::Ok,
1211                },
1212            )
1213            .await;
1214        }
1215    }
1216
1217    pub async fn test_offer_dictionary_to_dictionary(&self) {
1218        // Tests dictionary nesting when the nested dictionary comes from parent, self, or child.
1219        let components = vec![
1220            (
1221                "root",
1222                ComponentDeclBuilder::new()
1223                    .protocol_default("foo")
1224                    .dictionary_default("parent_dict")
1225                    .offer(
1226                        OfferBuilder::protocol()
1227                            .name("foo")
1228                            .target_name("B")
1229                            .source(OfferSource::Self_)
1230                            .target(OfferTarget::Capability("parent_dict".parse().unwrap())),
1231                    )
1232                    .offer(
1233                        OfferBuilder::dictionary()
1234                            .name("parent_dict")
1235                            .source(OfferSource::Self_)
1236                            .target_static_child("mid"),
1237                    )
1238                    .child_default("mid")
1239                    .build(),
1240            ),
1241            (
1242                "mid",
1243                ComponentDeclBuilder::new()
1244                    .protocol_default("foo")
1245                    .dictionary_default("self_dict")
1246                    .dictionary_default("root_dict")
1247                    .offer(
1248                        OfferBuilder::protocol()
1249                            .name("foo")
1250                            .target_name("A")
1251                            .source(OfferSource::Self_)
1252                            .target(OfferTarget::Capability("self_dict".parse().unwrap())),
1253                    )
1254                    .offer(
1255                        OfferBuilder::dictionary()
1256                            .name("self_dict")
1257                            .source(OfferSource::Self_)
1258                            .target(OfferTarget::Capability("root_dict".parse().unwrap())),
1259                    )
1260                    .offer(
1261                        OfferBuilder::dictionary()
1262                            .name("parent_dict")
1263                            .source(OfferSource::Parent)
1264                            .target(OfferTarget::Capability("root_dict".parse().unwrap())),
1265                    )
1266                    .offer(
1267                        OfferBuilder::dictionary()
1268                            .name("child_dict")
1269                            .source_static_child("leaf")
1270                            .target(OfferTarget::Capability("root_dict".parse().unwrap())),
1271                    )
1272                    .use_(
1273                        UseBuilder::protocol()
1274                            .source(UseSource::Self_)
1275                            .name("A")
1276                            .from_dictionary("root_dict/self_dict"),
1277                    )
1278                    .use_(
1279                        UseBuilder::protocol()
1280                            .source(UseSource::Self_)
1281                            .name("B")
1282                            .from_dictionary("root_dict/parent_dict"),
1283                    )
1284                    .use_(
1285                        UseBuilder::protocol()
1286                            .source(UseSource::Self_)
1287                            .name("C")
1288                            .from_dictionary("root_dict/child_dict"),
1289                    )
1290                    .child_default("leaf")
1291                    .build(),
1292            ),
1293            (
1294                "leaf",
1295                ComponentDeclBuilder::new()
1296                    .protocol_default("foo")
1297                    .dictionary_default("child_dict")
1298                    .offer(
1299                        OfferBuilder::protocol()
1300                            .name("foo")
1301                            .target_name("C")
1302                            .source(OfferSource::Self_)
1303                            .target(OfferTarget::Capability("child_dict".parse().unwrap())),
1304                    )
1305                    .expose(
1306                        ExposeBuilder::dictionary().name("child_dict").source(ExposeSource::Self_),
1307                    )
1308                    .build(),
1309            ),
1310        ];
1311
1312        let test = T::new("root", components).build().await;
1313        for path in ["/svc/A", "/svc/B", "/svc/C"] {
1314            test.check_use(
1315                "mid".try_into().unwrap(),
1316                CheckUse::Protocol {
1317                    path: path.parse().unwrap(),
1318                    expected_res: ExpectedResult::Ok,
1319                },
1320            )
1321            .await;
1322        }
1323    }
1324
1325    pub async fn test_use_from_dictionary_availability_attenuated(&self) {
1326        // required -> optional downgrade allowed, of:
1327        // - a capability in a dictionary
1328        // - a capability in a dictionary in a dictionary
1329        let components = vec![
1330            (
1331                "root",
1332                ComponentDeclBuilder::new()
1333                    .protocol_default("foo")
1334                    .protocol_default("bar")
1335                    .dictionary_default("nested")
1336                    .dictionary_default("dict")
1337                    .offer(
1338                        OfferBuilder::protocol()
1339                            .name("foo")
1340                            .target_name("A")
1341                            .source(OfferSource::Self_)
1342                            .target(OfferTarget::Capability("dict".parse().unwrap())),
1343                    )
1344                    .offer(
1345                        OfferBuilder::protocol()
1346                            .name("bar")
1347                            .target_name("B")
1348                            .source(OfferSource::Self_)
1349                            .target(OfferTarget::Capability("nested".parse().unwrap())),
1350                    )
1351                    .offer(
1352                        OfferBuilder::dictionary()
1353                            .name("nested")
1354                            .source(OfferSource::Self_)
1355                            .target(OfferTarget::Capability("dict".parse().unwrap())),
1356                    )
1357                    .offer(
1358                        OfferBuilder::dictionary()
1359                            .name("dict")
1360                            .source(OfferSource::Self_)
1361                            .target_static_child("leaf"),
1362                    )
1363                    .child_default("leaf")
1364                    .build(),
1365            ),
1366            (
1367                "leaf",
1368                ComponentDeclBuilder::new()
1369                    .use_(
1370                        UseBuilder::protocol()
1371                            .name("A")
1372                            .from_dictionary("dict")
1373                            .availability(Availability::Optional),
1374                    )
1375                    .use_(
1376                        UseBuilder::protocol()
1377                            .name("B")
1378                            .from_dictionary("dict/nested")
1379                            .availability(Availability::Optional),
1380                    )
1381                    .build(),
1382            ),
1383        ];
1384
1385        let test = T::new("root", components).build().await;
1386        test.check_use(
1387            "leaf".try_into().unwrap(),
1388            CheckUse::Protocol {
1389                path: "/svc/A".parse().unwrap(),
1390                expected_res: ExpectedResult::Ok,
1391            },
1392        )
1393        .await;
1394        test.check_use(
1395            "leaf".try_into().unwrap(),
1396            CheckUse::Protocol {
1397                path: "/svc/B".parse().unwrap(),
1398                expected_res: ExpectedResult::Ok,
1399            },
1400        )
1401        .await;
1402    }
1403
1404    pub async fn test_use_from_dictionary_availability_invalid(&self) {
1405        // attempted optional -> required upgrade, disallowed, of:
1406        // - an optional capability in a dictionary.
1407        // - a capability in an optional dictionary.
1408        // - a capability in a dictionary in an optional dictionary.
1409        let components = vec![
1410            (
1411                "root",
1412                ComponentDeclBuilder::new()
1413                    .protocol_default("foo")
1414                    .protocol_default("bar")
1415                    .protocol_default("qux")
1416                    .dictionary_default("required_dict")
1417                    .dictionary_default("optional_dict")
1418                    .dictionary_default("nested")
1419                    .dictionary_default("dict_with_optional_nested")
1420                    .offer(
1421                        OfferBuilder::protocol()
1422                            .name("foo")
1423                            .target_name("A")
1424                            .source(OfferSource::Self_)
1425                            .target(OfferTarget::Capability("required_dict".parse().unwrap()))
1426                            .availability(Availability::Optional),
1427                    )
1428                    .offer(
1429                        OfferBuilder::protocol()
1430                            .name("bar")
1431                            .target_name("B")
1432                            .source(OfferSource::Self_)
1433                            .target(OfferTarget::Capability("optional_dict".parse().unwrap())),
1434                    )
1435                    .offer(
1436                        OfferBuilder::protocol()
1437                            .name("qux")
1438                            .target_name("C")
1439                            .source(OfferSource::Self_)
1440                            .target(OfferTarget::Capability("nested".parse().unwrap())),
1441                    )
1442                    .offer(
1443                        OfferBuilder::dictionary()
1444                            .name("nested")
1445                            .source(OfferSource::Self_)
1446                            .target(OfferTarget::Capability(
1447                                "dict_with_optional_nested".parse().unwrap(),
1448                            ))
1449                            .availability(Availability::Optional),
1450                    )
1451                    .offer(
1452                        OfferBuilder::dictionary()
1453                            .name("required_dict")
1454                            .source(OfferSource::Self_)
1455                            .target_static_child("leaf"),
1456                    )
1457                    .offer(
1458                        OfferBuilder::dictionary()
1459                            .name("optional_dict")
1460                            .source(OfferSource::Self_)
1461                            .target_static_child("leaf")
1462                            .availability(Availability::Optional),
1463                    )
1464                    .offer(
1465                        OfferBuilder::dictionary()
1466                            .name("dict_with_optional_nested")
1467                            .source(OfferSource::Self_)
1468                            .target_static_child("leaf"),
1469                    )
1470                    .child_default("leaf")
1471                    .build(),
1472            ),
1473            (
1474                "leaf",
1475                ComponentDeclBuilder::new()
1476                    .use_(UseBuilder::protocol().name("A").from_dictionary("required_dict"))
1477                    .use_(UseBuilder::protocol().name("B").from_dictionary("optional_dict"))
1478                    .use_(
1479                        UseBuilder::protocol()
1480                            .name("C")
1481                            .from_dictionary("dict_with_optional_nested/nested"),
1482                    )
1483                    .build(),
1484            ),
1485        ];
1486
1487        let test = T::new("root", components).build().await;
1488        test.check_use(
1489            "leaf".try_into().unwrap(),
1490            CheckUse::Protocol {
1491                path: "/svc/A".parse().unwrap(),
1492                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1493            },
1494        )
1495        .await;
1496        test.check_use(
1497            "leaf".try_into().unwrap(),
1498            CheckUse::Protocol {
1499                path: "/svc/B".parse().unwrap(),
1500                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1501            },
1502        )
1503        .await;
1504        test.check_use(
1505            "leaf".try_into().unwrap(),
1506            CheckUse::Protocol {
1507                path: "/svc/C".parse().unwrap(),
1508                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1509            },
1510        )
1511        .await;
1512    }
1513
1514    pub async fn test_offer_from_dictionary_availability_attenuated(&self) {
1515        // required -> optional downgrade allowed, of:
1516        // - a capability in a dictionary
1517        // - a capability in a dictionary in a dictionary
1518        let components = vec![
1519            (
1520                "root",
1521                ComponentDeclBuilder::new()
1522                    .protocol_default("foo")
1523                    .protocol_default("bar")
1524                    .dictionary_default("nested")
1525                    .dictionary_default("dict")
1526                    .offer(
1527                        OfferBuilder::protocol()
1528                            .name("foo")
1529                            .target_name("A")
1530                            .source(OfferSource::Self_)
1531                            .target(OfferTarget::Capability("dict".parse().unwrap())),
1532                    )
1533                    .offer(
1534                        OfferBuilder::protocol()
1535                            .name("bar")
1536                            .target_name("B")
1537                            .source(OfferSource::Self_)
1538                            .target(OfferTarget::Capability("nested".parse().unwrap())),
1539                    )
1540                    .offer(
1541                        OfferBuilder::dictionary()
1542                            .name("nested")
1543                            .source(OfferSource::Self_)
1544                            .target(OfferTarget::Capability("dict".parse().unwrap())),
1545                    )
1546                    .offer(
1547                        OfferBuilder::protocol()
1548                            .name("A")
1549                            .source(OfferSource::Self_)
1550                            .target_static_child("leaf")
1551                            .from_dictionary("dict"),
1552                    )
1553                    .offer(
1554                        OfferBuilder::protocol()
1555                            .name("B")
1556                            .source(OfferSource::Self_)
1557                            .target_static_child("leaf")
1558                            .from_dictionary("dict/nested"),
1559                    )
1560                    .child_default("leaf")
1561                    .build(),
1562            ),
1563            (
1564                "leaf",
1565                ComponentDeclBuilder::new()
1566                    .use_(UseBuilder::protocol().name("A").availability(Availability::Optional))
1567                    .use_(UseBuilder::protocol().name("B").availability(Availability::Optional))
1568                    .build(),
1569            ),
1570        ];
1571
1572        let test = T::new("root", components).build().await;
1573        test.check_use(
1574            "leaf".try_into().unwrap(),
1575            CheckUse::Protocol {
1576                path: "/svc/A".parse().unwrap(),
1577                expected_res: ExpectedResult::Ok,
1578            },
1579        )
1580        .await;
1581        test.check_use(
1582            "leaf".try_into().unwrap(),
1583            CheckUse::Protocol {
1584                path: "/svc/B".parse().unwrap(),
1585                expected_res: ExpectedResult::Ok,
1586            },
1587        )
1588        .await;
1589    }
1590
1591    pub async fn test_offer_from_dictionary_availability_invalid(&self) {
1592        // attempted optional -> required upgrade, disallowed, of:
1593        // - an optional capability in a dictionary.
1594        // - a capability in an optional dictionary.
1595        // - a capability in a dictionary in an optional dictionary.
1596        let components = vec![
1597            (
1598                "root",
1599                ComponentDeclBuilder::new()
1600                    .protocol_default("foo")
1601                    .protocol_default("bar")
1602                    .protocol_default("qux")
1603                    .dictionary_default("required_dict")
1604                    .dictionary_default("optional_dict")
1605                    .dictionary_default("nested")
1606                    .dictionary_default("dict_with_optional_nested")
1607                    .offer(
1608                        OfferBuilder::protocol()
1609                            .name("foo")
1610                            .target_name("A")
1611                            .source(OfferSource::Self_)
1612                            .target(OfferTarget::Capability("required_dict".parse().unwrap()))
1613                            .availability(Availability::Optional),
1614                    )
1615                    .offer(
1616                        OfferBuilder::protocol()
1617                            .name("bar")
1618                            .target_name("B")
1619                            .source(OfferSource::Self_)
1620                            .target(OfferTarget::Capability("optional_dict".parse().unwrap())),
1621                    )
1622                    .offer(
1623                        OfferBuilder::protocol()
1624                            .name("qux")
1625                            .target_name("C")
1626                            .source(OfferSource::Self_)
1627                            .target(OfferTarget::Capability("nested".parse().unwrap())),
1628                    )
1629                    .offer(
1630                        OfferBuilder::dictionary()
1631                            .name("nested")
1632                            .source(OfferSource::Self_)
1633                            .target(OfferTarget::Capability(
1634                                "dict_with_optional_nested".parse().unwrap(),
1635                            ))
1636                            .availability(Availability::Optional),
1637                    )
1638                    .offer(
1639                        OfferBuilder::dictionary()
1640                            .name("required_dict")
1641                            .source(OfferSource::Self_)
1642                            .target_static_child("mid"),
1643                    )
1644                    .offer(
1645                        OfferBuilder::dictionary()
1646                            .name("optional_dict")
1647                            .source(OfferSource::Self_)
1648                            .target_static_child("mid")
1649                            .availability(Availability::Optional),
1650                    )
1651                    .offer(
1652                        OfferBuilder::dictionary()
1653                            .name("dict_with_optional_nested")
1654                            .source(OfferSource::Self_)
1655                            .target_static_child("mid"),
1656                    )
1657                    .child_default("mid")
1658                    .build(),
1659            ),
1660            (
1661                "mid",
1662                ComponentDeclBuilder::new()
1663                    .offer(
1664                        OfferBuilder::protocol()
1665                            .name("A")
1666                            .source(OfferSource::Parent)
1667                            .target_static_child("leaf")
1668                            .from_dictionary("required_dict"),
1669                    )
1670                    .offer(
1671                        OfferBuilder::protocol()
1672                            .name("B")
1673                            .source(OfferSource::Parent)
1674                            .target_static_child("leaf")
1675                            .from_dictionary("optional_dict"),
1676                    )
1677                    .offer(
1678                        OfferBuilder::protocol()
1679                            .name("C")
1680                            .source(OfferSource::Parent)
1681                            .target_static_child("leaf")
1682                            .from_dictionary("dict_with_optional_nested/nested"),
1683                    )
1684                    .child_default("leaf")
1685                    .build(),
1686            ),
1687            (
1688                "leaf",
1689                ComponentDeclBuilder::new()
1690                    .use_(UseBuilder::protocol().name("A"))
1691                    .use_(UseBuilder::protocol().name("B"))
1692                    .use_(UseBuilder::protocol().name("C"))
1693                    .build(),
1694            ),
1695        ];
1696
1697        let test = T::new("root", components).build().await;
1698        test.check_use(
1699            "mid/leaf".try_into().unwrap(),
1700            CheckUse::Protocol {
1701                path: "/svc/A".parse().unwrap(),
1702                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1703            },
1704        )
1705        .await;
1706        test.check_use(
1707            "mid/leaf".try_into().unwrap(),
1708            CheckUse::Protocol {
1709                path: "/svc/B".parse().unwrap(),
1710                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1711            },
1712        )
1713        .await;
1714        test.check_use(
1715            "mid/leaf".try_into().unwrap(),
1716            CheckUse::Protocol {
1717                path: "/svc/C".parse().unwrap(),
1718                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1719            },
1720        )
1721        .await;
1722    }
1723
1724    pub async fn test_expose_from_dictionary_availability_attenuated(&self) {
1725        // required -> optional downgrade allowed, of:
1726        // - a capability in a dictionary
1727        // - a capability in a dictionary in a dictionary
1728        let components = vec![
1729            (
1730                "root",
1731                ComponentDeclBuilder::new()
1732                    .use_(
1733                        UseBuilder::protocol()
1734                            .source_static_child("leaf")
1735                            .name("A")
1736                            .availability(Availability::Optional),
1737                    )
1738                    .use_(
1739                        UseBuilder::protocol()
1740                            .source_static_child("leaf")
1741                            .name("B")
1742                            .availability(Availability::Optional),
1743                    )
1744                    .child_default("leaf")
1745                    .build(),
1746            ),
1747            (
1748                "leaf",
1749                ComponentDeclBuilder::new()
1750                    .protocol_default("foo")
1751                    .protocol_default("bar")
1752                    .dictionary_default("nested")
1753                    .dictionary_default("dict")
1754                    .offer(
1755                        OfferBuilder::protocol()
1756                            .name("foo")
1757                            .target_name("A")
1758                            .source(OfferSource::Self_)
1759                            .target(OfferTarget::Capability("dict".parse().unwrap())),
1760                    )
1761                    .offer(
1762                        OfferBuilder::protocol()
1763                            .name("bar")
1764                            .target_name("B")
1765                            .source(OfferSource::Self_)
1766                            .target(OfferTarget::Capability("nested".parse().unwrap())),
1767                    )
1768                    .offer(
1769                        OfferBuilder::dictionary()
1770                            .name("nested")
1771                            .source(OfferSource::Self_)
1772                            .target(OfferTarget::Capability("dict".parse().unwrap())),
1773                    )
1774                    .expose(
1775                        ExposeBuilder::protocol()
1776                            .name("A")
1777                            .from_dictionary("dict")
1778                            .source(ExposeSource::Self_),
1779                    )
1780                    .expose(
1781                        ExposeBuilder::protocol()
1782                            .name("B")
1783                            .from_dictionary("dict/nested")
1784                            .source(ExposeSource::Self_),
1785                    )
1786                    .build(),
1787            ),
1788        ];
1789
1790        let test = T::new("root", components).build().await;
1791        test.check_use(
1792            ".".try_into().unwrap(),
1793            CheckUse::Protocol {
1794                path: "/svc/A".parse().unwrap(),
1795                expected_res: ExpectedResult::Ok,
1796            },
1797        )
1798        .await;
1799        test.check_use(
1800            ".".try_into().unwrap(),
1801            CheckUse::Protocol {
1802                path: "/svc/B".parse().unwrap(),
1803                expected_res: ExpectedResult::Ok,
1804            },
1805        )
1806        .await;
1807    }
1808
1809    pub async fn test_expose_from_dictionary_availability_invalid(&self) {
1810        // attempted optional -> required upgrade, disallowed, of:
1811        // - an optional capability in a dictionary.
1812        // - a capability in an optional dictionary.
1813        // - a capability in a dictionary in an optional dictionary.
1814        let components = vec![
1815            (
1816                "root",
1817                ComponentDeclBuilder::new()
1818                    .use_(UseBuilder::protocol().source_static_child("mid").name("A"))
1819                    .use_(UseBuilder::protocol().source_static_child("mid").name("B"))
1820                    .use_(UseBuilder::protocol().source_static_child("mid").name("C"))
1821                    .child_default("mid")
1822                    .build(),
1823            ),
1824            (
1825                "mid",
1826                ComponentDeclBuilder::new()
1827                    .expose(
1828                        ExposeBuilder::protocol()
1829                            .name("A")
1830                            .from_dictionary("required_dict")
1831                            .source_static_child("leaf"),
1832                    )
1833                    .expose(
1834                        ExposeBuilder::protocol()
1835                            .name("B")
1836                            .from_dictionary("optional_dict")
1837                            .source_static_child("leaf"),
1838                    )
1839                    .expose(
1840                        ExposeBuilder::protocol()
1841                            .name("C")
1842                            .from_dictionary("dict_with_optional_nested/nested")
1843                            .source_static_child("leaf"),
1844                    )
1845                    .child_default("leaf")
1846                    .build(),
1847            ),
1848            (
1849                "leaf",
1850                ComponentDeclBuilder::new()
1851                    .protocol_default("foo")
1852                    .protocol_default("bar")
1853                    .protocol_default("qux")
1854                    .dictionary_default("required_dict")
1855                    .dictionary_default("optional_dict")
1856                    .dictionary_default("nested")
1857                    .dictionary_default("dict_with_optional_nested")
1858                    .offer(
1859                        OfferBuilder::protocol()
1860                            .name("foo")
1861                            .target_name("A")
1862                            .source(OfferSource::Self_)
1863                            .target(OfferTarget::Capability("dict".parse().unwrap()))
1864                            .availability(Availability::Optional),
1865                    )
1866                    .offer(
1867                        OfferBuilder::protocol()
1868                            .name("bar")
1869                            .target_name("B")
1870                            .source(OfferSource::Self_)
1871                            .target(OfferTarget::Capability("optional_dict".parse().unwrap())),
1872                    )
1873                    .offer(
1874                        OfferBuilder::protocol()
1875                            .name("qux")
1876                            .target_name("C")
1877                            .source(OfferSource::Self_)
1878                            .target(OfferTarget::Capability("nested".parse().unwrap())),
1879                    )
1880                    .offer(
1881                        OfferBuilder::dictionary()
1882                            .name("nested")
1883                            .source(OfferSource::Self_)
1884                            .target(OfferTarget::Capability(
1885                                "dict_with_optional_nested".parse().unwrap(),
1886                            ))
1887                            .availability(Availability::Optional),
1888                    )
1889                    .expose(
1890                        ExposeBuilder::dictionary()
1891                            .name("required_dict")
1892                            .source(ExposeSource::Self_),
1893                    )
1894                    .expose(
1895                        ExposeBuilder::dictionary()
1896                            .name("optional_dict")
1897                            .source(ExposeSource::Self_)
1898                            .availability(Availability::Optional),
1899                    )
1900                    .expose(
1901                        ExposeBuilder::dictionary()
1902                            .name("dict_with_optional_nested")
1903                            .source(ExposeSource::Self_),
1904                    )
1905                    .build(),
1906            ),
1907        ];
1908
1909        let test = T::new("root", components).build().await;
1910        test.check_use(
1911            ".".try_into().unwrap(),
1912            CheckUse::Protocol {
1913                path: "/svc/A".parse().unwrap(),
1914                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1915            },
1916        )
1917        .await;
1918        test.check_use(
1919            ".".try_into().unwrap(),
1920            CheckUse::Protocol {
1921                path: "/svc/B".parse().unwrap(),
1922                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1923            },
1924        )
1925        .await;
1926        test.check_use(
1927            ".".try_into().unwrap(),
1928            CheckUse::Protocol {
1929                path: "/svc/C".parse().unwrap(),
1930                expected_res: ExpectedResult::Err(Status::NOT_FOUND),
1931            },
1932        )
1933        .await;
1934    }
1935
1936    pub async fn test_use_runner_from_dictionary(&self) {
1937        let components = vec![
1938            (
1939                "root",
1940                ComponentDeclBuilder::new()
1941                    .runner_default("foo")
1942                    .dictionary_default("dict")
1943                    .offer(
1944                        OfferBuilder::runner()
1945                            .name("foo")
1946                            .target_name("bar")
1947                            .source(OfferSource::Self_)
1948                            .target(OfferTarget::Capability("dict".parse().unwrap())),
1949                    )
1950                    .offer(
1951                        OfferBuilder::dictionary()
1952                            .name("dict")
1953                            .source(OfferSource::Self_)
1954                            .target_static_child("mid"),
1955                    )
1956                    .child_default("mid")
1957                    .build(),
1958            ),
1959            (
1960                "mid",
1961                ComponentDeclBuilder::new_empty_component()
1962                    .use_(UseBuilder::runner().name("bar").from_dictionary("dict"))
1963                    .build(),
1964            ),
1965        ];
1966
1967        let test = T::new("root", components).build().await;
1968        let mid_component =
1969            test.look_up_instance(&["mid"].try_into().unwrap()).await.expect("mid instance");
1970        let source = routing::route_capability(
1971            routing::RouteRequest::UseRunner(UseRunnerDecl {
1972                source: UseSource::Parent,
1973                source_name: "bar".parse().unwrap(),
1974                source_dictionary: "dict".parse().unwrap(),
1975            }),
1976            &mid_component,
1977            &mut routing::mapper::NoopRouteMapper,
1978        )
1979        .await
1980        .expect("failed to route runner");
1981
1982        match source {
1983            routing::RouteSource {
1984                source:
1985                    routing::capability_source::CapabilitySource::Component(
1986                        routing::capability_source::ComponentSource {
1987                            capability:
1988                                routing::capability_source::ComponentCapability::Runner(RunnerDecl {
1989                                    name,
1990                                    ..
1991                                }),
1992                            moniker,
1993                        },
1994                    ),
1995                relative_path,
1996            } if relative_path.is_dot() => {
1997                assert_eq!(name, "foo");
1998                assert_eq!(moniker, Moniker::root());
1999            }
2000            _ => panic!("unexpected source: {:?}", source),
2001        }
2002    }
2003
2004    pub async fn test_offer_runner_from_dictionary(&self) {
2005        let components = vec![
2006            (
2007                "root",
2008                ComponentDeclBuilder::new()
2009                    .runner_default("foo")
2010                    .dictionary_default("dict")
2011                    .offer(
2012                        OfferBuilder::runner()
2013                            .name("foo")
2014                            .target_name("bar")
2015                            .source(OfferSource::Self_)
2016                            .target(OfferTarget::Capability("dict".parse().unwrap())),
2017                    )
2018                    .offer(
2019                        OfferBuilder::dictionary()
2020                            .name("dict")
2021                            .source(OfferSource::Self_)
2022                            .target_static_child("mid"),
2023                    )
2024                    .child_default("mid")
2025                    .build(),
2026            ),
2027            (
2028                "mid",
2029                ComponentDeclBuilder::new()
2030                    .offer(
2031                        OfferBuilder::runner()
2032                            .name("bar")
2033                            .target_name("baz")
2034                            .from_dictionary("dict")
2035                            .source(OfferSource::Parent)
2036                            .target_static_child("leaf"),
2037                    )
2038                    .child_default("leaf")
2039                    .build(),
2040            ),
2041            (
2042                "leaf",
2043                ComponentDeclBuilder::new_empty_component()
2044                    .use_(UseBuilder::runner().name("baz"))
2045                    .build(),
2046            ),
2047        ];
2048
2049        let test = T::new("root", components).build().await;
2050        let leaf_component = test
2051            .look_up_instance(&["mid", "leaf"].try_into().unwrap())
2052            .await
2053            .expect("leaf instance");
2054        let source = routing::route_capability(
2055            routing::RouteRequest::UseRunner(UseRunnerDecl {
2056                source: UseSource::Parent,
2057                source_name: "baz".parse().unwrap(),
2058                source_dictionary: Default::default(),
2059            }),
2060            &leaf_component,
2061            &mut routing::mapper::NoopRouteMapper,
2062        )
2063        .await
2064        .expect("failed to route runner");
2065
2066        match source {
2067            routing::RouteSource {
2068                source:
2069                    routing::capability_source::CapabilitySource::Component(
2070                        routing::capability_source::ComponentSource {
2071                            capability:
2072                                routing::capability_source::ComponentCapability::Runner(RunnerDecl {
2073                                    name,
2074                                    ..
2075                                }),
2076                            moniker,
2077                        },
2078                    ),
2079                relative_path,
2080            } if relative_path.is_dot() => {
2081                assert_eq!(name, "foo");
2082                assert_eq!(moniker, Moniker::root());
2083            }
2084            _ => panic!("unexpected source: {:?}", source),
2085        }
2086    }
2087
2088    pub async fn test_offer_resolver_from_dictionary(&self) {
2089        let components = vec![
2090            (
2091                "root",
2092                ComponentDeclBuilder::new()
2093                    .resolver_default("foo")
2094                    .dictionary_default("dict")
2095                    .offer(
2096                        OfferBuilder::resolver()
2097                            .name("foo")
2098                            .target_name("bar")
2099                            .source(OfferSource::Self_)
2100                            .target(OfferTarget::Capability("dict".parse().unwrap())),
2101                    )
2102                    .offer(
2103                        OfferBuilder::dictionary()
2104                            .name("dict")
2105                            .source(OfferSource::Self_)
2106                            .target_static_child("mid"),
2107                    )
2108                    .child_default("mid")
2109                    .build(),
2110            ),
2111            (
2112                "mid",
2113                ComponentDeclBuilder::new()
2114                    .offer(
2115                        OfferBuilder::resolver()
2116                            .name("bar")
2117                            .target_name("baz")
2118                            .from_dictionary("dict")
2119                            .source(OfferSource::Parent)
2120                            .target_static_child("leaf"),
2121                    )
2122                    .child_default("leaf")
2123                    .build(),
2124            ),
2125            (
2126                "leaf",
2127                ComponentDeclBuilder::new()
2128                    .environment(EnvironmentBuilder::new().name("env").resolver(
2129                        ResolverRegistration {
2130                            resolver: "baz".parse().unwrap(),
2131                            source: RegistrationSource::Parent,
2132                            scheme: "test".to_string(),
2133                        },
2134                    ))
2135                    .build(),
2136            ),
2137        ];
2138
2139        let test = T::new("root", components).build().await;
2140        let leaf_component = test
2141            .look_up_instance(&["mid", "leaf"].try_into().unwrap())
2142            .await
2143            .expect("leaf instance");
2144
2145        let source = routing::route_capability(
2146            routing::RouteRequest::Resolver(ResolverRegistration {
2147                resolver: "baz".parse().unwrap(),
2148                source: RegistrationSource::Parent,
2149                scheme: "test".to_string(),
2150            }),
2151            &leaf_component,
2152            &mut routing::mapper::NoopRouteMapper,
2153        )
2154        .await
2155        .expect("failed to route resolver");
2156
2157        match source {
2158            routing::RouteSource {
2159                source:
2160                    routing::capability_source::CapabilitySource::Component(
2161                        routing::capability_source::ComponentSource {
2162                            capability:
2163                                routing::capability_source::ComponentCapability::Resolver(
2164                                    ResolverDecl { name, .. },
2165                                ),
2166                            moniker,
2167                        },
2168                    ),
2169                relative_path,
2170            } if relative_path.is_dot() => {
2171                assert_eq!(name, "foo");
2172                assert_eq!(moniker, Moniker::root());
2173            }
2174            _ => panic!("unexpected source: {:?}", source),
2175        }
2176    }
2177
2178    pub async fn test_use_config_from_dictionary(&self) {
2179        let components = vec![
2180            (
2181                "root",
2182                ComponentDeclBuilder::new()
2183                    .capability(CapabilityBuilder::config().name("foo").value(10_i32.into()))
2184                    .dictionary_default("dict")
2185                    .offer(
2186                        OfferBuilder::config()
2187                            .name("foo")
2188                            .target_name("bar")
2189                            .source(OfferSource::Self_)
2190                            .target(OfferTarget::Capability("dict".parse().unwrap())),
2191                    )
2192                    .offer(
2193                        OfferBuilder::dictionary()
2194                            .name("dict")
2195                            .source(OfferSource::Self_)
2196                            .target_static_child("leaf"),
2197                    )
2198                    .child_default("leaf")
2199                    .build(),
2200            ),
2201            (
2202                "leaf",
2203                ComponentDeclBuilder::new()
2204                    .use_(
2205                        UseBuilder::config()
2206                            .name("bar")
2207                            .config_type(ConfigValueType::Int32)
2208                            .from_dictionary("dict"),
2209                    )
2210                    .build(),
2211            ),
2212        ];
2213
2214        let test = T::new("root", components).build().await;
2215        let leaf_component =
2216            test.look_up_instance(&["leaf"].try_into().unwrap()).await.expect("leaf instance");
2217        let source = routing::route_capability(
2218            routing::RouteRequest::UseConfig(UseConfigurationDecl {
2219                source: UseSource::Parent,
2220                source_name: "bar".parse().unwrap(),
2221                target_name: "bar".parse().unwrap(),
2222                availability: Availability::Required,
2223                type_: ConfigValueType::Int32,
2224                default: None,
2225                source_dictionary: "dict".parse().unwrap(),
2226            }),
2227            &leaf_component,
2228            &mut routing::mapper::NoopRouteMapper,
2229        )
2230        .await
2231        .expect("failed to route config");
2232
2233        match source {
2234            routing::RouteSource {
2235                source:
2236                    routing::capability_source::CapabilitySource::Component(
2237                        routing::capability_source::ComponentSource {
2238                            capability: routing::capability_source::ComponentCapability::Config(_),
2239                            moniker,
2240                        },
2241                    ),
2242                relative_path,
2243            } if relative_path.is_dot() => {
2244                assert_eq!(moniker, moniker::Moniker::root());
2245            }
2246            _ => panic!("unexpected source: {:?}", source),
2247        }
2248    }
2249
2250    pub async fn test_offer_config_from_dictionary(&self) {
2251        let components = vec![
2252            (
2253                "root",
2254                ComponentDeclBuilder::new()
2255                    .capability(CapabilityBuilder::config().name("foo").value(10_i32.into()))
2256                    .dictionary_default("dict")
2257                    .offer(
2258                        OfferBuilder::config()
2259                            .name("foo")
2260                            .target_name("bar")
2261                            .source(OfferSource::Self_)
2262                            .target(OfferTarget::Capability("dict".parse().unwrap())),
2263                    )
2264                    .offer(
2265                        OfferBuilder::dictionary()
2266                            .name("dict")
2267                            .source(OfferSource::Self_)
2268                            .target_static_child("mid"),
2269                    )
2270                    .child_default("mid")
2271                    .build(),
2272            ),
2273            (
2274                "mid",
2275                ComponentDeclBuilder::new()
2276                    .offer(
2277                        OfferBuilder::config()
2278                            .name("bar")
2279                            .target_name("baz")
2280                            .from_dictionary("dict")
2281                            .source(OfferSource::Parent)
2282                            .target_static_child("leaf"),
2283                    )
2284                    .child_default("leaf")
2285                    .build(),
2286            ),
2287            (
2288                "leaf",
2289                ComponentDeclBuilder::new()
2290                    .use_(UseBuilder::config().name("baz").config_type(ConfigValueType::Int32))
2291                    .build(),
2292            ),
2293        ];
2294
2295        let test = T::new("root", components).build().await;
2296        let leaf_component = test
2297            .look_up_instance(&["mid", "leaf"].try_into().unwrap())
2298            .await
2299            .expect("leaf instance");
2300        let source = routing::route_capability(
2301            routing::RouteRequest::UseConfig(UseConfigurationDecl {
2302                source: UseSource::Parent,
2303                source_name: "baz".parse().unwrap(),
2304                target_name: "baz".parse().unwrap(),
2305                availability: Availability::Required,
2306                type_: ConfigValueType::Int32,
2307                default: None,
2308                source_dictionary: Default::default(),
2309            }),
2310            &leaf_component,
2311            &mut routing::mapper::NoopRouteMapper,
2312        )
2313        .await
2314        .expect("failed to route config");
2315
2316        match source {
2317            routing::RouteSource {
2318                source:
2319                    routing::capability_source::CapabilitySource::Component(
2320                        routing::capability_source::ComponentSource {
2321                            capability: routing::capability_source::ComponentCapability::Config(_),
2322                            moniker,
2323                        },
2324                    ),
2325                relative_path,
2326            } if relative_path.is_dot() => {
2327                assert_eq!(moniker, moniker::Moniker::root());
2328            }
2329            _ => panic!("unexpected source: {:?}", source),
2330        }
2331    }
2332}