blob: d66712641b1d9644dcdaa8890674d61591bd0d1e [file] [log] [blame]
// Copyright 2019 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.
#![feature(async_await, await_macro, futures_api)]
#![deny(warnings)]
// Explicitly added due to conflict using custom_attribute and async_await above.
#[macro_use]
extern crate serde_derive;
mod opts;
use crate::opts::Opt;
use connectivity_testing::wlan_ap_service_util;
use connectivity_testing::wlan_service_util;
use failure::{bail, Error, ResultExt};
use fidl_fuchsia_wlan_device_service::{DeviceServiceMarker, DeviceServiceProxy};
use fidl_fuchsia_wlan_sme as fidl_sme;
use fuchsia_app::client::connect_to_service;
use fuchsia_async as fasync;
use fuchsia_syslog::{self as syslog, fx_log_err, fx_log_info};
use fuchsia_zircon as zx;
use std::collections::HashMap;
use std::process;
use structopt::StructOpt;
#[allow(dead_code)]
type WlanService = DeviceServiceProxy;
fn main() -> Result<(), Error> {
syslog::init_with_tags(&["wlan-ap-smoke-test"]).expect("should not fail");
let opt = Opt::from_args();
fx_log_info!("{:?}", opt);
// create objects to hold test objects and results
let mut test_results: TestResults = Default::default();
let mut test_pass = true;
if let Err(e) = run_test(opt, &mut test_results) {
test_pass = false;
test_results.error_message = e.to_string();
}
report_results(&mut test_results);
if !test_pass {
process::exit(1);
}
Ok(())
}
fn run_test(opt: Opt, test_results: &mut TestResults) -> Result<(), Error> {
let target_ssid = opt.target_ssid.as_bytes();
let target_pwd = opt.target_pwd.as_bytes();
let target_channel = opt.target_channel;
let mut test_pass = false;
let mut exec = fasync::Executor::new().context("error creating event loop")?;
let wlan_svc =
connect_to_service::<DeviceServiceMarker>().context("Failed to connect to wlan_service")?;
test_results.connect_to_wlan_service = true;
let fut = async {
let wlan_iface_ids = await!(wlan_service_util::get_iface_list(&wlan_svc))
.context("wlan-ap-smoke-test: failed to query wlanservice iface list")?;
test_results.query_wlan_service_iface_list = true;
if wlan_iface_ids.is_empty() {
bail!("Did not find wlan interfaces");
};
test_results.wlan_client_discovered = false;
test_results.wlan_ap_discovered = false;
// find MAC role supported by each interface
for iface in wlan_iface_ids {
let (status, response) =
await!(wlan_svc.query_iface(iface)).context("error querying iface")?;
if status == zx::sys::ZX_OK {
let query_iface_response = match response {
Some(response) => response,
_ => panic!("Expected a valid list response"),
};
if query_iface_response.role == fidl_fuchsia_wlan_device::MacRole::Client {
match await!(wlan_service_util::get_iface_sme_proxy(&wlan_svc, iface)) {
Ok(client_sme_proxy) => {
match await!(client_sme_proxy.status()) {
Ok(_status) => {
let mut wlan_client_ifaces =
WlanClientIface::new(client_sme_proxy);
wlan_client_ifaces.client_interface_status = true;
test_results.wlan_client_discovered = true;
test_results
.iface_client_objects
.insert(iface, wlan_client_ifaces);
}
Err(_) => {
continue;
}
};
}
Err(_) => {
continue;
}
}
}
if query_iface_response.role == fidl_fuchsia_wlan_device::MacRole::Ap {
match await!(wlan_ap_service_util::get_iface_ap_sme_proxy(&wlan_svc, iface)) {
Ok(ap_sme_proxy) => {
let mut wlan_ap_iface = WlanApIface::new(ap_sme_proxy);
wlan_ap_iface.ap_interface_status = true;
test_results.iface_ap_objects.insert(iface, wlan_ap_iface);
test_results.wlan_ap_discovered = true;
test_pass = true;
}
Err(_) => {
bail!("Expected a valid ap_sme_proxy for interface {:?}", iface);
}
}
}
}
}
// Go over all APs, create a network, have every client scan, connect and disconnect.
// When done, stop the AP.
for (ap_iface_id, wlan_ap_iface) in test_results.iface_ap_objects.iter_mut() {
let start_ap_result_code = await!(wlan_ap_service_util::start_ap(
&wlan_ap_iface.sme_proxy,
target_ssid.to_vec(),
target_pwd.to_vec(),
target_channel
));
match start_ap_result_code {
Ok(result_code) => match result_code {
fidl_sme::StartApResultCode::Success => {
fx_log_info!("AP started successfully");
wlan_ap_iface.ap_channel = target_channel;
wlan_ap_iface.ap_start_success = true;
}
_ => {
fx_log_err!("Error starting AP: {:?}", result_code);
test_pass = false;
continue;
}
},
_ => {
continue;
}
};
// Scan and look for a specific network
for (client_iface_id, wlan_client_iface) in test_results.iface_client_objects.iter_mut()
{
// Move on if it's the same interface
if ap_iface_id == client_iface_id {
continue;
}
let mut wlan_client_results = WlanClientResultsPerAP::new();
let scan_results_return =
await!(wlan_service_util::perform_scan(&wlan_client_iface.sme_proxy));
let scan_results = match scan_results_return {
Ok(scan_results) => scan_results,
Err(_) => {
test_pass = false;
wlan_client_results.found_ap_in_scan = false;
continue;
}
};
if scan_results.iter().find(|&ap| ap.best_bss.ssid == target_ssid.to_vec()) != None
{
wlan_client_results.found_ap_in_scan = true;
}
// Connect to network, if found in scan results
if wlan_client_results.found_ap_in_scan == true {
let connect_result = await!(wlan_service_util::connect_to_network(
&wlan_client_iface.sme_proxy,
target_ssid.to_vec(),
target_pwd.to_vec()
));
match connect_result {
Ok(true) => {
wlan_client_results.connection_success = true;
}
_ => continue,
};
}
// If connected, disconnect
if wlan_client_results.connection_success == true {
match await!(wlan_service_util::disconnect_from_network(
&wlan_client_iface.sme_proxy
)) {
Err(_) => wlan_client_results.disconnect_success = false,
_ => wlan_client_results.disconnect_success = true,
};
}
if wlan_ap_iface.ap_start_success
&& wlan_client_results.found_ap_in_scan
&& wlan_client_results.connection_success
&& wlan_client_results.disconnect_success
&& wlan_client_results.dhcp_success
&& wlan_client_results.data_transfer
&& test_pass == true
{
test_pass = true;
} else {
test_pass = false;
}
wlan_ap_iface.iface_client_results.insert(*client_iface_id, wlan_client_results);
}
if wlan_ap_iface.ap_start_success == true {
// Stop AP
let stop_ap_result =
await!(wlan_ap_service_util::stop_ap(&wlan_ap_iface.sme_proxy));
if stop_ap_result.is_ok() {
wlan_ap_iface.ap_stop_success = true;
} else {
println!("Couldn't stop AP on interface {:?}", ap_iface_id);
}
if test_pass == true && wlan_ap_iface.ap_stop_success == true {
test_pass = true;
}
}
}
Ok(())
};
exec.run_singlethreaded(fut)?;
if !test_pass {
bail!("Saw a failure on at least one interface");
}
Ok(())
}
// Object to hold overall test status
#[derive(Default, Serialize)]
struct TestResults {
connect_to_wlan_service: bool,
query_wlan_service_iface_list: bool,
wlan_ap_discovered: bool,
wlan_client_discovered: bool,
#[serde(flatten)]
iface_ap_objects: HashMap<u16, WlanApIface>,
#[serde(flatten)]
iface_client_objects: HashMap<u16, WlanClientIface>,
error_message: String,
}
// Object to hold test specific status
#[derive(Serialize)]
struct WlanClientIface {
#[serde(skip_serializing)]
sme_proxy: fidl_sme::ClientSmeProxy,
client_interface_status: bool,
}
impl WlanClientIface {
pub fn new(sme_proxy: fidl_sme::ClientSmeProxy) -> WlanClientIface {
WlanClientIface { sme_proxy: sme_proxy, client_interface_status: false }
}
}
// Object to hold test specific status
#[derive(Serialize)]
struct WlanClientResultsPerAP {
found_ap_in_scan: bool,
connection_success: bool,
disconnect_success: bool,
dhcp_success: bool,
data_transfer: bool,
}
impl WlanClientResultsPerAP {
pub fn new() -> WlanClientResultsPerAP {
WlanClientResultsPerAP {
found_ap_in_scan: false,
connection_success: false,
disconnect_success: false,
dhcp_success: false,
data_transfer: false,
}
}
}
#[derive(Serialize)]
struct WlanApIface {
#[serde(skip_serializing)]
sme_proxy: fidl_sme::ApSmeProxy,
ap_interface_status: bool,
ap_start_success: bool,
ap_channel: u8,
ap_stop_success: bool,
#[serde(flatten)]
iface_client_results: HashMap<u16, WlanClientResultsPerAP>,
}
impl WlanApIface {
pub fn new(sme_proxy: fidl_sme::ApSmeProxy) -> WlanApIface {
WlanApIface {
sme_proxy: sme_proxy,
ap_interface_status: false,
ap_start_success: false,
ap_stop_success: false,
ap_channel: 0,
iface_client_results: HashMap::new(),
}
}
}
fn report_results(test_results: &TestResults) {
println!("{}", serde_json::to_string_pretty(&test_results).unwrap());
}