Skip to main content

routing/
availability.rs

1// Copyright 2022 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::error::AvailabilityRoutingError;
6use cm_rust::offer::{OfferDeclCommon, OfferSource};
7use cm_rust::{Availability, ExposeDeclCommon, ExposeSource};
8use moniker::ExtendedMoniker;
9
10pub fn advance_with_offer(
11    moniker: &ExtendedMoniker,
12    current: Availability,
13    offer: &impl OfferDeclCommon,
14) -> Result<Availability, AvailabilityRoutingError> {
15    let result = advance(moniker, current, *offer.availability());
16    if offer.source() == &OfferSource::Void
17        && result
18            == Err(AvailabilityRoutingError::TargetHasStrongerAvailability {
19                moniker: moniker.clone(),
20            })
21    {
22        return Err(AvailabilityRoutingError::OfferFromVoidToRequiredTarget {
23            moniker: moniker.clone(),
24        });
25    }
26    result
27}
28
29pub fn advance_with_expose(
30    moniker: &ExtendedMoniker,
31    current: Availability,
32    expose: &impl ExposeDeclCommon,
33) -> Result<Availability, AvailabilityRoutingError> {
34    let result = advance(moniker, current, *expose.availability());
35    if expose.source() == &ExposeSource::Void
36        && result
37            == Err(AvailabilityRoutingError::TargetHasStrongerAvailability {
38                moniker: moniker.clone(),
39            })
40    {
41        return Err(AvailabilityRoutingError::ExposeFromVoidToRequiredTarget {
42            moniker: moniker.clone(),
43        });
44    }
45    result
46}
47
48pub fn advance(
49    moniker: &ExtendedMoniker,
50    current: Availability,
51    next_availability: Availability,
52) -> Result<Availability, AvailabilityRoutingError> {
53    let next = availability::advance(moniker, current, next_availability)?;
54    Ok(next)
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use cm_rust::offer::{OfferDecl, OfferProtocolDecl};
61    use cm_rust::{DependencyType, ExposeDecl, ExposeProtocolDecl, ExposeTarget};
62    use cm_rust_testing::*;
63    use test_case::test_case;
64
65    fn new_offer(availability: Availability) -> OfferDecl {
66        OfferDecl::Protocol(OfferProtocolDecl {
67            source: OfferSource::Parent,
68            source_name: "fuchsia.examples.Echo".parse().unwrap(),
69            source_dictionary: Default::default(),
70            target: offer_target_static_child("echo"),
71            target_name: "fuchsia.examples.Echo".parse().unwrap(),
72            dependency_type: DependencyType::Weak,
73            availability,
74        })
75    }
76
77    fn new_void_offer() -> OfferDecl {
78        OfferDecl::Protocol(OfferProtocolDecl {
79            source: OfferSource::Void,
80            source_name: "fuchsia.examples.Echo".parse().unwrap(),
81            source_dictionary: Default::default(),
82            target: offer_target_static_child("echo"),
83            target_name: "fuchsia.examples.Echo".parse().unwrap(),
84            dependency_type: DependencyType::Weak,
85            availability: Availability::Optional,
86        })
87    }
88
89    #[test_case(Availability::Optional, new_offer(Availability::Optional), Ok(()))]
90    #[test_case(Availability::Optional, new_offer(Availability::Required), Ok(()))]
91    #[test_case(Availability::Optional, new_offer(Availability::SameAsTarget), Ok(()))]
92    #[test_case(
93        Availability::Optional,
94        new_offer(Availability::Transitional),
95        Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
96    )]
97    #[test_case(Availability::Optional, new_void_offer(), Ok(()))]
98    #[test_case(
99        Availability::Required,
100        new_offer(Availability::Optional),
101        Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
102    )]
103    #[test_case(Availability::Required, new_offer(Availability::Required), Ok(()))]
104    #[test_case(Availability::Required, new_offer(Availability::SameAsTarget), Ok(()))]
105    #[test_case(
106        Availability::Required,
107        new_offer(Availability::Transitional),
108        Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
109    )]
110    #[test_case(
111        Availability::Required,
112        new_void_offer(),
113        Err(AvailabilityRoutingError::OfferFromVoidToRequiredTarget { moniker: ExtendedMoniker::ComponentManager })
114    )]
115    #[test_case(Availability::Transitional, new_offer(Availability::Optional), Ok(()))]
116    #[test_case(Availability::Transitional, new_offer(Availability::Required), Ok(()))]
117    #[test_case(Availability::Transitional, new_offer(Availability::SameAsTarget), Ok(()))]
118    #[test_case(Availability::Transitional, new_offer(Availability::Transitional), Ok(()))]
119    #[test_case(Availability::Transitional, new_void_offer(), Ok(()))]
120    fn offer_tests(
121        availability: Availability,
122        offer: OfferDecl,
123        expected: Result<(), AvailabilityRoutingError>,
124    ) {
125        let actual = advance_with_offer(&ExtendedMoniker::ComponentManager, availability, &offer)
126            .map(|_| ());
127        assert_eq!(actual, expected);
128    }
129
130    fn new_expose(availability: Availability) -> ExposeDecl {
131        ExposeDecl::Protocol(ExposeProtocolDecl {
132            source: ExposeSource::Self_,
133            source_name: "fuchsia.examples.Echo".parse().unwrap(),
134            source_dictionary: Default::default(),
135            target: ExposeTarget::Parent,
136            target_name: "fuchsia.examples.Echo".parse().unwrap(),
137            availability,
138        })
139    }
140
141    fn new_void_expose() -> ExposeDecl {
142        ExposeDecl::Protocol(ExposeProtocolDecl {
143            source: ExposeSource::Void,
144            source_name: "fuchsia.examples.Echo".parse().unwrap(),
145            source_dictionary: Default::default(),
146            target: ExposeTarget::Parent,
147            target_name: "fuchsia.examples.Echo".parse().unwrap(),
148            availability: Availability::Optional,
149        })
150    }
151
152    #[test_case(Availability::Optional, new_expose(Availability::Optional), Ok(()))]
153    #[test_case(Availability::Optional, new_expose(Availability::Required), Ok(()))]
154    #[test_case(Availability::Optional, new_expose(Availability::SameAsTarget), Ok(()))]
155    #[test_case(
156        Availability::Optional,
157        new_expose(Availability::Transitional),
158        Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
159    )]
160    #[test_case(
161        Availability::Optional,
162        new_void_expose(),
163        Ok(())
164    )]
165    #[test_case(
166        Availability::Required,
167        new_expose(Availability::Optional),
168        Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
169    )]
170    #[test_case(Availability::Required, new_expose(Availability::Required), Ok(()))]
171    #[test_case(Availability::Required, new_expose(Availability::SameAsTarget), Ok(()))]
172    #[test_case(
173        Availability::Required,
174        new_expose(Availability::Transitional),
175        Err(AvailabilityRoutingError::TargetHasStrongerAvailability { moniker: ExtendedMoniker::ComponentManager })
176    )]
177    #[test_case(
178        Availability::Required,
179        new_void_expose(),
180        Err(AvailabilityRoutingError::ExposeFromVoidToRequiredTarget { moniker: ExtendedMoniker::ComponentManager })
181    )]
182    #[test_case(Availability::Transitional, new_expose(Availability::Optional), Ok(()))]
183    #[test_case(Availability::Transitional, new_expose(Availability::Required), Ok(()))]
184    #[test_case(Availability::Transitional, new_expose(Availability::SameAsTarget), Ok(()))]
185    #[test_case(Availability::Transitional, new_expose(Availability::Transitional), Ok(()))]
186    #[test_case(
187        Availability::Transitional,
188        new_void_expose(),
189        Ok(())
190    )]
191    fn expose_tests(
192        availability: Availability,
193        expose: ExposeDecl,
194        expected: Result<(), AvailabilityRoutingError>,
195    ) {
196        let actual = advance_with_expose(&ExtendedMoniker::ComponentManager, availability, &expose)
197            .map(|_| ());
198        assert_eq!(actual, expected);
199    }
200}