// Copyright 2018 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 anyhow::Context as _;
use core::sync::atomic::AtomicUsize;
use fidl::endpoints::create_proxy;
use fidl_fuchsia_wlan_device as fidl_wlan_dev;
use fidl_fuchsia_wlan_device_service::{self as fidl_svc, DeviceServiceRequest};
use fidl_fuchsia_wlan_mlme::{self as fidl_mlme, MinstrelStatsResponse, MlmeMarker};
use fuchsia_async as fasync;
use fuchsia_cobalt::{self, CobaltSender};
use fuchsia_inspect_contrib::inspect_log;
use fuchsia_zircon as zx;
use futures::prelude::*;
use log::{error, info};
use std::sync::{atomic::Ordering, Arc};

use crate::device::{self, IfaceDevice, IfaceMap, NewIface, PhyDevice, PhyMap};
use crate::inspect;
use crate::station;
use crate::stats_scheduler::StatsRef;
use crate::watcher_service::WatcherService;
use crate::ServiceCfg;

/// Thread-safe counter for spawned ifaces.
pub struct IfaceCounter(AtomicUsize);

impl IfaceCounter {
    pub fn new() -> Self {
        Self(AtomicUsize::new(0))
    }

    /// Provides the caller with a new unique id.
    pub fn next_iface_id(&self) -> usize {
        self.0.fetch_add(1, Ordering::SeqCst)
    }

    #[cfg(test)]
    pub fn new_with_value(v: usize) -> Self {
        Self(AtomicUsize::new(v))
    }
}

pub async fn serve_device_requests(
    iface_counter: Arc<IfaceCounter>,
    cfg: ServiceCfg,
    phys: Arc<PhyMap>,
    ifaces: Arc<IfaceMap>,
    watcher_service: WatcherService<PhyDevice, IfaceDevice>,
    mut req_stream: fidl_svc::DeviceServiceRequestStream,
    inspect_tree: Arc<inspect::WlanstackTree>,
    cobalt_sender: CobaltSender,
) -> Result<(), anyhow::Error> {
    while let Some(req) = req_stream.try_next().await.context("error running DeviceService")? {
        // Note that errors from responder.send() are propagated intentionally.
        // If we fail to send a response, the only way to recover is to stop serving the
        // client and close the channel. Otherwise, the client would be left hanging
        // forever.
        match req {
            DeviceServiceRequest::ListPhys { responder } => responder.send(&mut list_phys(&phys)),
            DeviceServiceRequest::QueryPhy { req, responder } => {
                let result = query_phy(&phys, req.phy_id).await;
                let (status, mut response) = into_status_and_opt(result);
                responder.send(status.into_raw(), response.as_mut())
            }
            DeviceServiceRequest::ListIfaces { responder } => {
                responder.send(&mut list_ifaces(&ifaces))
            }
            DeviceServiceRequest::QueryIface { iface_id, responder } => {
                let result = query_iface(&ifaces, iface_id);
                let (status, mut response) = into_status_and_opt(result);
                responder.send(status.into_raw(), response.as_mut())
            }
            DeviceServiceRequest::CreateIface { req, responder } => {
                match create_iface(&iface_counter, &phys, req).await {
                    Ok(new_iface) => {
                        info!("iface #{} started ({:?})", new_iface.id, new_iface.phy_ownership);
                        let iface_id = new_iface.id;

                        let inspect_tree = inspect_tree.clone();
                        let iface_tree_holder = inspect_tree.create_iface_child(iface_id);

                        let device_info = match new_iface.mlme_channel.query_device_info().await {
                            Ok(device_info) => device_info,
                            Err(e) => {
                                responder.send(zx::sys::ZX_ERR_PEER_CLOSED, None.as_mut())?;
                                return Err(e.into());
                            }
                        };

                        let serve_sme_fut = device::create_and_serve_sme(
                            cfg.clone(),
                            iface_id,
                            new_iface.phy_ownership,
                            new_iface.mlme_channel,
                            ifaces.clone(),
                            inspect_tree.clone(),
                            iface_tree_holder,
                            cobalt_sender.clone(),
                            device_info,
                        )?;

                        let resp = fidl_svc::CreateIfaceResponse { iface_id };
                        responder.send(zx::sys::ZX_OK, Some(resp).as_mut())?;

                        let serve_sme_fut = serve_sme_fut.map(move |result| {
                            let msg = match result {
                                Ok(()) => {
                                    let msg = format!("iface {} shutdown gracefully", iface_id);
                                    info!("{}", msg);
                                    msg
                                }
                                Err(e) => {
                                    let msg = format!("error serving iface {}: {}", iface_id, e);
                                    error!("{}", msg);
                                    msg
                                }
                            };
                            inspect_log!(inspect_tree.device_events.lock(), msg: msg);
                            inspect_tree.notify_iface_removed(iface_id);
                        });
                        fasync::Task::spawn(serve_sme_fut).detach();
                        Ok(())
                    }
                    Err(status) => responder.send(status.into_raw(), None),
                }
            }
            DeviceServiceRequest::DestroyIface { req, responder } => {
                let result = destroy_iface(&phys, &ifaces, req.iface_id).await;
                let status = into_status_and_opt(result).0;
                responder.send(status.into_raw())
            }
            DeviceServiceRequest::GetClientSme { iface_id, sme, responder } => {
                let status = get_client_sme(&ifaces, iface_id, sme);
                responder.send(status.into_raw())
            }
            DeviceServiceRequest::GetApSme { iface_id, sme, responder } => {
                let status = get_ap_sme(&ifaces, iface_id, sme);
                responder.send(status.into_raw())
            }
            DeviceServiceRequest::GetMeshSme { iface_id, sme, responder } => {
                let status = get_mesh_sme(&ifaces, iface_id, sme);
                responder.send(status.into_raw())
            }
            DeviceServiceRequest::GetIfaceStats { iface_id, responder } => {
                match get_iface_stats(&ifaces, iface_id).await {
                    Ok(stats_ref) => {
                        let mut stats = stats_ref.lock();
                        responder.send(zx::sys::ZX_OK, Some(&mut stats))
                    }
                    Err(status) => responder.send(status.into_raw(), None),
                }
            }
            DeviceServiceRequest::GetMinstrelList { iface_id, responder } => {
                let (status, mut peers) = list_minstrel_peers(&ifaces, iface_id).await;
                responder.send(status.into_raw(), &mut peers)
            }
            DeviceServiceRequest::GetMinstrelStats { iface_id, peer_addr, responder } => {
                let (status, mut peer) = get_minstrel_stats(&ifaces, iface_id, peer_addr).await;
                responder.send(status.into_raw(), peer.as_deref_mut())
            }
            DeviceServiceRequest::WatchDevices { watcher, control_handle: _ } => {
                watcher_service
                    .add_watcher(watcher)
                    .unwrap_or_else(|e| error!("error registering a device watcher: {}", e));
                Ok(())
            }
            DeviceServiceRequest::GetCountry { phy_id, responder } => responder
                .send(&mut get_country(&phys, phy_id).await.map_err(|status| status.into_raw())),
            DeviceServiceRequest::SetCountry { req, responder } => {
                let status = set_country(&phys, req).await;
                responder.send(status.into_raw())
            }
            DeviceServiceRequest::ClearCountry { req, responder } => {
                let status = clear_country(&phys, req).await;
                responder.send(status.into_raw())
            }
        }?;
    }
    Ok(())
}

fn into_status_and_opt<T>(r: Result<T, zx::Status>) -> (zx::Status, Option<T>) {
    match r {
        Ok(x) => (zx::Status::OK, Some(x)),
        Err(status) => (status, None),
    }
}

fn list_phys(phys: &PhyMap) -> fidl_svc::ListPhysResponse {
    let list = phys
        .get_snapshot()
        .iter()
        .map(|(phy_id, phy)| fidl_svc::PhyListItem {
            phy_id: *phy_id,
            path: phy.device.path().to_string_lossy().into_owned(),
        })
        .collect();
    fidl_svc::ListPhysResponse { phys: list }
}

async fn query_phy(phys: &PhyMap, id: u16) -> Result<fidl_svc::QueryPhyResponse, zx::Status> {
    info!("query_phy(id = {})", id);
    let phy = phys.get(&id).ok_or(zx::Status::NOT_FOUND)?;
    let query_result = phy.proxy.query().await.map_err(move |e| {
        error!("query_phy(id = {}): error sending 'Query' request to phy: {}", id, e);
        zx::Status::INTERNAL
    })?;
    info!("query_phy(id = {}): received a 'QueryResult' from device", id);
    zx::Status::ok(query_result.status)?;
    let mut info = query_result.info;
    info.id = id;
    info.dev_path = Some(phy.device.path().to_string_lossy().into_owned());
    Ok(fidl_svc::QueryPhyResponse { info })
}

fn list_ifaces(ifaces: &IfaceMap) -> fidl_svc::ListIfacesResponse {
    let list = ifaces
        .get_snapshot()
        .iter()
        .map(|(iface_id, _iface)| fidl_svc::IfaceListItem { iface_id: *iface_id })
        .collect();
    fidl_svc::ListIfacesResponse { ifaces: list }
}

async fn destroy_iface<'a>(
    phys: &'a PhyMap,
    ifaces: &'a IfaceMap,
    id: u16,
) -> Result<(), zx::Status> {
    info!("destroy_iface(id = {})", id);
    let iface = ifaces.get(&id).ok_or(zx::Status::NOT_FOUND)?;
    let phy_ownership = &iface.phy_ownership;

    // Shutdown the corresponding SME first. We don't want to send requests to MLME while we're mid-shutdown.
    if let Err(e) = iface.shutdown_sender.clone().send(()).await {
        error!("Error shutting down SME before iface removal: {:?}", e);
    }

    let phy = phys.get(&phy_ownership.phy_id).ok_or(zx::Status::NOT_FOUND)?;
    let mut phy_req = fidl_wlan_dev::DestroyIfaceRequest { id: phy_ownership.phy_assigned_id };
    let r = phy.proxy.destroy_iface(&mut phy_req).await.map_err(move |e| {
        error!("Error sending 'DestroyIface' request to phy {:?}: {}", phy_ownership, e);
        zx::Status::INTERNAL
    })?;
    let () = zx::Status::ok(r.status)?;

    ifaces.remove(&id);
    Ok(())
}

fn query_iface(ifaces: &IfaceMap, id: u16) -> Result<fidl_svc::QueryIfaceResponse, zx::Status> {
    info!("query_iface(id = {})", id);
    let iface = ifaces.get(&id).ok_or(zx::Status::NOT_FOUND)?;

    let role = match iface.device_info.role {
        fidl_mlme::MacRole::Client => fidl_wlan_dev::MacRole::Client,
        fidl_mlme::MacRole::Ap => fidl_wlan_dev::MacRole::Ap,
        fidl_mlme::MacRole::Mesh => fidl_wlan_dev::MacRole::Mesh,
    };

    let phy_id = iface.phy_ownership.phy_id;
    let phy_assigned_id = iface.phy_ownership.phy_assigned_id;
    let mac_addr = iface.device_info.mac_addr;
    Ok(fidl_svc::QueryIfaceResponse { role, id, mac_addr, phy_id, phy_assigned_id })
}

async fn get_country(
    phys: &PhyMap,
    phy_id: u16,
) -> Result<fidl_svc::GetCountryResponse, zx::Status> {
    let phy = phys.get(&phy_id).ok_or(Err(zx::Status::NOT_FOUND))?;
    match phy.proxy.get_country().await {
        Ok(result) => match result {
            Ok(country_code) => Ok(fidl_svc::GetCountryResponse { alpha2: country_code.alpha2 }),
            Err(status) => Err(zx::Status::from_raw(status)),
        },
        Err(e) => {
            error!("Error sending 'GetCountry' request to phy #{}: {}", phy_id, e);
            Err(zx::Status::INTERNAL)
        }
    }
}

async fn set_country(phys: &PhyMap, req: fidl_svc::SetCountryRequest) -> zx::Status {
    let phy_id = req.phy_id;
    let phy = match phys.get(&req.phy_id) {
        None => return zx::Status::NOT_FOUND,
        Some(p) => p,
    };

    let mut phy_req = fidl_wlan_dev::CountryCode { alpha2: req.alpha2 };
    match phy.proxy.set_country(&mut phy_req).await {
        Ok(status) => zx::Status::from_raw(status),
        Err(e) => {
            error!("Error sending SetCountry set_country request to phy #{}: {}", phy_id, e);
            zx::Status::INTERNAL
        }
    }
}

async fn clear_country(phys: &PhyMap, req: fidl_svc::ClearCountryRequest) -> zx::Status {
    let phy = match phys.get(&req.phy_id) {
        None => return zx::Status::NOT_FOUND,
        Some(p) => p,
    };

    match phy.proxy.clear_country().await {
        Ok(status) => zx::Status::from_raw(status),
        Err(e) => {
            error!(
                "Error sending ClearCountry clear_country request to phy #{}: {}",
                req.phy_id, e
            );
            zx::Status::INTERNAL
        }
    }
}

async fn create_iface<'a>(
    iface_counter: &'a IfaceCounter,
    phys: &'a PhyMap,
    req: fidl_svc::CreateIfaceRequest,
) -> Result<NewIface, zx::Status> {
    let phy_id = req.phy_id;
    let phy = phys.get(&req.phy_id).ok_or(zx::Status::NOT_FOUND)?;

    let (mlme_channel, sme_channel) = create_proxy::<MlmeMarker>()
        .map_err(|e| {
            error!("failed to create MlmeProxy: {}", e);
            zx::Status::INTERNAL
        })
        .map(|(p, c)| (p, Some(c.into_channel())))?;

    let mut phy_req = fidl_wlan_dev::CreateIfaceRequest {
        role: req.role,
        sme_channel,
        init_mac_addr: req.mac_addr,
    };
    let r = phy.proxy.create_iface(&mut phy_req).await.map_err(move |e| {
        error!("Error sending 'CreateIface' request to phy #{}: {}", phy_id, e);
        zx::Status::INTERNAL
    })?;
    zx::Status::ok(r.status)?;

    Ok(NewIface {
        id: iface_counter.next_iface_id() as u16,
        phy_ownership: device::PhyOwnership { phy_id, phy_assigned_id: r.iface_id },
        mlme_channel,
    })
}

fn get_client_sme(
    ifaces: &IfaceMap,
    iface_id: u16,
    endpoint: station::client::Endpoint,
) -> zx::Status {
    let iface = ifaces.get(&iface_id);
    let server = match iface {
        None => return zx::Status::NOT_FOUND,
        Some(ref iface) => match iface.sme_server {
            device::SmeServer::Client(ref server) => server,
            _ => return zx::Status::NOT_SUPPORTED,
        },
    };
    match server.unbounded_send(endpoint) {
        Ok(()) => zx::Status::OK,
        Err(e) => {
            error!("error sending an endpoint to the SME server future: {}", e);
            zx::Status::INTERNAL
        }
    }
}

fn get_ap_sme(ifaces: &IfaceMap, iface_id: u16, endpoint: station::ap::Endpoint) -> zx::Status {
    let iface = ifaces.get(&iface_id);
    let server = match iface {
        None => return zx::Status::NOT_FOUND,
        Some(ref iface) => match iface.sme_server {
            device::SmeServer::Ap(ref server) => server,
            _ => return zx::Status::NOT_SUPPORTED,
        },
    };
    match server.unbounded_send(endpoint) {
        Ok(()) => zx::Status::OK,
        Err(e) => {
            error!("error sending an endpoint to the SME server future: {}", e);
            zx::Status::INTERNAL
        }
    }
}

fn get_mesh_sme(ifaces: &IfaceMap, iface_id: u16, endpoint: station::mesh::Endpoint) -> zx::Status {
    let iface = ifaces.get(&iface_id);
    let server = match iface {
        None => return zx::Status::NOT_FOUND,
        Some(ref iface) => match iface.sme_server {
            device::SmeServer::Mesh(ref server) => server,
            _ => return zx::Status::NOT_SUPPORTED,
        },
    };
    match server.unbounded_send(endpoint) {
        Ok(()) => zx::Status::OK,
        Err(e) => {
            error!("error sending an endpoint to the SME server future: {}", e);
            zx::Status::INTERNAL
        }
    }
}

pub async fn get_iface_stats(ifaces: &IfaceMap, iface_id: u16) -> Result<StatsRef, zx::Status> {
    let iface = ifaces.get(&iface_id).ok_or(zx::Status::NOT_FOUND)?;
    iface.stats_sched.get_stats().await
}

async fn list_minstrel_peers(
    ifaces: &IfaceMap,
    iface_id: u16,
) -> (zx::Status, fidl_fuchsia_wlan_minstrel::Peers) {
    let empty_peer_list = fidl_fuchsia_wlan_minstrel::Peers { peers: vec![] };
    let iface = match ifaces.get(&iface_id) {
        Some(iface) => iface,
        None => return (zx::Status::NOT_FOUND, empty_peer_list),
    };
    match iface.mlme_query.get_minstrel_list().await {
        Ok(resp) => (zx::Status::OK, resp.peers),
        Err(_) => (zx::Status::INTERNAL, empty_peer_list),
    }
}

async fn get_minstrel_stats(
    ifaces: &IfaceMap,
    iface_id: u16,
    mac_addr: [u8; 6],
) -> (zx::Status, Option<Box<fidl_fuchsia_wlan_minstrel::Peer>>) {
    let iface = match ifaces.get(&iface_id) {
        Some(iface) => iface,
        None => return (zx::Status::NOT_FOUND, None),
    };
    match iface.mlme_query.get_minstrel_peer(mac_addr).await {
        Ok(MinstrelStatsResponse { peer }) => (zx::Status::OK, peer),
        Err(_) => (zx::Status::INTERNAL, None),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use fidl::endpoints::ServerEnd;
    use fidl_fuchsia_wlan_device::{self as fidl_dev, PhyRequest, PhyRequestStream};
    use fidl_fuchsia_wlan_device_service::{IfaceListItem, PhyListItem};
    use fidl_fuchsia_wlan_mlme::{self as fidl_mlme, MlmeMarker};
    use fidl_fuchsia_wlan_sme as fidl_sme;
    use fuchsia_async as fasync;
    use fuchsia_inspect::Inspector;
    use fuchsia_zircon as zx;
    use futures::channel::mpsc;
    use futures::future::BoxFuture;
    use futures::task::Poll;
    use pin_utils::pin_mut;
    use wlan_common::{
        assert_variant,
        channel::{Cbw, Phy},
        RadioConfig,
    };
    use wlan_dev::DeviceEnv;

    use crate::{
        mlme_query_proxy::MlmeQueryProxy,
        stats_scheduler::{self, StatsRequest},
        watcher_service,
    };

    #[test]
    fn iface_counter() {
        let iface_counter = IfaceCounter::new();
        assert_eq!(0, iface_counter.next_iface_id());
        assert_eq!(1, iface_counter.next_iface_id());
        assert_eq!(2, iface_counter.next_iface_id());
        assert_eq!(3, iface_counter.next_iface_id());
    }

    #[test]
    fn list_two_phys() {
        let _exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);
        let (phy_null, _phy_null_stream) = fake_phy("/dev/null");
        let (phy_zero, _phy_zero_stream) = fake_phy("/dev/zero");
        phy_map.insert(10u16, phy_null);
        phy_map.insert(20u16, phy_zero);
        let mut list = super::list_phys(&phy_map).phys;
        list.sort_by_key(|p| p.phy_id);
        assert_eq!(
            vec![
                PhyListItem { phy_id: 10u16, path: "/dev/null".to_string() },
                PhyListItem { phy_id: 20u16, path: "/dev/zero".to_string() },
            ],
            list
        )
    }

    #[test]
    fn query_phy_success() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);
        let (phy, mut phy_stream) = fake_phy("/dev/null");
        phy_map.insert(10u16, phy);

        // Initiate a QueryPhy request. The returned future should not be able
        // to produce a result immediately
        let query_fut = super::query_phy(&phy_map, 10u16);
        pin_mut!(query_fut);
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut query_fut));

        // The call above should trigger a Query message to the phy.
        // Pretend that we are the phy and read the message from the other side.
        let responder = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::Query { responder }))) => responder
        );

        // Reply with a fake phy info
        responder
            .send(&mut fidl_wlan_dev::QueryResponse {
                status: zx::sys::ZX_OK,
                info: fake_phy_info(),
            })
            .expect("failed to send QueryResponse");

        // Our original future should complete now, and return the same phy info
        let response = assert_variant!(exec.run_until_stalled(&mut query_fut),
            Poll::Ready(Ok(response)) => response
        );
        assert_eq!(fake_phy_info(), response.info);
    }

    #[test]
    fn query_phy_not_found() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);

        let query_fut = super::query_phy(&phy_map, 10u16);
        pin_mut!(query_fut);
        assert_eq!(Poll::Ready(Err(zx::Status::NOT_FOUND)), exec.run_until_stalled(&mut query_fut));
    }

    #[test]
    fn list_two_ifaces() {
        let _exec = fasync::Executor::new().expect("Failed to create an executor");
        let (iface_map, _iface_map_events) = IfaceMap::new();
        let iface_map = Arc::new(iface_map);
        let iface_null = fake_client_iface();
        let iface_zero = fake_client_iface();
        iface_map.insert(10u16, iface_null.iface);
        iface_map.insert(20u16, iface_zero.iface);
        let mut list = super::list_ifaces(&iface_map).ifaces;
        list.sort_by_key(|p| p.iface_id);
        assert_eq!(
            vec![IfaceListItem { iface_id: 10u16 }, IfaceListItem { iface_id: 20u16 },],
            list
        )
    }

    #[test]
    fn query_iface_success() {
        let _exec = fasync::Executor::new().expect("Failed to create an executor");

        let (iface_map, _iface_map_events) = IfaceMap::new();
        let iface_map = Arc::new(iface_map);
        let iface = fake_client_iface();
        iface_map.insert(10, iface.iface);

        let response = super::query_iface(&iface_map, 10).expect("querying iface failed");
        let expected = fake_device_info();
        assert_eq!(response.role, fidl_dev::MacRole::Client);
        assert_eq!(response.mac_addr, expected.mac_addr);
        assert_eq!(response.id, 10);
    }

    #[test]
    fn destroy_iface_success() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (mut phy_map, _phy_map_events) = PhyMap::new();
        let (mut iface_map, _iface_map_events) = IfaceMap::new();
        let mut phy_stream = fake_destroy_iface_env(&mut phy_map, &mut iface_map);

        let destroy_fut = super::destroy_iface(&phy_map, &iface_map, 42);
        pin_mut!(destroy_fut);
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut destroy_fut));

        let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::DestroyIface { req, responder }))) => (req, responder)
        );

        // Verify the destroy iface request to the corresponding PHY is correct.
        assert_eq!(13, req.id);

        responder
            .send(&mut fidl_wlan_dev::DestroyIfaceResponse { status: zx::sys::ZX_OK })
            .expect("failed to send DestroyIfaceResponse");
        assert_eq!(Poll::Ready(Ok(())), exec.run_until_stalled(&mut destroy_fut));

        // Verify iface was removed from available ifaces.
        assert!(iface_map.get(&42u16).is_none(), "iface expected to be deleted");
    }

    #[test]
    fn destroy_iface_failure() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (mut phy_map, _phy_map_events) = PhyMap::new();
        let (mut iface_map, _iface_map_events) = IfaceMap::new();
        let mut phy_stream = fake_destroy_iface_env(&mut phy_map, &mut iface_map);

        let destroy_fut = super::destroy_iface(&phy_map, &iface_map, 42);
        pin_mut!(destroy_fut);
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut destroy_fut));

        let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::DestroyIface { req, responder }))) => (req, responder)
        );

        // Verify the destroy iface request to the corresponding PHY is correct.
        assert_eq!(13, req.id);

        responder
            .send(&mut fidl_wlan_dev::DestroyIfaceResponse { status: zx::sys::ZX_ERR_INTERNAL })
            .expect("failed to send DestroyIfaceResponse");
        assert_eq!(
            Poll::Ready(Err(zx::Status::INTERNAL)),
            exec.run_until_stalled(&mut destroy_fut)
        );

        // Verify iface was not removed from available ifaces.
        assert!(iface_map.get(&42u16).is_some(), "iface expected to not be deleted");
    }

    #[test]
    fn destroy_iface_not_found() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (mut phy_map, _phy_map_events) = PhyMap::new();
        let (mut iface_map, _iface_map_events) = IfaceMap::new();
        let _phy_stream = fake_destroy_iface_env(&mut phy_map, &mut iface_map);

        let fut = super::destroy_iface(&phy_map, &iface_map, 43);
        pin_mut!(fut);
        assert_eq!(Poll::Ready(Err(zx::Status::NOT_FOUND)), exec.run_until_stalled(&mut fut));
    }

    #[test]
    fn query_iface_not_found() {
        let (iface_map, _iface_map_events) = IfaceMap::new();
        let iface_map = Arc::new(iface_map);

        let status = super::query_iface(&iface_map, 10u16).expect_err("querying iface succeeded");
        assert_eq!(zx::Status::NOT_FOUND, status);
    }

    #[test]
    fn create_iface_without_mac_success() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);

        let (phy, mut phy_stream) = fake_phy("/dev/null");
        phy_map.insert(10, phy);

        // Initiate a CreateIface request. The returned future should not be able
        // to produce a result immediately
        let iface_counter = IfaceCounter::new_with_value(5);
        let create_fut = super::create_iface(
            &iface_counter,
            &phy_map,
            fidl_svc::CreateIfaceRequest {
                phy_id: 10,
                role: fidl_wlan_dev::MacRole::Client,
                mac_addr: None,
            },
        );
        pin_mut!(create_fut);
        let fut_result = exec.run_until_stalled(&mut create_fut);
        assert_variant!(fut_result, Poll::Pending);

        // Continue running create iface request.

        let fut_result = exec.run_until_stalled(&mut create_fut);
        assert_variant!(fut_result, Poll::Pending);

        let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::CreateIface { req, responder }))) => (req, responder)
        );

        // Since we requested the Client role, the request to the phy should also have
        // the Client role
        assert_eq!(fidl_wlan_dev::MacRole::Client, req.role);

        // Pretend that the interface was created with local id 123.
        responder
            .send(&mut fidl_wlan_dev::CreateIfaceResponse { status: zx::sys::ZX_OK, iface_id: 123 })
            .expect("failed to send CreateIfaceResponse");

        // The original future should resolve into a response.
        let response = assert_variant!(exec.run_until_stalled(&mut create_fut),
            Poll::Ready(Ok(response)) => response
        );

        assert_eq!(5, response.id);
        assert_eq!(
            device::PhyOwnership { phy_id: 10, phy_assigned_id: 123 },
            response.phy_ownership
        );

        // TODO(fxbug.dev/29547): response.mlme_channel use and talk to it
    }

    #[test]
    fn create_iface_with_mac_success() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);

        let (phy, mut phy_stream) = fake_phy("/dev/null");
        phy_map.insert(10, phy);

        // Initiate a CreateIface request. The returned future should not be able
        // to produce a result immediately
        let iface_counter = IfaceCounter::new_with_value(5);
        let mac_addr = Some(vec![1, 2, 3, 4, 5, 6]);

        let create_fut = super::create_iface(
            &iface_counter,
            &phy_map,
            fidl_svc::CreateIfaceRequest { phy_id: 10, role: fidl_wlan_dev::MacRole::Ap, mac_addr },
        );
        pin_mut!(create_fut);
        assert_variant!(exec.run_until_stalled(&mut create_fut), Poll::Pending);

        // Continue running create iface request.
        assert_variant!(exec.run_until_stalled(&mut create_fut), Poll::Pending);

        let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::CreateIface { req, responder }))) => (req, responder)
        );

        // Since we requested the Ap role, the request to the phy should also have
        // the Ap role
        assert_eq!(fidl_wlan_dev::MacRole::Ap, req.role);
        let res = match req.init_mac_addr {
            None => false,
            Some(mac_addr) => {
                assert_eq!(mac_addr, [1, 2, 3, 4, 5, 6]);
                true
            }
        };
        assert!(res);

        // Pretend that the interface was created with local id 123.
        responder
            .send(&mut fidl_wlan_dev::CreateIfaceResponse { status: zx::sys::ZX_OK, iface_id: 123 })
            .expect("failed to send CreateIfaceResponse");

        // The original future should resolve into a response.
        let response = assert_variant!(exec.run_until_stalled(&mut create_fut),
            Poll::Ready(Ok(response)) => response
        );

        assert_eq!(5, response.id);
        assert_eq!(
            device::PhyOwnership { phy_id: 10, phy_assigned_id: 123 },
            response.phy_ownership
        );
    }

    #[test]
    fn create_iface_not_found() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);

        let iface_counter = IfaceCounter::new_with_value(2);
        let fut = super::create_iface(
            &iface_counter,
            &phy_map,
            fidl_svc::CreateIfaceRequest {
                phy_id: 10,
                role: fidl_wlan_dev::MacRole::Client,
                mac_addr: None,
            },
        );
        pin_mut!(fut);
        assert_variant!(
            exec.run_until_stalled(&mut fut),
            Poll::Ready(Err(zx::Status::NOT_FOUND)),
            "expected failure on invalid PHY"
        );
    }

    #[test]
    fn get_client_sme_success() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (iface_map, _iface_map_events) = IfaceMap::new();
        let iface_map = Arc::new(iface_map);

        let mut iface = fake_client_iface();
        iface_map.insert(10, iface.iface);

        let (proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
        assert_eq!(zx::Status::OK, super::get_client_sme(&iface_map, 10, server));

        // Expect to get a new FIDL client in the stream
        let endpoint = iface
            .new_sme_clients
            .try_next()
            .expect("expected a message in new_sme_clients")
            .expect("didn't expect new_sme_clients stream to end");
        let mut sme_stream = endpoint.into_stream().expect("failed to create stream for endpoint");

        // Verify that `proxy` is indeed connected to `sme_stream`
        let (_scan_proxy, scan_txn) =
            create_proxy().expect("failed to create a pair of scan txn endpoints");
        proxy.scan(&mut fake_scan_request(), scan_txn).expect("failed to send a scan request");

        assert_variant!(exec.run_until_stalled(&mut sme_stream.next()),
            Poll::Ready(Some(Ok(fidl_sme::ClientSmeRequest::Scan { req, .. }))) => {
                assert_eq!(fake_scan_request(), req)
            }
        );
    }

    #[test]
    fn get_client_sme_not_found() {
        let mut _exec = fasync::Executor::new().expect("Failed to create an executor");
        let (iface_map, _iface_map_events) = IfaceMap::new();
        let iface_map = Arc::new(iface_map);

        let (_proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
        assert_eq!(zx::Status::NOT_FOUND, super::get_client_sme(&iface_map, 10, server));
    }

    #[test]
    fn get_client_sme_wrong_role() {
        let mut _exec = fasync::Executor::new().expect("Failed to create an executor");
        let (iface_map, _iface_map_events) = IfaceMap::new();
        let iface_map = Arc::new(iface_map);

        let iface = fake_ap_iface();
        iface_map.insert(10, iface.iface);

        let (_proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
        assert_eq!(zx::Status::NOT_SUPPORTED, super::get_client_sme(&iface_map, 10, server));
    }

    #[test]
    fn get_ap_sme_success() {
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (iface_map, _iface_map_events) = IfaceMap::new();
        let iface_map = Arc::new(iface_map);

        let mut iface = fake_ap_iface();
        iface_map.insert(10, iface.iface);

        let (proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
        assert_eq!(zx::Status::OK, super::get_ap_sme(&iface_map, 10, server));

        // Expect to get a new FIDL client in the stream
        let endpoint = iface
            .new_sme_clients
            .try_next()
            .expect("expected a message in new_sme_clients")
            .expect("didn't expect new_sme_clients stream to end");
        let mut sme_stream = endpoint.into_stream().expect("failed to create stream for endpoint");

        // Verify that `proxy` is indeed connected to `sme_stream`
        let mut fut = fidl_sme::ApSmeProxyInterface::start(&proxy, &mut fake_ap_config());

        assert_variant!(exec.run_until_stalled(&mut sme_stream.next()),
            Poll::Ready(Some(Ok(fidl_sme::ApSmeRequest::Start { config, responder }))) => {
                assert_eq!(fake_ap_config(), config);
                responder
                    .send(fidl_sme::StartApResultCode::Success)
                    .expect("failed to send response");
            }
        );

        let fut_result = exec.run_until_stalled(&mut fut);
        assert_variant!(fut_result, Poll::Ready(Ok(fidl_sme::StartApResultCode::Success)));
    }

    #[test]
    fn get_ap_sme_not_found() {
        let mut _exec = fasync::Executor::new().expect("Failed to create an executor");
        let (iface_map, _iface_map_events) = IfaceMap::new();
        let iface_map = Arc::new(iface_map);

        let (_proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
        assert_eq!(zx::Status::NOT_FOUND, super::get_ap_sme(&iface_map, 10, server));
    }

    #[test]
    fn get_ap_sme_wrong_role() {
        let mut _exec = fasync::Executor::new().expect("Failed to create an executor");
        let (iface_map, _iface_map_events) = IfaceMap::new();
        let iface_map = Arc::new(iface_map);

        let iface = fake_client_iface();
        iface_map.insert(10, iface.iface);

        let (_proxy, server) = create_proxy().expect("failed to create a pair of SME endpoints");
        assert_eq!(zx::Status::NOT_SUPPORTED, super::get_ap_sme(&iface_map, 10, server));
    }

    #[test]
    fn test_set_country() {
        // Setup environment
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);
        let (phy, mut phy_stream) = fake_phy("/dev/null");
        let phy_id = 10u16;
        phy_map.insert(phy_id, phy);
        let alpha2 = fake_alpha2();

        // Initiate a QueryPhy request. The returned future should not be able
        // to produce a result immediately
        // Issue service.fidl::SetCountryRequest()
        let req_msg = fidl_svc::SetCountryRequest { phy_id, alpha2: alpha2.clone() };
        let req_fut = super::set_country(&phy_map, req_msg);
        pin_mut!(req_fut);
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));

        assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::SetCountry { req, responder }))) => {
                assert_eq!(req.alpha2, alpha2.clone());
                // Pretend to be a WLAN PHY to return the result.
                responder.send(zx::Status::OK.into_raw())
                    .expect("failed to send the response to SetCountry");
            }
        );

        // req_fut should have completed by now. Test the result.
        assert_eq!(exec.run_until_stalled(&mut req_fut), Poll::Ready(zx::Status::OK));
    }

    #[test]
    fn test_set_country_failure() {
        // Setup environment
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);
        let (phy, mut phy_stream) = fake_phy("/dev/null");
        let phy_id = 10u16;
        phy_map.insert(phy_id, phy);
        let alpha2 = fake_alpha2();

        // Initiate a QueryPhy request. The returned future should not be able
        // to produce a result immediately
        // Issue service.fidl::SetCountryRequest()
        let req_msg = fidl_svc::SetCountryRequest { phy_id, alpha2: alpha2.clone() };
        let req_fut = super::set_country(&phy_map, req_msg);
        pin_mut!(req_fut);
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));

        let (req, responder) = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::SetCountry { req, responder }))) => (req, responder)
        );
        assert_eq!(req.alpha2, alpha2.clone());

        // Failure case #1: WLAN PHY not responding
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));

        // Failure case #2: WLAN PHY has not implemented the feature.
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
        let resp = zx::Status::NOT_SUPPORTED.into_raw();
        responder.send(resp).expect("failed to send the response to SetCountry");
        assert_eq!(Poll::Ready(zx::Status::NOT_SUPPORTED), exec.run_until_stalled(&mut req_fut));
    }

    #[test]
    fn test_get_country() {
        // Setup environment
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);
        let (phy, mut phy_stream) = fake_phy("/dev/null");
        let phy_id = 10u16;
        phy_map.insert(phy_id, phy);
        let alpha2 = fake_alpha2();

        // Initiate a QueryPhy request. The returned future should not be able
        // to produce a result immediately
        // Issue service.fidl::SetCountryRequest()
        let req_fut = super::get_country(&phy_map, phy_id);
        pin_mut!(req_fut);
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));

        assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::GetCountry { responder }))) => {
                // Pretend to be a WLAN PHY to return the result.
                responder.send(
                    &mut Ok(fidl_wlan_dev::CountryCode { alpha2 })
                ).expect("failed to send the response to SetCountry");
            }
        );

        assert_eq!(
            exec.run_until_stalled(&mut req_fut),
            Poll::Ready(Ok(fidl_svc::GetCountryResponse { alpha2 }))
        );
    }

    #[test]
    fn test_get_country_failure() {
        // Setup environment
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);
        let (phy, mut phy_stream) = fake_phy("/dev/null");
        let phy_id = 10u16;
        phy_map.insert(phy_id, phy);

        // Initiate a QueryPhy request. The returned future should not be able
        // to produce a result immediately
        // Issue service.fidl::GetCountryRequest()
        let req_fut = super::get_country(&phy_map, phy_id);
        pin_mut!(req_fut);
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));

        assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::GetCountry { responder }))) => {
                // Pretend to be a WLAN PHY to return the result.
                // Right now the returned country code is not optional, so we just return garbage.
                responder.send(&mut Err(zx::Status::NOT_SUPPORTED.into_raw()))
                    .expect("failed to send the response to SetCountry");
            }
        );

        assert_variant!(exec.run_until_stalled(&mut req_fut), Poll::Ready(Err(_)));
    }

    #[test]
    fn test_clear_country() {
        // Setup environment
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);
        let (phy, mut phy_stream) = fake_phy("/dev/null");
        let phy_id = 10u16;
        phy_map.insert(phy_id, phy);

        // Initiate a QueryPhy request. The returned future should not be able
        // to produce a result immediately
        // Issue service.fidl::ClearCountryRequest()
        let req_msg = fidl_svc::ClearCountryRequest { phy_id };
        let req_fut = super::clear_country(&phy_map, req_msg);
        pin_mut!(req_fut);
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));

        assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::ClearCountry { responder }))) => {
                // Pretend to be a WLAN PHY to return the result.
                responder.send(zx::Status::OK.into_raw())
                    .expect("failed to send the response to ClearCountry");
            }
        );

        // req_fut should have completed by now. Test the result.
        assert_eq!(exec.run_until_stalled(&mut req_fut), Poll::Ready(zx::Status::OK));
    }

    #[test]
    fn test_clear_country_failure() {
        // Setup environment
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phy_map, _phy_map_events) = PhyMap::new();
        let phy_map = Arc::new(phy_map);
        let (phy, mut phy_stream) = fake_phy("/dev/null");
        let phy_id = 10u16;
        phy_map.insert(phy_id, phy);

        // Initiate a QueryPhy request. The returned future should not be able
        // to produce a result immediately
        // Issue service.fidl::ClearCountryRequest()
        let req_msg = fidl_svc::ClearCountryRequest { phy_id };
        let req_fut = super::clear_country(&phy_map, req_msg);
        pin_mut!(req_fut);
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));

        let responder = assert_variant!(exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::ClearCountry { responder }))) => responder
        );

        // Failure case #1: WLAN PHY not responding
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));

        // Failure case #2: WLAN PHY has not implemented the feature.
        assert_eq!(Poll::Pending, exec.run_until_stalled(&mut req_fut));
        let resp = zx::Status::NOT_SUPPORTED.into_raw();
        responder.send(resp).expect("failed to send the response to ClearCountry");
        assert_eq!(Poll::Ready(zx::Status::NOT_SUPPORTED), exec.run_until_stalled(&mut req_fut));
    }

    fn setup_create_iface_test() -> (
        fasync::Executor,
        BoxFuture<'static, Result<(), anyhow::Error>>,
        BoxFuture<'static, Result<(i32, Option<Box<fidl_svc::CreateIfaceResponse>>), fidl::Error>>,
        impl Future<Output = Result<void::Void, anyhow::Error>>,
        fidl_wlan_dev::CreateIfaceRequest,
    ) {
        let fake_phy_id = 10;
        let mut exec = fasync::Executor::new().expect("Failed to create an executor");
        let (phys, phy_events) = device::PhyMap::new();
        let (ifaces, iface_events) = device::IfaceMap::new();

        let iface_counter = Arc::new(IfaceCounter::new());
        let cfg: ServiceCfg = argh::from_env();
        let phys = Arc::new(phys);
        let ifaces = Arc::new(ifaces);
        let (watcher_service, watcher_fut) =
            watcher_service::serve_watchers(phys.clone(), ifaces.clone(), phy_events, iface_events);

        // Insert a fake PHY
        let (phy, mut phy_stream) = fake_phy("/dev/null");
        phys.insert(fake_phy_id, phy);

        // Create a CobaltSender with a dangling receiver end.
        let (cobalt_sender, _cobalt_receiver) = mpsc::channel(1);
        let cobalt_sender = CobaltSender::new(cobalt_sender);

        // Create an inspector, but don't serve.
        let inspect_tree = Arc::new(inspect::WlanstackTree::new(Inspector::new()));

        let (proxy, marker) =
            create_proxy::<fidl_svc::DeviceServiceMarker>().expect("failed to create proxy");
        let req_stream = marker.into_stream().expect("could not create request stream");

        let fut = serve_device_requests(
            iface_counter,
            cfg,
            phys,
            ifaces,
            watcher_service,
            req_stream,
            inspect_tree,
            cobalt_sender,
        );

        let mut fut = Box::pin(fut);

        // Make the CreateIface request
        let mut create_iface_request = fidl_svc::CreateIfaceRequest {
            phy_id: fake_phy_id,
            role: fidl_wlan_dev::MacRole::Ap,
            mac_addr: None,
        };
        let create_iface_fut = proxy.create_iface(&mut create_iface_request);
        let mut create_iface_fut = Box::pin(create_iface_fut);

        assert_variant!(exec.run_until_stalled(&mut create_iface_fut), Poll::Pending);

        // Advance the server so that it gets the CreateIfaceRequest
        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);

        // There should be a pending CreateIfaceRequest. Send it a response and capture its request
        // so that the MLME channel associated with the request can be used to inject a successful
        // MLME response when the PHY's information is queried.
        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
        let (phy_create_iface_req, responder) = assert_variant!(
            exec.run_until_stalled(&mut phy_stream.next()),
            Poll::Ready(Some(Ok(PhyRequest::CreateIface { req, responder }))) => (req, responder)
        );
        responder
            .send(&mut fidl_wlan_dev::CreateIfaceResponse { status: zx::sys::ZX_OK, iface_id: 0 })
            .expect("failed to send CreateIfaceResponse");

        (exec, fut, create_iface_fut, watcher_fut, phy_create_iface_req)
    }

    #[test]
    fn test_query_device_info_succeeds() {
        let (mut exec, mut fut, mut create_iface_fut, _watcher_fut, phy_create_iface_req) =
            setup_create_iface_test();

        // Use the channel that is included in the CreateIfaceRequest to create an MLME request
        // stream.
        let mlme_channel =
            phy_create_iface_req.sme_channel.expect("no mlme stream found in iface request");
        let mut mlme_stream = ServerEnd::<fidl_mlme::MlmeMarker>::new(mlme_channel)
            .into_stream()
            .expect("could not create MLME event stream");

        // Run the server's future so that it can query device information.
        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
        assert_variant!(
            exec.run_until_stalled(&mut mlme_stream.next()),
            Poll::Ready(Some(Ok(fidl_mlme::MlmeRequest::QueryDeviceInfo{ responder } ))) => {
                assert!(responder.send(&mut fake_device_info()).is_ok());
            }
        );

        // Run the query future to completion and expect an Ok result.
        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
        assert_variant!(
            exec.run_until_stalled(&mut create_iface_fut),
            Poll::Ready(Ok((status, Some(response)))) => {
                assert_eq!(status, zx::sys::ZX_OK);
                assert_eq!(*response, fidl_svc::CreateIfaceResponse { iface_id: 0 });
            }
        );
    }

    #[test]
    fn test_query_device_info_fails() {
        // Drop the CreateIfaceRequest to terminate the serving end of the MLME transaction.
        let (mut exec, mut fut, mut create_iface_fut, _watcher_fut, create_iface_req) =
            setup_create_iface_test();
        drop(create_iface_req);

        // Run the server's future so that it can fail to query the device information.
        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
        assert_variant!(
            exec.run_until_stalled(&mut create_iface_fut),
            Poll::Ready(Ok((zx::sys::ZX_ERR_PEER_CLOSED, None)))
        );
    }

    fn fake_destroy_iface_env(phy_map: &mut PhyMap, iface_map: &mut IfaceMap) -> PhyRequestStream {
        let (phy, phy_stream) = fake_phy("/dev/null");
        phy_map.insert(10, phy);

        // Insert device which does not support destruction.
        let iface = fake_client_iface();
        iface_map.insert(10, iface.iface);

        // Insert device which does support destruction.
        let iface = fake_client_iface();
        let iface = FakeClientIface {
            iface: IfaceDevice {
                phy_ownership: device::PhyOwnership { phy_id: 10, phy_assigned_id: 13 },
                ..iface.iface
            },
            ..iface
        };
        iface_map.insert(42, iface.iface);

        phy_stream
    }

    fn fake_phy(path: &str) -> (PhyDevice, PhyRequestStream) {
        let (proxy, server) =
            create_proxy::<fidl_wlan_dev::PhyMarker>().expect("fake_phy: create_proxy() failed");
        let device = wlan_dev::RealDeviceEnv::device_from_path(path)
            .expect(&format!("fake_phy: failed to open {}", path));
        let stream = server.into_stream().expect("fake_phy: failed to create stream");
        (PhyDevice { proxy, device }, stream)
    }

    struct FakeClientIface<St: Stream<Item = StatsRequest>> {
        iface: IfaceDevice,
        _stats_requests: St,
        new_sme_clients: mpsc::UnboundedReceiver<station::client::Endpoint>,
    }

    fn fake_client_iface() -> FakeClientIface<impl Stream<Item = StatsRequest>> {
        let (sme_sender, sme_receiver) = mpsc::unbounded();
        let (stats_sched, stats_requests) = stats_scheduler::create_scheduler();
        let (proxy, _server) = create_proxy::<MlmeMarker>().expect("Error creating proxy");
        let (shutdown_sender, _) = mpsc::channel(1);
        let mlme_query = MlmeQueryProxy::new(proxy);
        let device_info = fake_device_info();
        let iface = IfaceDevice {
            phy_ownership: device::PhyOwnership { phy_id: 0, phy_assigned_id: 0 },
            sme_server: device::SmeServer::Client(sme_sender),
            stats_sched,
            mlme_query,
            device_info,
            shutdown_sender,
        };
        FakeClientIface { iface, _stats_requests: stats_requests, new_sme_clients: sme_receiver }
    }

    struct FakeApIface<St: Stream<Item = StatsRequest>> {
        iface: IfaceDevice,
        _stats_requests: St,
        new_sme_clients: mpsc::UnboundedReceiver<station::ap::Endpoint>,
    }

    fn fake_ap_iface() -> FakeApIface<impl Stream<Item = StatsRequest>> {
        let (sme_sender, sme_receiver) = mpsc::unbounded();
        let (stats_sched, stats_requests) = stats_scheduler::create_scheduler();
        let (proxy, _server) = create_proxy::<MlmeMarker>().expect("Error creating proxy");
        let mlme_query = MlmeQueryProxy::new(proxy);
        let (shutdown_sender, _) = mpsc::channel(1);
        let device_info = fake_device_info();
        let iface = IfaceDevice {
            phy_ownership: device::PhyOwnership { phy_id: 0, phy_assigned_id: 0 },
            sme_server: device::SmeServer::Ap(sme_sender),
            stats_sched,
            mlme_query,
            device_info,
            shutdown_sender,
        };
        FakeApIface { iface, _stats_requests: stats_requests, new_sme_clients: sme_receiver }
    }

    fn fake_phy_info() -> fidl_wlan_dev::PhyInfo {
        fidl_wlan_dev::PhyInfo {
            id: 10,
            dev_path: Some("/dev/null".to_string()),
            hw_mac_address: [0x67, 0x62, 0x6f, 0x6e, 0x69, 0x6b],
            supported_phys: Vec::new(),
            driver_features: Vec::new(),
            mac_roles: Vec::new(),
            caps: Vec::new(),
            bands: Vec::new(),
        }
    }

    fn fake_device_info() -> fidl_mlme::DeviceInfo {
        fidl_mlme::DeviceInfo {
            role: fidl_mlme::MacRole::Client,
            bands: vec![],
            mac_addr: [0xAC; 6],
            driver_features: vec![],
            qos_capable: false,
        }
    }

    fn fake_scan_request() -> fidl_sme::ScanRequest {
        fidl_sme::ScanRequest::Passive(fidl_sme::PassiveScanRequest {})
    }

    fn fake_ap_config() -> fidl_sme::ApConfig {
        fidl_sme::ApConfig {
            ssid: b"qwerty".to_vec(),
            password: vec![],
            radio_cfg: RadioConfig::new(Phy::Ht, Cbw::Cbw20, 6).to_fidl(),
        }
    }

    fn fake_alpha2() -> [u8; 2] {
        let mut alpha2: [u8; 2] = [0, 0];
        alpha2.copy_from_slice("MX".as_bytes());
        alpha2
    }
}
