991 lines
29 KiB
Rust
991 lines
29 KiB
Rust
//! # peach-network
|
|
//!
|
|
//! `peach-network` is a networking microservice module for PeachCloud. It
|
|
//! exposes a JSON-RPC API over HTTP which allows querying of network interface
|
|
//! data and modification of interface state.
|
|
//!
|
|
//! The `src/network.rs` module contains the core networking logic and data
|
|
//! types for interacting with the `wpa_supplicant` process and related parts of
|
|
//! the operating system, while the `src/error.rs` module contains
|
|
//! error-handling data types and methods.
|
|
//!
|
|
//! `src/main.rs` initializes the logger, starts the application and catches
|
|
//! application errors, while `src/lib.rs` contains the JSON-RPC server, RPC
|
|
//! methods, HTTP server and tests.
|
|
//!
|
|
mod error;
|
|
pub mod network;
|
|
mod utils;
|
|
|
|
use std::env;
|
|
use std::result::Result;
|
|
|
|
use jsonrpc_core::{types::error::Error, IoHandler, Params, Value};
|
|
use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder};
|
|
use log::info;
|
|
use serde_json::json;
|
|
|
|
use crate::error::NetworkError;
|
|
use crate::network::{Iface, IfaceId, IfaceIdPass, IfaceSsid, WiFi};
|
|
|
|
/// Create JSON-RPC I/O handler, add RPC methods and launch HTTP server.
|
|
pub fn run() -> Result<(), NetworkError> {
|
|
info!("Starting up.");
|
|
|
|
info!("Creating JSON-RPC I/O handler.");
|
|
let mut io = IoHandler::default();
|
|
|
|
/* GET - All RPC methods for retrieving data */
|
|
|
|
io.add_method("available_networks", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::available_networks(&iface)? {
|
|
Some(list) => Ok(Value::String(list)),
|
|
None => Err(Error::from(NetworkError::AvailableNetworks { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("id", move |params: Params| {
|
|
let i: Result<IfaceSsid, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
let ssid = i.ssid;
|
|
match network::id(&iface, &ssid)? {
|
|
Some(id) => Ok(Value::String(id)),
|
|
None => Err(Error::from(NetworkError::Id { iface, ssid })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("ip", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::ip(&iface)? {
|
|
Some(ip) => Ok(Value::String(ip)),
|
|
None => Err(Error::from(NetworkError::Ip { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("ping", |_| Ok(Value::String("success".to_string())));
|
|
|
|
io.add_method("rssi", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::rssi(&iface)? {
|
|
Some(rssi) => Ok(Value::String(rssi)),
|
|
None => Err(Error::from(NetworkError::Rssi { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("rssi_percent", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::rssi_percent(&iface)? {
|
|
Some(rssi) => Ok(Value::String(rssi)),
|
|
None => Err(Error::from(NetworkError::RssiPercent { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("saved_networks", move |_| {
|
|
let list = network::saved_networks()?;
|
|
match list {
|
|
Some(list) => Ok(Value::String(list)),
|
|
None => Err(Error::from(NetworkError::SavedNetworks)),
|
|
}
|
|
});
|
|
|
|
io.add_method("ssid", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::ssid(&iface)? {
|
|
Some(ip) => Ok(Value::String(ip)),
|
|
None => Err(Error::from(NetworkError::Ssid { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("state", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::state(&iface)? {
|
|
Some(state) => Ok(Value::String(state)),
|
|
None => Err(Error::from(NetworkError::State { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("status", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::status(&iface)? {
|
|
Some(status) => {
|
|
let json_status = json!(status);
|
|
Ok(Value::String(json_status.to_string()))
|
|
}
|
|
None => Err(Error::from(NetworkError::Status { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("traffic", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::traffic(&iface)? {
|
|
Some(traffic) => Ok(Value::String(traffic)),
|
|
None => Err(Error::from(NetworkError::Traffic { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
/* SET - All RPC methods for modifying state */
|
|
|
|
io.add_method("activate_ap", move |_| {
|
|
network::activate_ap()?;
|
|
|
|
Ok(Value::String("success".to_string()))
|
|
});
|
|
|
|
io.add_method("activate_client", move |_| {
|
|
network::activate_client()?;
|
|
|
|
Ok(Value::String("success".to_string()))
|
|
});
|
|
|
|
io.add_method("add", move |params: Params| {
|
|
let w: Result<WiFi, Error> = params.parse();
|
|
match w {
|
|
Ok(w) => match network::add(&w) {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(e) => Err(Error::from(e)),
|
|
},
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("check_iface", move |_| {
|
|
network::check_iface()?;
|
|
|
|
Ok(Value::String("success".to_string()))
|
|
});
|
|
|
|
io.add_method("delete", move |params: Params| {
|
|
let i: Result<IfaceId, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let id = i.id;
|
|
let iface = i.iface;
|
|
match network::delete(&id, &iface) {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(_) => Err(Error::from(NetworkError::Delete { id, iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("disable", move |params: Params| {
|
|
let i: Result<IfaceId, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let id = i.id;
|
|
let iface = i.iface;
|
|
match network::disable(&id, &iface) {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(_) => Err(Error::from(NetworkError::Disable { id, iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("disconnect", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::disconnect(&iface) {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(_) => Err(Error::from(NetworkError::Disconnect { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("modify", move |params: Params| {
|
|
let i: Result<IfaceIdPass, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
let id = i.id;
|
|
let pass = i.pass;
|
|
match network::modify(&iface, &id, &pass) {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(_) => Err(Error::from(NetworkError::Modify { iface, id })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("reassociate", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::reassociate(&iface) {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(_) => Err(Error::from(NetworkError::Reassociate { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("reconfigure", move |_| match network::reconfigure() {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(_) => Err(Error::from(NetworkError::Reconfigure)),
|
|
});
|
|
|
|
io.add_method("reconnect", move |params: Params| {
|
|
let i: Result<Iface, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let iface = i.iface;
|
|
match network::reconnect(&iface) {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(_) => Err(Error::from(NetworkError::Reconnect { iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
io.add_method("save", move |_| match network::save() {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(_) => Err(Error::from(NetworkError::Save)),
|
|
});
|
|
|
|
io.add_method("connect", move |params: Params| {
|
|
let i: Result<IfaceId, Error> = params.parse();
|
|
match i {
|
|
Ok(i) => {
|
|
let id = i.id;
|
|
let iface = i.iface;
|
|
match network::connect(&id, &iface) {
|
|
Ok(_) => Ok(Value::String("success".to_string())),
|
|
Err(_) => Err(Error::from(NetworkError::Connect { id, iface })),
|
|
}
|
|
}
|
|
Err(e) => Err(Error::from(NetworkError::MissingParams(e))),
|
|
}
|
|
});
|
|
|
|
let http_server =
|
|
env::var("PEACH_NETWORK_SERVER").unwrap_or_else(|_| "127.0.0.1:5110".to_string());
|
|
|
|
info!("Starting JSON-RPC server on {}.", http_server);
|
|
let server = ServerBuilder::new(io)
|
|
.cors(DomainsValidation::AllowOnly(vec![
|
|
AccessControlAllowOrigin::Null,
|
|
]))
|
|
.start_http(
|
|
&http_server
|
|
.parse()
|
|
.expect("Invalid HTTP address and port combination"),
|
|
)
|
|
.expect("Unable to start RPC server");
|
|
|
|
server.wait();
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
use jsonrpc_core::ErrorCode;
|
|
use jsonrpc_test as test_rpc;
|
|
use std::io::Error as IoError;
|
|
use std::io::ErrorKind;
|
|
|
|
#[test]
|
|
fn rpc_success() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_success_response", |_| {
|
|
Ok(Value::String("success".into()))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(rpc.request("rpc_success_response", &()), r#""success""#);
|
|
}
|
|
|
|
// test to ensure correct MissingParams parse error
|
|
#[test]
|
|
fn rpc_parse_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_parse_error", |_| {
|
|
let e = Error {
|
|
code: ErrorCode::ParseError,
|
|
message: String::from("Parse error"),
|
|
data: None,
|
|
};
|
|
Err(Error::from(NetworkError::MissingParams(e)))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_parse_error", &()),
|
|
r#"{
|
|
"code": -32700,
|
|
"message": "Parse error"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Add error response
|
|
#[test]
|
|
fn rpc_add_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_add_error", |_| {
|
|
Err(Error::from(NetworkError::Add {
|
|
ssid: "Home".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_add_error", &()),
|
|
r#"{
|
|
"code": -32000,
|
|
"message": "Failed to add network for Home"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Disable error response
|
|
#[test]
|
|
fn rpc_disable_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_disable_error", |_| {
|
|
Err(Error::from(NetworkError::Disable {
|
|
id: "0".to_string(),
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_disable_error", &()),
|
|
r#"{
|
|
"code": -32029,
|
|
"message": "Failed to disable network 0 for wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Disconnect error response
|
|
#[test]
|
|
fn rpc_disconnect_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_disconnect_error", |_| {
|
|
Err(Error::from(NetworkError::Disconnect {
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_disconnect_error", &()),
|
|
r#"{
|
|
"code": -32032,
|
|
"message": "Failed to disconnect wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct GenWpaPassphrase error response
|
|
#[test]
|
|
fn rpc_genwpapassphrase_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_genwpapassphrase_error", |_| {
|
|
Err(Error::from(NetworkError::GenWpaPassphrase {
|
|
ssid: "HomeWifi".to_string(),
|
|
source: IoError::new(ErrorKind::NotFound, "oh no!"),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_genwpapassphrase_error", &()),
|
|
r#"{
|
|
"code": -32025,
|
|
"message": "Failed to generate wpa passphrase for HomeWifi: oh no!"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Id error response
|
|
#[test]
|
|
fn rpc_id_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_id_error", |_| {
|
|
Err(Error::from(NetworkError::Id {
|
|
iface: "wlan0".to_string(),
|
|
ssid: "Home".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_id_error", &()),
|
|
r#"{
|
|
"code": -32026,
|
|
"message": "No ID found for Home on interface wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct NoIp error response
|
|
#[test]
|
|
fn rpc_noip_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_noip_error", |_| {
|
|
Err(Error::from(NetworkError::NoIp {
|
|
iface: "wlan7".to_string(),
|
|
source: IoError::new(ErrorKind::AddrNotAvailable, "oh no!"),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_noip_error", &()),
|
|
r#"{
|
|
"code": -32001,
|
|
"message": "Failed to retrieve IP address for wlan7: oh no!"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Rssi error response
|
|
#[test]
|
|
fn rpc_rssi_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_rssi_error", |_| {
|
|
Err(Error::from(NetworkError::Rssi {
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_rssi_error", &()),
|
|
r#"{
|
|
"code": -32002,
|
|
"message": "Failed to retrieve RSSI for wlan0. Interface may not be connected"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct RssiPercent error response
|
|
#[test]
|
|
fn rpc_rssipercent_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_rssipercent_error", |_| {
|
|
Err(Error::from(NetworkError::RssiPercent {
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_rssipercent_error", &()),
|
|
r#"{
|
|
"code": -32034,
|
|
"message": "Failed to retrieve signal quality (%) for wlan0. Interface may not be connected"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Ssid error response
|
|
#[test]
|
|
fn rpc_ssid_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_ssid_error", |_| {
|
|
Err(Error::from(NetworkError::Ssid {
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_ssid_error", &()),
|
|
r#"{
|
|
"code": -32003,
|
|
"message": "Failed to retrieve SSID for wlan0. Interface may not be connected"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct State error response
|
|
#[test]
|
|
fn rpc_state_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_state_error", |_| {
|
|
Err(Error::from(NetworkError::State {
|
|
iface: "wlan1".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_state_error", &()),
|
|
r#"{
|
|
"code": -32023,
|
|
"message": "No state found for wlan1. Interface may not exist"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Traffic error response
|
|
#[test]
|
|
fn rpc_traffic_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_traffic_error", |_| {
|
|
Err(Error::from(NetworkError::Traffic {
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_traffic_error", &()),
|
|
r#"{
|
|
"code": -32004,
|
|
"message": "No network traffic statistics found for wlan0. Interface may not exist"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct SavedNetworks error response
|
|
#[test]
|
|
fn rpc_savednetworks_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_savednetworks_error", |_| {
|
|
Err(Error::from(NetworkError::SavedNetworks))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_savednetworks_error", &()),
|
|
r#"{
|
|
"code": -32005,
|
|
"message": "No saved networks found"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct AvailableNetworks error response
|
|
#[test]
|
|
fn rpc_availablenetworks_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_availablenetworks_error", |_| {
|
|
Err(Error::from(NetworkError::AvailableNetworks {
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_availablenetworks_error", &()),
|
|
r#"{
|
|
"code": -32006,
|
|
"message": "No networks found in range of wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct MissingParams error response
|
|
#[test]
|
|
fn rpc_missingparams_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_missingparams_error", |_| {
|
|
let e = Error {
|
|
code: ErrorCode::InvalidParams,
|
|
message: String::from(
|
|
"Invalid params: invalid type: null, expected struct Iface.",
|
|
),
|
|
data: None,
|
|
};
|
|
Err(Error::from(NetworkError::MissingParams(e)))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_missingparams_error", &()),
|
|
r#"{
|
|
"code": -32602,
|
|
"message": "Invalid params: invalid type: null, expected struct Iface."
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Modify error response
|
|
#[test]
|
|
fn rpc_modify_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_modify_error", |_| {
|
|
Err(Error::from(NetworkError::Modify {
|
|
id: "1".to_string(),
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_modify_error", &()),
|
|
r#"{
|
|
"code": -32033,
|
|
"message": "Failed to set new password for network 1 on wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Ip error response
|
|
#[test]
|
|
fn rpc_ip_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_ip_error", |_| {
|
|
Err(Error::from(NetworkError::Ip {
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_ip_error", &()),
|
|
r#"{
|
|
"code": -32007,
|
|
"message": "No IP address found for wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Reassociate error response
|
|
#[test]
|
|
fn rpc_reassociate_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_reassociate_error", |_| {
|
|
Err(Error::from(NetworkError::Reassociate {
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_reassociate_error", &()),
|
|
r#"{
|
|
"code": -32008,
|
|
"message": "Failed to reassociate with WiFi network for wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Reconfigure error response
|
|
#[test]
|
|
fn rpc_reconfigure_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_reconfigure_error", |_| {
|
|
Err(Error::from(NetworkError::Reconfigure))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_reconfigure_error", &()),
|
|
r#"{
|
|
"code": -32030,
|
|
"message": "Failed to force reread of wpa_supplicant configuration file"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Connect error response
|
|
#[test]
|
|
fn rpc_connect_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_connect_error", |_| {
|
|
Err(Error::from(NetworkError::Connect {
|
|
id: "0".to_string(),
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_connect_error", &()),
|
|
r#"{
|
|
"code": -32027,
|
|
"message": "Failed to connect to network 0 for wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Reconnect error response
|
|
#[test]
|
|
fn rpc_reconnect_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_reconnect_error", |_| {
|
|
Err(Error::from(NetworkError::Reconnect {
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_reconnect_error", &()),
|
|
r#"{
|
|
"code": -32009,
|
|
"message": "Failed to reconnect with WiFi network for wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Regex error response
|
|
#[test]
|
|
fn rpc_regex_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_regex_error", |_| {
|
|
let source = regex::Error::Syntax("oh no!".to_string());
|
|
Err(Error::from(NetworkError::Regex(source)))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_regex_error", &()),
|
|
r#"{
|
|
"code": -32010,
|
|
"message": "Regex command error: oh no!"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Delete error response
|
|
#[test]
|
|
fn rpc_delete_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_delete_error", |_| {
|
|
Err(Error::from(NetworkError::Delete {
|
|
id: "0".to_string(),
|
|
iface: "wlan0".to_string(),
|
|
}))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_delete_error", &()),
|
|
r#"{
|
|
"code": -32028,
|
|
"message": "Failed to delete network 0 for wlan0"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct WlanState error response
|
|
#[test]
|
|
fn rpc_wlanstate_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_wlanstate_error", |_| {
|
|
let source = IoError::new(ErrorKind::PermissionDenied, "oh no!");
|
|
Err(Error::from(NetworkError::WlanState(source)))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_wlanstate_error", &()),
|
|
r#"{
|
|
"code": -32011,
|
|
"message": "Failed to retrieve state of wlan0 service: oh no!"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct WlanOperstate error response
|
|
#[test]
|
|
fn rpc_wlanoperstate_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_wlanoperstate_error", |_| {
|
|
let source = IoError::new(ErrorKind::PermissionDenied, "oh no!");
|
|
Err(Error::from(NetworkError::WlanOperstate(source)))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_wlanoperstate_error", &()),
|
|
r#"{
|
|
"code": -32021,
|
|
"message": "Failed to retrieve connection state of wlan0 interface: oh no!"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct Save error response
|
|
#[test]
|
|
fn rpc_save_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_save_error", |_| Err(Error::from(NetworkError::Save)));
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_save_error", &()),
|
|
r#"{
|
|
"code": -32031,
|
|
"message": "Failed to save configuration changes to file"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct WpaCtrlOpen error response
|
|
#[test]
|
|
fn rpc_wpactrlopen_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_wpactrlopen_error", |_| {
|
|
let permission_error = IoError::new(
|
|
ErrorKind::PermissionDenied,
|
|
"Permission denied (os error 13)",
|
|
);
|
|
Err(Error::from(NetworkError::WpaCtrl(wpactrl::WpaError::Io(
|
|
permission_error,
|
|
))))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_wpactrlopen_error", &()),
|
|
r#"{
|
|
"code": -32013,
|
|
"message": "WPA control interface failure: Failed to execute the specified command: Permission denied (os error 13)"
|
|
}"#
|
|
);
|
|
}
|
|
|
|
// test to ensure correct WpaCtrlRequest error response
|
|
#[test]
|
|
fn rpc_wpactrlrequest_error() {
|
|
let rpc = {
|
|
let mut io = IoHandler::new();
|
|
io.add_method("rpc_wpactrlrequest_error", |_| {
|
|
let conn_refused_error = IoError::new(ErrorKind::ConnectionRefused, "oh no!");
|
|
Err(Error::from(NetworkError::WpaCtrl(wpactrl::WpaError::Io(
|
|
conn_refused_error,
|
|
))))
|
|
});
|
|
test_rpc::Rpc::from(io)
|
|
};
|
|
|
|
assert_eq!(
|
|
rpc.request("rpc_wpactrlrequest_error", &()),
|
|
r#"{
|
|
"code": -32013,
|
|
"message": "WPA control interface failure: Failed to execute the specified command: oh no!"
|
|
}"#
|
|
);
|
|
}
|
|
}
|