component_events/
sequence.rs

1// Copyright 2020 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::descriptor::EventDescriptor;
6use crate::events::{EventStream, EventStreamError, event_name};
7use crate::matcher::EventMatcher;
8use anyhow::{Error, format_err};
9use futures::StreamExt;
10
11/// Determines whether an EventGroup allows events to be verified in any order
12/// or only in the order specified in the group.
13#[derive(Clone)]
14pub enum Ordering {
15    Ordered,
16    Unordered,
17}
18
19/// Determines whether an EventGroup requires all observed events to match
20/// an EventMatcher in the group, or ignores events that don't match.
21#[derive(Clone, PartialEq)]
22pub enum Contains {
23    All,
24    Subset,
25}
26
27#[derive(Clone)]
28pub struct EventSequence {
29    groups: Vec<EventGroup>,
30}
31
32impl EventSequence {
33    pub fn new() -> Self {
34        Self { groups: vec![] }
35    }
36
37    pub fn then(self, matcher: EventMatcher) -> Self {
38        self.all_of(vec![matcher], Ordering::Ordered)
39    }
40
41    /// Adds a group of matchers to verify all following events in the sequence match
42    /// with the given ordering.
43    ///
44    /// The sequence will fail to match if contains events that don't match the group.
45    pub fn all_of(mut self, events: Vec<EventMatcher>, ordering: Ordering) -> Self {
46        self.groups.push(EventGroup::new(events, ordering, Contains::All));
47        self
48    }
49
50    /// Adds a group of matchers to verify that the sequence contains a subset of
51    /// events that match with the given ordering.
52    ///
53    /// Events in the sequence that don't match will be ignored. Subsequent matchers
54    /// outside of this group will not be able to match against ignored events.
55    pub fn has_subset(mut self, events: Vec<EventMatcher>, ordering: Ordering) -> Self {
56        self.groups.push(EventGroup::new(events, ordering, Contains::Subset));
57        self
58    }
59
60    /// Verify that the events in this sequence are received from the provided EventStream.
61    pub async fn expect(self, event_stream: EventStream) -> Result<(), Error> {
62        self.expect_and_giveback(event_stream).await.map(|_| ())
63    }
64
65    /// Verify that the events in this sequence are received from the provided EventStream,
66    /// and gives back the event stream on success.
67    pub async fn expect_and_giveback(
68        mut self,
69        mut event_stream: EventStream,
70    ) -> Result<EventStream, Error> {
71        while !self.groups.is_empty() {
72            match event_stream.next().await {
73                None => return Err(EventStreamError::StreamClosed.into()),
74                Some(event) => {
75                    let actual_event = EventDescriptor::try_from(&event)?;
76                    let _ = self.next(&actual_event)?;
77                }
78            }
79        }
80        Ok(event_stream)
81    }
82
83    pub fn is_empty(&self) -> bool {
84        self.groups.is_empty()
85    }
86
87    pub fn event_names(&self) -> Result<Vec<String>, Error> {
88        let mut event_names = vec![];
89        for group in &self.groups {
90            let mut group_event_names = group.event_names()?;
91            event_names.append(&mut group_event_names);
92        }
93        event_names.dedup();
94        Ok(event_names)
95    }
96
97    /// Tests an EventDescriptor and against the first EventGroup.
98    ///
99    /// If an EventGroup has been entirely consumed (no further EventMatchers
100    /// to match against) then the EventGroup is dropped.
101    ///
102    /// Returns an error if the EventSequence have not been entirely consumed,
103    /// and the incoming EventDescriptor does not match the first sequence.
104    ///
105    /// Returns Ok(true) if there is a positive match.
106    /// Returns Ok(false) if the EventSequence is empty.
107    pub fn next(&mut self, event: &EventDescriptor) -> Result<(), Error> {
108        loop {
109            if self.groups.is_empty() {
110                return Ok(());
111            }
112            let group = &mut self.groups[0];
113            if group.next(event)? {
114                if group.is_empty() {
115                    self.groups.remove(0);
116                }
117                return Ok(());
118            }
119            self.groups.remove(0);
120        }
121    }
122}
123
124#[derive(Clone)]
125pub struct EventGroup {
126    events: Vec<EventMatcher>,
127    ordering: Ordering,
128    contains: Contains,
129}
130
131impl EventGroup {
132    pub fn new(events: Vec<EventMatcher>, ordering: Ordering, contains: Contains) -> Self {
133        Self { events, ordering, contains }
134    }
135
136    pub fn is_empty(&self) -> bool {
137        self.events.is_empty()
138    }
139
140    pub fn event_names(&self) -> Result<Vec<String>, Error> {
141        let mut event_names = vec![];
142        for event in &self.events {
143            if let Some(event_type) = &event.event_type {
144                event_names.push(event_name(&event_type.value()));
145            } else {
146                return Err(format_err!("No event name or type set for matcher {:?}", event));
147            }
148        }
149        event_names.dedup();
150        Ok(event_names)
151    }
152
153    /// Returns true if `event` matches an event matcher in this group.
154    ///
155    /// If the group ordering is Ordered, the event must match the first matcher.
156    /// If the group ordering is Unordered, the event can match any matcher in the group.
157    /// The matcher is removed after a successful match.
158    ///
159    /// Returns an error if the event does not match a matcher and the contains
160    /// policy is All, indicating that the unknown event did not match the group.
161    ///
162    /// Returns Ok(true) if there is a positive match.
163    /// Returns Ok(false) if the EventGroup is empty.
164    pub fn next(&mut self, event: &EventDescriptor) -> Result<bool, Error> {
165        if self.events.is_empty() {
166            return Ok(Contains::Subset == self.contains);
167        }
168        match self.ordering {
169            Ordering::Ordered => {
170                let matches = self.events.get(0).unwrap().matches(event);
171                if matches.is_ok() {
172                    self.events.remove(0);
173                    Ok(true)
174                } else {
175                    // There was no matcher that matched this event.
176                    // This is an error only if the group expects all events to be matched.
177                    match self.contains {
178                        Contains::All => Err(Error::new(matches.unwrap_err())),
179                        Contains::Subset => Ok(true),
180                    }
181                }
182            }
183            Ordering::Unordered => {
184                if let Some((index, _)) = self
185                    .events
186                    .iter()
187                    .enumerate()
188                    .find(|&matcher| matcher.1.matches(&event).is_ok())
189                {
190                    self.events.remove(index);
191                    Ok(true)
192                } else {
193                    match self.contains {
194                        Contains::All => Err(format_err!("Failed to find event: {:?}", event)),
195                        Contains::Subset => Ok(true),
196                    }
197                }
198            }
199        }
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    use super::*;
206    use crate::events::{Event, Started};
207    use fidl_fuchsia_component as fcomponent;
208    use futures::StreamExt;
209
210    async fn run_server(
211        events: Vec<fcomponent::Event>,
212        mut server: fcomponent::EventStreamRequestStream,
213    ) {
214        let (tx, mut rx) = futures::channel::mpsc::unbounded();
215        for event in events {
216            tx.unbounded_send(event).unwrap();
217        }
218        // The tests expect the event_stream to terminate once all events have been consumed.
219        // This behavior does not match that of component_manager but is needed for negative
220        // proof tests (such as the event_stream does NOT contain a given event).
221        drop(tx);
222        while let Some(Ok(request)) = server.next().await {
223            match request {
224                fcomponent::EventStreamRequest::GetNext { responder } => {
225                    if let Some(event) = rx.next().await {
226                        responder.send(vec![event]).unwrap();
227                    } else {
228                        return;
229                    }
230                }
231                fcomponent::EventStreamRequest::WaitForReady { responder } => {
232                    responder.send().unwrap()
233                }
234            }
235        }
236    }
237
238    async fn make_event_stream(
239        events: Vec<fcomponent::Event>,
240    ) -> Result<(EventStream, fuchsia_async::Task<()>), Error> {
241        let (proxy, server) = fidl::endpoints::create_proxy::<fcomponent::EventStreamMarker>();
242        Ok((
243            EventStream::new(proxy),
244            fuchsia_async::Task::spawn(run_server(events, server.into_stream())),
245        ))
246    }
247
248    // Returns a successful Started event for the given moniker.
249    fn make_event<M: Into<String>>(moniker: M) -> fcomponent::Event {
250        fcomponent::Event {
251            header: Some(fcomponent::EventHeader {
252                event_type: Some(fcomponent::EventType::Started),
253                moniker: Some(moniker.into()),
254                ..Default::default()
255            }),
256            payload: Some(fcomponent::EventPayload::Started(fcomponent::StartedPayload::default())),
257            ..Default::default()
258        }
259    }
260
261    // Returns a matcher for a successful Started event for the given moniker.
262    fn make_matcher<M: Into<String>>(moniker: M) -> EventMatcher {
263        EventMatcher::ok().r#type(Started::TYPE).moniker(moniker)
264    }
265
266    #[fuchsia::test]
267    async fn event_sequence_empty() {
268        let (event_stream, _server) =
269            make_event_stream(vec![]).await.expect("failed to make event stream");
270        EventSequence::new()
271            .expect(event_stream)
272            .await
273            .expect("event sequence did not match expected");
274    }
275
276    #[fuchsia::test]
277    async fn event_sequence_then() {
278        let moniker = "./foo:0";
279        let (event_stream, _server) = make_event_stream(vec![make_event(moniker)])
280            .await
281            .expect("failed to make event stream");
282        EventSequence::new()
283            .then(make_matcher(moniker))
284            .expect(event_stream)
285            .await
286            .expect("event sequence did not match expected");
287    }
288
289    #[fuchsia::test]
290    async fn event_sequence_all_of_ordered_ok() {
291        let monikers = vec!["./foo:0", "./bar:0", "./baz:0"];
292        let events = monikers.iter().copied().map(make_event).collect();
293        let matchers = monikers.iter().copied().map(make_matcher).collect();
294
295        let (event_stream, _server) =
296            make_event_stream(events).await.expect("failed to make event stream");
297        EventSequence::new()
298            .all_of(matchers, Ordering::Ordered)
299            .expect(event_stream)
300            .await
301            .expect("event sequence did not match expected");
302    }
303
304    #[fuchsia::test]
305    async fn event_sequence_all_of_ordered_fail_order() {
306        let monikers = vec!["./foo:0", "./bar:0", "./baz:0"];
307        // Events are in reverse order of the matchers.
308        let events = monikers.iter().rev().copied().map(make_event).collect();
309        let matchers = monikers.iter().copied().map(make_matcher).collect();
310
311        let (event_stream, _server) =
312            make_event_stream(events).await.expect("failed to make event stream");
313        assert!(
314            EventSequence::new()
315                .all_of(matchers, Ordering::Ordered)
316                .expect(event_stream)
317                .await
318                .is_err()
319        );
320    }
321
322    #[fuchsia::test]
323    async fn event_sequence_all_of_ordered_fail_missing_event() {
324        let monikers = vec!["./foo:0", "./bar:0", "./baz:0"];
325        // The first event is missing.
326        let events = monikers.iter().skip(1).copied().map(make_event).collect();
327        let matchers = monikers.iter().copied().map(make_matcher).collect();
328
329        let (event_stream, _server) =
330            make_event_stream(events).await.expect("failed to make event stream");
331        assert!(
332            EventSequence::new()
333                .all_of(matchers, Ordering::Ordered)
334                .expect(event_stream)
335                .await
336                .is_err()
337        );
338    }
339
340    #[fuchsia::test]
341    async fn event_sequence_all_of_ordered_fail_missing_matcher() {
342        let monikers = vec!["./foo:0", "./bar:0", "./baz:0"];
343        let events = monikers.iter().copied().map(make_event).collect();
344        // The first matcher is missing, so the first event is unmatched.
345        let matchers = monikers.iter().skip(1).copied().map(make_matcher).collect();
346
347        let (event_stream, _server) =
348            make_event_stream(events).await.expect("failed to make event stream");
349        assert!(
350            EventSequence::new()
351                .all_of(matchers, Ordering::Ordered)
352                .expect(event_stream)
353                .await
354                .is_err()
355        );
356    }
357
358    #[fuchsia::test]
359    async fn event_sequence_all_of_unordered_ok_reversed() {
360        let monikers = vec!["./foo:0", "./bar:0", "./baz:0"];
361        // Events are in reverse order of the matchers.
362        let events = monikers.iter().rev().copied().map(make_event).collect();
363        let matchers = monikers.iter().copied().map(make_matcher).collect();
364
365        let (event_stream, _server) =
366            make_event_stream(events).await.expect("failed to make event stream");
367        EventSequence::new()
368            .all_of(matchers, Ordering::Unordered)
369            .expect(event_stream)
370            .await
371            .expect("event sequence did not match expected");
372    }
373
374    #[fuchsia::test]
375    async fn event_sequence_has_subset_ordered_ok() {
376        let monikers = vec!["./foo:0", "./bar:0", "./baz:0"];
377        let events = monikers.iter().copied().map(make_event).collect();
378        // The first matcher is missing, so the first event is ignored.
379        let matchers = monikers.iter().skip(1).copied().map(make_matcher).collect();
380
381        let (event_stream, _server) =
382            make_event_stream(events).await.expect("failed to make event stream");
383        EventSequence::new()
384            .has_subset(matchers, Ordering::Ordered)
385            .expect(event_stream)
386            .await
387            .expect("event sequence did not match expected");
388    }
389
390    #[fuchsia::test]
391    async fn event_sequence_has_subset_ordered_missing_event() {
392        let monikers = vec!["./foo:0", "./bar:0", "./baz:0"];
393        // The first two events are missing.
394        let events = monikers.iter().skip(2).copied().map(make_event).collect();
395        // The first matcher is missing, so the first event is ignored.
396        let matchers = monikers.iter().skip(1).copied().map(make_matcher).collect();
397
398        // Matching should fail because the matcher for "./bar:0" can't find the event.
399        let (event_stream, _server) =
400            make_event_stream(events).await.expect("failed to make event stream");
401        assert!(
402            EventSequence::new()
403                .has_subset(matchers, Ordering::Ordered)
404                .expect(event_stream)
405                .await
406                .is_err()
407        );
408    }
409
410    #[fuchsia::test]
411    async fn event_sequence_has_subset_unordered_ok_reversed() {
412        let monikers = vec!["./foo:0", "./bar:0", "./baz:0"];
413        // Events are in reverse order of the matchers.
414        let events = monikers.iter().rev().copied().map(make_event).collect();
415        // The first matcher is missing, so the first event is ignored.
416        let matchers = monikers.iter().skip(1).copied().map(make_matcher).collect();
417
418        let (event_stream, _server) =
419            make_event_stream(events).await.expect("failed to make event stream");
420        EventSequence::new()
421            .has_subset(matchers, Ordering::Unordered)
422            .expect(event_stream)
423            .await
424            .expect("event sequence did not match expected");
425    }
426}