use crate::stash_store::StashStore;
use crate::storage_store::StorageStore;
use anyhow::{format_err, Context, Error};
use fidl_fuchsia_stash as fidl_stash;
use fuchsia_component::client::connect_to_protocol;
use wlan_metrics_registry::StashMigrationResultsMetricDimensionMigrationResult as MigrationResult;
pub use wlan_stash_constants::{
self, Credential, NetworkIdentifier, PersistentData, PersistentStorageData, SecurityType,
POLICY_STORAGE_ID,
};
const FILE_PATH_FORMAT: &str = "/data/network-data.";
pub struct PolicyStorage {
root: StorageStore,
legacy_stash: Result<StashStore, Error>,
cobalt_proxy: Option<fidl_fuchsia_metrics::MetricEventLoggerProxy>,
}
impl PolicyStorage {
pub async fn new_with_id(id: &str) -> Self {
let path = format!("{FILE_PATH_FORMAT}{id}");
let root = StorageStore::new(&path);
let proxy = connect_to_protocol::<fidl_stash::SecureStoreMarker>();
let legacy_stash =
proxy.and_then(|p| StashStore::from_secure_store_proxy(id, p)).map_err(|e| e);
let cobalt_proxy = init_telemetry_channel()
.await
.inspect_err(|e| {
tracing::info!(
"Error accessing telemetry. Stash migration metric will not be logged: {}",
e
);
})
.ok();
Self { root, legacy_stash, cobalt_proxy }
}
pub fn new_with_stash_proxy_and_id(
stash_proxy: fidl_stash::SecureStoreProxy,
id: &str,
) -> Self {
let root = StorageStore::new(id);
let legacy_stash = StashStore::from_secure_store_proxy(id, stash_proxy);
let cobalt_proxy = None;
Self { root, legacy_stash, cobalt_proxy }
}
pub async fn load(&mut self) -> Result<Vec<PersistentStorageData>, Error> {
let load_err = match self.root.load() {
Ok(networks) => {
self.log_load_metric(MigrationResult::AlreadyMigrated).await;
return Ok(networks);
}
Err(e) => e,
};
let stash_store: &mut StashStore = if let Ok(stash) = self.legacy_stash.as_mut() {
stash
} else {
return Err(format_err!("error accessing stash"));
};
if let Ok(config) = stash_store.load().await {
let mut networks_list = Vec::new();
for (id, legacy_configs) in config.into_iter() {
let mut new_configs = legacy_configs
.into_iter()
.map(|c| PersistentStorageData::new_from_legacy_data(id.clone(), c));
networks_list.extend(&mut new_configs);
}
match self.root.write(networks_list.clone()) {
Ok(_) => {
tracing::info!("Migrated saved networks from stash");
let delete_result = stash_store.delete_store().await;
match delete_result {
Ok(()) => {
self.log_load_metric(MigrationResult::Success).await;
}
Err(e) => {
tracing::info!(
"Failed to delete legacy stash data after migration: {:?}",
e
);
self.log_load_metric(MigrationResult::MigratedButFailedToDeleteLegacy)
.await;
}
}
}
Err(e) => {
tracing::info!(?e, "Failed to write migrated saved networks");
self.log_load_metric(MigrationResult::FailedToWriteNewStore).await;
}
}
Ok(networks_list)
} else {
tracing::info!(?load_err, "Failed to read saved networks from file and legacy stash, new file will be created when a network is saved",);
self.log_load_metric(MigrationResult::FailedToLoadLegacyData).await;
Ok(Vec::new())
}
}
pub fn write(&self, network_configs: Vec<PersistentStorageData>) -> Result<(), Error> {
self.root.write(network_configs)
}
pub fn clear(&mut self) -> Result<(), Error> {
self.root.empty_store()
}
async fn log_load_metric(&self, result_event_code: MigrationResult) {
let cobalt_proxy = match &self.cobalt_proxy {
Some(proxy) => proxy,
None => return,
};
let events = &[fidl_fuchsia_metrics::MetricEvent {
metric_id: wlan_metrics_registry::STASH_MIGRATION_RESULTS_METRIC_ID,
event_codes: vec![result_event_code as u32],
payload: fidl_fuchsia_metrics::MetricEventPayload::Count(1),
}];
match cobalt_proxy.log_metric_events(events).await {
Err(e) => {
tracing::info!(
"Error logging metric {:?} for migration result: {:?}",
result_event_code,
e
);
}
Ok(Err(e)) => {
tracing::info!(
"Error sending metric {:?} for migration result: {:?}",
result_event_code,
e
);
}
Ok(_) => (),
}
}
}
async fn init_telemetry_channel() -> Result<fidl_fuchsia_metrics::MetricEventLoggerProxy, Error> {
let factory_proxy = fuchsia_component::client::connect_to_protocol::<
fidl_fuchsia_metrics::MetricEventLoggerFactoryMarker,
>()?;
let (cobalt_proxy, cobalt_1dot1_server) =
fidl::endpoints::create_proxy::<fidl_fuchsia_metrics::MetricEventLoggerMarker>();
let project_spec = fidl_fuchsia_metrics::ProjectSpec {
customer_id: None, project_id: Some(wlan_metrics_registry::PROJECT_ID),
..Default::default()
};
let experiment_ids = [];
factory_proxy
.create_metric_event_logger_with_experiments(
&project_spec,
&experiment_ids,
cobalt_1dot1_server,
)
.await
.context("failed to create metrics event logger")?
.map_err(|e| format_err!("failed to create metrics event logger: {:?}", e))?;
Ok(cobalt_proxy)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::{network_id, rand_string};
use fidl::endpoints::create_request_stream;
use fidl_fuchsia_stash::{SecureStoreRequest, StoreAccessorRequest};
use fuchsia_async as fasync;
use futures::task::Poll;
use futures::{StreamExt, TryStreamExt};
use ieee80211::Ssid;
use std::convert::TryFrom;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use wlan_common::assert_variant;
use wlan_stash_constants::PersistentData;
pub const PSK_BYTE_LEN: usize = 32;
#[fuchsia::test]
async fn write_and_read() {
let mut store = new_storage(&rand_string()).await;
let cfg = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::Wpa2,
credential: Credential::Password(b"password".to_vec()),
has_ever_connected: true,
};
store.write(vec![cfg.clone()]).expect("Failed writing to storage");
let cfgs_from_store = store.load().await.expect("Failed reading from storage");
assert_eq!(1, cfgs_from_store.len());
assert_eq!(vec![cfg.clone()], cfgs_from_store);
let cfg_2 = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::Wpa2,
credential: Credential::Password(b"other-password".to_vec()),
has_ever_connected: false,
};
store.write(vec![cfg.clone(), cfg_2.clone()]).expect("Failed writing to storage");
let cfgs_from_store = store.load().await.expect("Failed reading from stash");
assert_eq!(2, cfgs_from_store.len());
assert!(cfgs_from_store.contains(&cfg));
assert!(cfgs_from_store.contains(&cfg_2));
}
#[fuchsia::test]
async fn write_read_security_types() {
let mut store = new_storage(&rand_string()).await;
let password = Credential::Password(b"config-password".to_vec());
let cfg_open = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::None,
credential: Credential::None,
has_ever_connected: false,
};
let cfg_wep = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::Wep,
credential: password.clone(),
has_ever_connected: false,
};
let cfg_wpa = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::Wpa,
credential: password.clone(),
has_ever_connected: false,
};
let cfg_wpa2 = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::Wpa2,
credential: password.clone(),
has_ever_connected: false,
};
let cfg_wpa3 = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::Wpa3,
credential: password.clone(),
has_ever_connected: false,
};
let mut saved_networks = vec![cfg_open.clone()];
store.write(saved_networks.clone()).expect("failed to write config");
saved_networks.push(cfg_wep.clone());
store.write(saved_networks.clone()).expect("failed to write config");
saved_networks.push(cfg_wpa.clone());
store.write(saved_networks.clone()).expect("failed to write config");
saved_networks.push(cfg_wpa2.clone());
store.write(saved_networks.clone()).expect("failed to write config");
saved_networks.push(cfg_wpa3.clone());
store.write(saved_networks.clone()).expect("failed to write config");
let configs = store.load().await.expect("failed loading from storage");
assert_eq!(configs.len(), 5);
assert!(configs.contains(&cfg_open));
assert!(configs.contains(&cfg_wep));
assert!(configs.contains(&cfg_wpa));
assert!(configs.contains(&cfg_wpa2));
assert!(configs.contains(&cfg_wpa3));
}
#[fuchsia::test]
async fn write_read_credentials() {
let mut store = new_storage(&rand_string()).await;
let password = Credential::Password(b"config-password".to_vec());
let psk = Credential::Psk([65; PSK_BYTE_LEN].to_vec());
let cfg_none = PersistentStorageData {
ssid: b"bar-none".to_vec(),
security_type: SecurityType::None,
credential: Credential::None,
has_ever_connected: false,
};
let cfg_password = PersistentStorageData {
ssid: b"bar-password".to_vec(),
security_type: SecurityType::Wpa2,
credential: password,
has_ever_connected: false,
};
let cfg_psk = PersistentStorageData {
ssid: b"bar-psk".to_vec(),
security_type: SecurityType::Wpa2,
credential: psk,
has_ever_connected: false,
};
let mut saved_networks = vec![cfg_none.clone()];
store.write(saved_networks.clone()).expect("failed to write");
saved_networks.push(cfg_password.clone());
store.write(saved_networks.clone()).expect("failed to write");
saved_networks.push(cfg_psk.clone());
store.write(saved_networks.clone()).expect("failed to write");
let configs = store.load().await.expect("failed loading from storage");
assert_eq!(3, configs.len());
assert!(configs.contains(&cfg_none));
assert!(configs.contains(&cfg_password));
assert!(configs.contains(&cfg_psk));
}
#[fuchsia::test]
async fn write_persists() {
let path = rand_string();
let store = new_storage(&path).await;
let cfg = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::Wpa2,
credential: Credential::Password(b"password".to_vec()),
has_ever_connected: true,
};
store.write(vec![cfg.clone()]).expect("Failed writing to storage");
let mut store = PolicyStorage::new_with_id(&path).await;
let cfgs_from_store = store.load().await.expect("Failed reading from storage");
assert_eq!(1, cfgs_from_store.len());
assert!(cfgs_from_store.contains(&cfg));
}
#[fuchsia::test]
async fn load_storage() {
let mut store = new_storage(&rand_string()).await;
let cfg_foo = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::Wpa2,
credential: Credential::Password(b"12345678".to_vec()),
has_ever_connected: true,
};
let cfg_bar = PersistentStorageData {
ssid: Ssid::try_from("bar").unwrap().to_vec(),
security_type: SecurityType::Wpa2,
credential: Credential::Password(b"qwertyuiop".to_vec()),
has_ever_connected: true,
};
store
.write(vec![cfg_foo.clone(), cfg_bar.clone()])
.expect("Failed to save configs to stash");
let expected_cfgs = vec![cfg_foo, cfg_bar];
assert_eq!(expected_cfgs, store.load().await.expect("Failed to load configs from stash"));
}
#[fuchsia::test]
async fn load_empty_storage_does_loads_empty_list() {
let store_id = &rand_string();
let mut store = new_storage(&store_id).await;
store.write(vec![]).expect("failed to write value");
let loaded_configs = store.load().await.expect("failed to load store");
assert!(loaded_configs.is_empty());
}
#[fuchsia::test]
pub async fn load_no_file_creates_file() {
let store_id = &rand_string();
let backing_file_path = format!("{}{}", FILE_PATH_FORMAT, store_id).to_string();
let mut store = PolicyStorage::new_with_id(store_id).await;
std::fs::read(&backing_file_path).expect_err("The file for the store should not exist yet");
let loaded_configs = store.load().await.expect("failed to load store");
assert_eq!(loaded_configs, vec![]);
let file_contents = std::fs::read(&backing_file_path).expect(
"Failed to read file that should have been created when loading non-existant file",
);
assert!(!file_contents.is_empty());
let cfg_id = NetworkIdentifier {
ssid: Ssid::try_from(rand_string().as_str()).unwrap().to_vec(),
security_type: SecurityType::Wpa2,
};
let cfg = PersistentData {
credential: Credential::Password(rand_string().as_bytes().to_vec()),
has_ever_connected: true,
};
match store.legacy_stash.as_mut() {
Ok(stash) => {
stash.write(&cfg_id, &[cfg]).await.expect("Failed writing to legacy stash");
stash.flush().await.expect("Failed to flush legacy stash");
}
Err(e) => {
panic!("error initializing legacy stash: {}", e);
}
}
let loaded_configs = store.load().await.expect("failed to load store");
assert!(loaded_configs.is_empty());
let file_contents = std::fs::read(&backing_file_path).expect(
"Failed to read file that should have been created when loading non-existant file",
);
assert!(!file_contents.is_empty());
}
#[fuchsia::test]
async fn clear_storage() {
let storage_id = &rand_string();
let mut storage = new_storage(&storage_id).await;
let cfg_foo = PersistentStorageData {
ssid: Ssid::try_from("foo").unwrap().to_vec(),
security_type: SecurityType::Wpa2,
credential: Credential::Password(b"qwertyuio".to_vec()),
has_ever_connected: true,
};
let cfg_bar = PersistentStorageData {
ssid: Ssid::try_from("bar").unwrap().to_vec(),
security_type: SecurityType::Wpa2,
credential: Credential::Password(b"12345678".to_vec()),
has_ever_connected: false,
};
storage.write(vec![cfg_foo.clone(), cfg_bar.clone()]).expect("Failed to write to storage");
let configs_from_storage = storage.load().await.expect("Failed to read");
assert_eq!(2, configs_from_storage.len());
assert!(configs_from_storage.contains(&cfg_foo));
assert!(configs_from_storage.contains(&cfg_bar));
storage.clear().expect("Failed to clear storage");
let configs_from_storage = storage.load().await.expect("Failed to read");
assert_eq!(0, configs_from_storage.len());
let mut storage = PolicyStorage::new_with_id(storage_id).await;
let configs_from_storage = storage.load().await.expect("Failed to read");
assert_eq!(0, configs_from_storage.len());
}
#[fuchsia::test]
async fn test_migration() {
let storage_id = rand_string();
let stash_client = connect_to_protocol::<fidl_stash::SecureStoreMarker>()
.expect("failed to connect to store");
let ssid = "foo";
let security_type = SecurityType::Wpa2;
let credential = Credential::Password(b"password".to_vec());
let has_ever_connected = false;
let network_id = network_id(ssid, security_type);
let previous_data = PersistentData { credential: credential.clone(), has_ever_connected };
let network_config = vec![PersistentStorageData {
ssid: ssid.into(),
security_type: security_type,
credential: credential.clone(),
has_ever_connected,
}];
let stash = StashStore::from_secure_store_proxy(&storage_id, stash_client.clone())
.expect("failed to get stash proxy");
stash.write(&network_id, &vec![previous_data]).await.expect("write failed");
let mut storage = PolicyStorage::new_with_id(&storage_id).await;
storage.legacy_stash = Ok(stash);
assert_eq!(storage.load().await.expect("load failed"), network_config);
let stash_client = connect_to_protocol::<fidl_stash::SecureStoreMarker>()
.expect("failed to connect to store");
let stash = StashStore::from_secure_store_proxy(&storage_id, stash_client)
.expect("failed to get stash proxy");
assert!(stash.load().await.expect("load failed").is_empty());
let mut storage = PolicyStorage::new_with_id(&storage_id).await;
assert_eq!(storage.load().await.expect("load failed"), network_config);
}
#[fuchsia::test]
async fn test_migration_with_bad_stash() {
let store_id = rand_string();
let (client, mut request_stream) = create_request_stream::<fidl_stash::SecureStoreMarker>();
let read_from_stash = Arc::new(AtomicBool::new(false));
let _task = {
let read_from_stash = read_from_stash.clone();
fasync::Task::spawn(async move {
while let Some(request) = request_stream.next().await {
match request.unwrap() {
SecureStoreRequest::Identify { .. } => {}
SecureStoreRequest::CreateAccessor { accessor_request, .. } => {
let read_from_stash = read_from_stash.clone();
fuchsia_async::Task::spawn(async move {
let mut request_stream = accessor_request.into_stream();
while let Some(request) = request_stream.next().await {
match request.unwrap() {
StoreAccessorRequest::ListPrefix { .. } => {
read_from_stash.store(true, Ordering::Relaxed);
}
_ => unreachable!(),
}
}
})
.detach();
}
}
}
})
};
let mut store = PolicyStorage::new_with_id(&store_id).await;
let proxy_fn = client.into_proxy();
store.legacy_stash = StashStore::from_secure_store_proxy(&store_id, proxy_fn);
assert!(&store.load().await.expect("load failed").is_empty());
assert!(read_from_stash.load(Ordering::Relaxed));
}
pub async fn new_storage(id: &str) -> PolicyStorage {
let mut store = PolicyStorage::new_with_id(id).await;
store.clear().expect("failed to clear stash");
store
}
struct MetricsTestValues {
store: PolicyStorage,
cobalt_stream: fidl_fuchsia_metrics::MetricEventLoggerRequestStream,
stash_stream: fidl_stash::SecureStoreRequestStream,
}
fn migration_metrics_test_values() -> MetricsTestValues {
let (cobalt_proxy, cobalt_stream) = fidl::endpoints::create_proxy_and_stream::<
fidl_fuchsia_metrics::MetricEventLoggerMarker,
>();
let (legacy_stash, stash_stream) = stash_for_test();
let root = StorageStore::new(format!("{FILE_PATH_FORMAT}{}", rand_string()));
let store = PolicyStorage { root, legacy_stash, cobalt_proxy: Some(cobalt_proxy) };
MetricsTestValues { store, cobalt_stream, stash_stream }
}
fn stash_for_test() -> (Result<StashStore, Error>, fidl_stash::SecureStoreRequestStream) {
let (client, stash_stream) = create_request_stream::<fidl_stash::SecureStoreMarker>();
let proxy_fn = client.into_proxy();
let id = rand_string();
let legacy_stash = StashStore::from_secure_store_proxy(&id, proxy_fn);
(legacy_stash, stash_stream)
}
fn check_load_metric(
logged_metric: fidl_fuchsia_metrics::MetricEventLoggerRequest,
expected_event: MigrationResult,
) {
assert_variant!(logged_metric, fidl_fuchsia_metrics::MetricEventLoggerRequest::LogMetricEvents {
mut events, responder, ..
} => {
assert_eq!(events.len(), 1);
let event = events.pop().unwrap();
assert_variant!(event, fidl_fuchsia_metrics::MetricEvent { metric_id, event_codes, payload: _payload } => {
assert_eq!(metric_id, wlan_metrics_registry::STASH_MIGRATION_RESULTS_METRIC_ID);
assert_eq!(event_codes, [expected_event as u32]);
});
assert!(responder.send(Ok(())).is_ok());
});
}
fn process_init_stash(
exec: &mut fasync::TestExecutor,
mut stash_stream: fidl_stash::SecureStoreRequestStream,
) -> fidl_stash::StoreAccessorRequestStream {
assert_variant!(
exec.run_until_stalled(&mut stash_stream.next()),
Poll::Ready(Some(Ok(SecureStoreRequest::Identify { .. })))
);
let accessor_req_stream = assert_variant!(
exec.run_until_stalled(&mut stash_stream.next()),
Poll::Ready(Some(Ok(SecureStoreRequest::CreateAccessor { accessor_request, .. }))) =>
{
accessor_request.into_stream()
});
accessor_req_stream
}
fn respond_to_stash_list_prefix(
exec: &mut fasync::TestExecutor,
stash_server: &mut fidl_stash::StoreAccessorRequestStream,
) {
let request = assert_variant!(exec.run_until_stalled(&mut stash_server.next()), Poll::Ready(req) => {
req.expect("ListPrefix stash request not recieved.")
});
match request.unwrap() {
StoreAccessorRequest::ListPrefix { it, .. } => {
let mut iter = it.into_stream();
assert_variant!(
exec.run_until_stalled(&mut iter.try_next()),
Poll::Ready(Ok(Some(fidl_stash::ListIteratorRequest::GetNext { responder }))) => {
responder.send(&[]).expect("error sending stash response");
});
}
_ => unreachable!(),
}
}
fn process_stash_delete(
exec: &mut fasync::TestExecutor,
stash_server: &mut fidl_stash::StoreAccessorRequestStream,
) {
let request = assert_variant!(exec.run_until_stalled(&mut stash_server.next()), Poll::Ready(req) => {
req.expect("DeletePrefix stash request not recieved.")
});
match request.unwrap() {
StoreAccessorRequest::DeletePrefix { .. } => {}
_ => unreachable!(),
}
assert_variant!(
exec.run_until_stalled(&mut stash_server.try_next()),
Poll::Ready(Ok(Some(fidl_stash::StoreAccessorRequest::Flush{responder}))) => {
responder.send(Ok(())).expect("failed to send stash response");
}
);
}
#[fuchsia::test]
pub fn test_load_logs_result_success_metric() {
let mut exec = fasync::TestExecutor::new();
let mut test_values = migration_metrics_test_values();
{
let load_fut = test_values.store.load();
futures::pin_mut!(load_fut);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
let mut accessor_req_stream = process_init_stash(&mut exec, test_values.stash_stream);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
respond_to_stash_list_prefix(&mut exec, &mut accessor_req_stream);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
process_stash_delete(&mut exec, &mut accessor_req_stream);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
let mut metric_fut = test_values.cobalt_stream.next();
assert_variant!(exec.run_until_stalled(&mut metric_fut), Poll::Ready(Some(Ok(logged_metric))) => {
check_load_metric(logged_metric, MigrationResult::Success);
});
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Ready(Ok(_)));
}
let load_fut = test_values.store.load();
futures::pin_mut!(load_fut);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
let mut metric_fut = test_values.cobalt_stream.next();
assert_variant!(exec.run_until_stalled(&mut metric_fut), Poll::Ready(Some(Ok(logged_metric))) => {
check_load_metric(logged_metric, MigrationResult::AlreadyMigrated);
});
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Ready(Ok(_)));
assert_variant!(exec.run_until_stalled(&mut metric_fut), Poll::Pending);
}
#[fuchsia::test]
pub fn test_load_failure_logs_result_metric() {
let mut exec = fuchsia_async::TestExecutor::new();
let mut test_values = migration_metrics_test_values();
let load_fut = test_values.store.load();
futures::pin_mut!(load_fut);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
let mut accessor_req_stream = process_init_stash(&mut exec, test_values.stash_stream);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
let request = assert_variant!(exec.run_until_stalled(&mut accessor_req_stream.next()), Poll::Ready(req) => {
req.expect("ListPrefix stash request not recieved.")
});
match request.unwrap() {
StoreAccessorRequest::ListPrefix { it: _, .. } => {
}
_ => unreachable!(),
}
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
assert_variant!(exec.run_until_stalled(&mut test_values.cobalt_stream.next()), Poll::Ready(Some(Ok(metric))) => {
check_load_metric(metric, MigrationResult::FailedToLoadLegacyData);
});
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Ready(Ok(data)) => {
assert!(data.is_empty());
});
assert_variant!(
exec.run_until_stalled(&mut test_values.cobalt_stream.next()),
Poll::Pending
);
}
#[fuchsia::test]
pub fn test_load_delete_stash_failure_logs_result_metric() {
let mut exec = fuchsia_async::TestExecutor::new();
let mut test_values = migration_metrics_test_values();
let load_fut = test_values.store.load();
futures::pin_mut!(load_fut);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
let mut accessor_req_stream = process_init_stash(&mut exec, test_values.stash_stream);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
respond_to_stash_list_prefix(&mut exec, &mut accessor_req_stream);
drop(accessor_req_stream);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
assert_variant!(exec.run_until_stalled(&mut test_values.cobalt_stream.next()), Poll::Ready(Some(Ok(metric))) => {
check_load_metric(metric, MigrationResult::MigratedButFailedToDeleteLegacy);
});
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Ready(Ok(data)) => {
assert!(data.is_empty());
});
assert_variant!(
exec.run_until_stalled(&mut test_values.cobalt_stream.next()),
Poll::Pending
);
}
#[fuchsia::test]
pub fn test_load_logs_result_failed_to_write_metric() {
let mut exec = fasync::TestExecutor::new();
let store_id = "//";
let mut test_values = migration_metrics_test_values();
test_values.store.root = StorageStore::new(std::path::Path::new(store_id));
let load_fut = test_values.store.load();
futures::pin_mut!(load_fut);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
let mut accessor_req_stream = process_init_stash(&mut exec, test_values.stash_stream);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
respond_to_stash_list_prefix(&mut exec, &mut accessor_req_stream);
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Pending);
let mut metric_fut = test_values.cobalt_stream.next();
assert_variant!(exec.run_until_stalled(&mut metric_fut), Poll::Ready(Some(Ok(logged_metric))) => {
check_load_metric(logged_metric, MigrationResult::FailedToWriteNewStore);
});
assert_variant!(exec.run_until_stalled(&mut load_fut), Poll::Ready(Ok(_)));
assert_variant!(
exec.run_until_stalled(&mut test_values.cobalt_stream.next()),
Poll::Pending
);
}
}