blob: a34af4a8197a9d20918adf8411dd66bb4bc3fce6 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::{
descriptor::EventDescriptor,
events::{event_name, EventMode, EventSource, EventStream, EventSubscription},
matcher::EventMatcher,
},
anyhow::{format_err, Error},
fuchsia_async as fasync,
futures::{channel::oneshot, future::BoxFuture},
std::convert::TryFrom,
};
/// Ordering is used by `EventSequence::subscribe_and_expect`to determine if it should allow events to be
/// verified in any order or only in the order specified by the test.
#[derive(Clone)]
pub enum Ordering {
Ordered,
Unordered,
}
#[derive(Clone)]
pub struct EventSequence {
groups: Vec<EventGroup>,
}
impl EventSequence {
pub fn new() -> Self {
Self { groups: vec![] }
}
pub fn then(self, matcher: EventMatcher) -> Self {
self.all_of(vec![matcher], Ordering::Ordered)
}
pub fn all_of(mut self, events: Vec<EventMatcher>, ordering: Ordering) -> Self {
self.groups.push(EventGroup::new(events, ordering));
self
}
/// Verify that the events in this sequence are received from the provided
/// EventStream.
pub async fn expect(mut self, mut event_stream: EventStream) -> Result<(), Error> {
while !self.groups.is_empty() {
match event_stream.next().await {
Err(e) => return Err(e.into()),
Ok(event) => {
let actual_event = EventDescriptor::try_from(&event)?;
if actual_event.target_moniker != Some(".".to_string()) {
let _ = self.next(&actual_event)?;
}
}
}
}
Ok(())
}
/// Verifies that the given events are received from the event system. Based on the vector of
/// events passed in this function will subscribe to an event stream with the relevant event
/// types and verify that the correct events for the component are received.
pub async fn subscribe_and_expect<'a>(
self,
event_source: &mut EventSource,
) -> Result<BoxFuture<'a, Result<(), Error>>, Error> {
let event_names = self.event_names()?;
let event_stream = event_source
.subscribe(vec![EventSubscription::new(event_names, EventMode::Sync)])
.await?;
let expected_events = self.clone();
let (tx, rx) = oneshot::channel();
fasync::Task::spawn(async move {
let res = expected_events.expect(event_stream).await;
tx.send(res).expect("Unable to send result");
})
.detach();
Ok(Box::pin(async move { rx.await? }))
}
pub fn is_empty(&self) -> bool {
self.groups.is_empty()
}
pub fn event_names(&self) -> Result<Vec<String>, Error> {
let mut event_names = vec![];
for group in &self.groups {
let mut group_event_names = group.event_names()?;
event_names.append(&mut group_event_names);
}
event_names.dedup();
Ok(event_names)
}
// Takes in an EventDescriptor and tests it against the first EventGroup.
// If an EventGroup has been entirely consumed (no further EventMatchers
// to match against) then the EventGroup is dropped. If the
// EventSequence have not been entirely consumed, and the incoming
// EventDescriptor does not match the first sequence then an error is returned.
// If the EventSequence is empty, then Ok(false) is returned. Otherwise, if
// there is a positive match, then Ok(true) is returned.
pub fn next(&mut self, event: &EventDescriptor) -> Result<(), Error> {
loop {
if self.groups.is_empty() {
return Ok(());
}
let group = &mut self.groups[0];
if group.next(event)? {
if group.is_empty() {
self.groups.remove(0);
}
return Ok(());
}
self.groups.remove(0);
}
}
}
#[derive(Clone)]
pub struct EventGroup {
events: Vec<EventMatcher>,
ordering: Ordering,
}
impl EventGroup {
pub fn new(events: Vec<EventMatcher>, ordering: Ordering) -> Self {
Self { events, ordering }
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
pub fn event_names(&self) -> Result<Vec<String>, Error> {
let mut event_names = vec![];
for event in &self.events {
if let Some(event_type) = &event.event_type {
event_names.push(event_name(&event_type.value()));
} else {
return Err(format_err!("No event name or type set for matcher {:?}", event));
}
}
event_names.dedup();
Ok(event_names)
}
// Takes in an EventDescriptor and tests it against the next EventMatcher in
// the sequence. If the sequence is empty, then Ok(false) is returned. If
// the sequence is Ordered, then this tests it against the first
// EventMatcher. If the sequence is Unordered, then this tests the
// EventDescriptor against all EventMatchers in the sequence to find a
// match. In either case, if no match is found, then an Error is returned.
// If there is a positive match, then Ok(true) is returned.
pub fn next(&mut self, event: &EventDescriptor) -> Result<bool, Error> {
if self.events.is_empty() {
return Ok(false);
}
let expected_event = match self.ordering {
Ordering::Ordered => self.events.remove(0),
Ordering::Unordered => {
if let Some((index, _)) = self
.events
.iter()
.enumerate()
.find(|&matcher| matcher.1.matches(&event).is_ok())
{
self.events.remove(index)
} else {
return Err(format_err!("Failed to find event: {:?}", event));
}
}
};
expected_event.matches(&event).map(|_| true).map_err(|e| format_err!("{}", e))
}
}