blob: dadbd27b7313b033ab6c4fffc456ab557977c27e [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.
#[cfg(test)]
use {
crate::registry::device_storage::testing::*,
crate::switchboard::base::SettingType,
crate::tests::test_failure_utils::create_test_env_with_failures,
crate::EnvironmentBuilder,
anyhow::format_err,
fidl::endpoints::{ServerEnd, ServiceMarker},
fidl::Error::ClientChannelClosed,
fidl_fuchsia_settings::*,
fuchsia_async as fasync, fuchsia_zircon as zx,
fuchsia_zircon::Status,
futures::future::BoxFuture,
futures::lock::Mutex,
futures::prelude::*,
std::sync::Arc,
};
use crate::fidl_clone::FIDLClone;
use crate::switchboard::intl_types::IntlInfo;
const ENV_NAME: &str = "settings_service_intl_test_environment";
const CONTEXT_ID: u64 = 0;
async fn create_test_intl_env(storage_factory: Arc<Mutex<InMemoryStorageFactory>>) -> IntlProxy {
let service_gen = Box::new(
|service_name: &str,
channel: zx::Channel|
-> BoxFuture<'static, Result<(), anyhow::Error>> {
if service_name != fidl_fuchsia_deprecatedtimezone::TimezoneMarker::NAME {
return Box::pin(async { Err(format_err!("unsupported!")) });
}
let timezone_stream_result =
ServerEnd::<fidl_fuchsia_deprecatedtimezone::TimezoneMarker>::new(channel)
.into_stream();
if timezone_stream_result.is_err() {
return Box::pin(async { Err(format_err!("could not open stream")) });
}
let mut timezone_stream = timezone_stream_result.unwrap();
fasync::spawn(async move {
while let Some(req) = timezone_stream.try_next().await.unwrap() {
#[allow(unreachable_patterns)]
match req {
fidl_fuchsia_deprecatedtimezone::TimezoneRequest::GetTimezoneId {
responder,
} => {
responder.send("PDT").unwrap();
}
fidl_fuchsia_deprecatedtimezone::TimezoneRequest::SetTimezone {
timezone_id: _,
responder,
} => {
responder.send(true).unwrap();
}
_ => {}
}
}
});
return Box::pin(async { Ok(()) });
},
);
let env = EnvironmentBuilder::new(storage_factory)
.service(Box::new(service_gen))
.settings(&[SettingType::Intl])
.spawn_and_get_nested_environment(ENV_NAME)
.await
.unwrap();
env.connect_to_service::<IntlMarker>().unwrap()
}
/// Creates an environment that will fail on a get request.
async fn create_intl_test_env_with_failures(
storage_factory: Arc<Mutex<InMemoryStorageFactory>>,
) -> IntlProxy {
create_test_env_with_failures(storage_factory, ENV_NAME, SettingType::Intl)
.await
.connect_to_service::<IntlMarker>()
.unwrap()
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_intl_e2e() {
// Create and fetch a store from device storage so we can read stored value for testing.
let factory = InMemoryStorageFactory::create();
let store =
factory.lock().await.get_device_storage::<IntlInfo>(StorageAccessContext::Test, CONTEXT_ID);
let intl_service = create_test_intl_env(factory).await;
// Check if the initial value is correct.
let settings = intl_service.watch2().await.expect("watch completed");
assert_eq!(
settings.time_zone_id,
Some(fidl_fuchsia_intl::TimeZoneId { id: "UTC".to_string() })
);
assert_eq!(
settings.locales,
Some(vec![fidl_fuchsia_intl::LocaleId { id: "en-US".to_string() }])
);
assert_eq!(settings.temperature_unit, Some(fidl_fuchsia_intl::TemperatureUnit::Celsius));
assert_eq!(settings.hour_cycle, Some(fidl_fuchsia_settings::HourCycle::H12));
// Set new values.
let intl_settings = fidl_fuchsia_settings::IntlSettings {
locales: Some(vec![fidl_fuchsia_intl::LocaleId { id: "blah".into() }]),
temperature_unit: Some(fidl_fuchsia_intl::TemperatureUnit::Celsius),
time_zone_id: Some(fidl_fuchsia_intl::TimeZoneId { id: "GMT".to_string() }),
hour_cycle: Some(fidl_fuchsia_settings::HourCycle::H24),
};
intl_service.set(intl_settings.clone()).await.expect("set completed").expect("set successful");
// Verify the values we set are returned when watching.
let settings = intl_service.watch2().await.expect("watch completed");
assert_eq!(settings, intl_settings.clone());
// Verify the value we set is persisted in DeviceStorage.
let mut store_lock = store.lock().await;
let retrieved_struct = store_lock.get().await;
assert_eq!(retrieved_struct, intl_settings.clone().into());
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_intl_e2e_set_twice() {
// Create and fetch a store from device storage so we can read stored value for testing.
let factory = InMemoryStorageFactory::create();
let store =
factory.lock().await.get_device_storage::<IntlInfo>(StorageAccessContext::Test, CONTEXT_ID);
let intl_service = create_test_intl_env(factory).await;
// Initial value is not None.
let settings = intl_service.watch2().await.expect("watch completed");
assert_eq!(
settings.time_zone_id,
Some(fidl_fuchsia_intl::TimeZoneId { id: "UTC".to_string() })
);
assert_eq!(
settings.locales,
Some(vec![fidl_fuchsia_intl::LocaleId { id: "en-US".to_string() }])
);
assert_eq!(settings.temperature_unit, Some(fidl_fuchsia_intl::TemperatureUnit::Celsius));
assert_eq!(settings.hour_cycle, Some(fidl_fuchsia_settings::HourCycle::H12));
// Set new values.
let mut intl_settings = fidl_fuchsia_settings::IntlSettings::empty();
let updated_timezone = "GMT";
intl_settings.time_zone_id =
Some(fidl_fuchsia_intl::TimeZoneId { id: updated_timezone.to_string() });
intl_settings.hour_cycle = Some(fidl_fuchsia_settings::HourCycle::H24);
intl_service.set(intl_settings).await.expect("set completed").expect("set successful");
// Try to set to a new value: this second set should succeed too.
let mut intl_settings = fidl_fuchsia_settings::IntlSettings::empty();
let updated_timezone = "PST";
intl_settings.time_zone_id =
Some(fidl_fuchsia_intl::TimeZoneId { id: updated_timezone.to_string() });
intl_service.set(intl_settings).await.expect("set completed").expect("repeated set successful");
// Verify the value we set is persisted in DeviceStorage.
let mut store_lock = store.lock().await;
let retrieved_struct = store_lock.get().await;
assert_eq!(retrieved_struct.time_zone_id.unwrap(), updated_timezone);
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_intl_e2e_idempotent_set() {
// Create and fetch a store from device storage so we can read stored value for testing.
let factory = InMemoryStorageFactory::create();
let store =
factory.lock().await.get_device_storage::<IntlInfo>(StorageAccessContext::Test, CONTEXT_ID);
let intl_service = create_test_intl_env(factory).await;
// Check if the initial value is correct.
let settings = intl_service.watch2().await.expect("watch completed");
assert_eq!(
settings.time_zone_id,
Some(fidl_fuchsia_intl::TimeZoneId { id: "UTC".to_string() })
);
assert_eq!(
settings.locales,
Some(vec![fidl_fuchsia_intl::LocaleId { id: "en-US".to_string() }])
);
assert_eq!(settings.temperature_unit, Some(fidl_fuchsia_intl::TemperatureUnit::Celsius));
assert_eq!(settings.hour_cycle, Some(fidl_fuchsia_settings::HourCycle::H12));
// Set new values.
let mut intl_settings = fidl_fuchsia_settings::IntlSettings::empty();
let updated_timezone = "GMT";
intl_settings.time_zone_id =
Some(fidl_fuchsia_intl::TimeZoneId { id: updated_timezone.to_string() });
intl_service.set(intl_settings).await.expect("set completed").expect("set successful");
// Try to set again to the same value: this second set should succeed.
let mut intl_settings = fidl_fuchsia_settings::IntlSettings::empty();
intl_settings.time_zone_id =
Some(fidl_fuchsia_intl::TimeZoneId { id: updated_timezone.to_string() });
intl_service.set(intl_settings).await.expect("set completed").expect("repeated set successful");
// Verify the value we set is persisted in DeviceStorage.
let mut store_lock = store.lock().await;
let retrieved_struct = store_lock.get().await;
assert_eq!(retrieved_struct.time_zone_id.unwrap(), updated_timezone);
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_intl_invalid_timezone() {
const INITIAL_TIME_ZONE: &'static str = "GMT";
let factory = InMemoryStorageFactory::create();
let intl_service = create_test_intl_env(factory).await;
// Set a real value.
let mut intl_settings = fidl_fuchsia_settings::IntlSettings::empty();
intl_settings.time_zone_id =
Some(fidl_fuchsia_intl::TimeZoneId { id: INITIAL_TIME_ZONE.to_string() });
intl_service.set(intl_settings).await.expect("set completed").expect("set successful");
// Set with an invalid timezone value.
let mut intl_settings = fidl_fuchsia_settings::IntlSettings::empty();
let updated_timezone = "not_a_real_time_zone";
intl_settings.time_zone_id =
Some(fidl_fuchsia_intl::TimeZoneId { id: updated_timezone.to_string() });
intl_service.set(intl_settings).await.expect("set completed").expect_err("invalid");
// Verify the returned when watching hasn't changed.
let settings = intl_service.watch2().await.expect("watch completed");
assert_eq!(
settings.time_zone_id,
Some(fidl_fuchsia_intl::TimeZoneId { id: INITIAL_TIME_ZONE.to_string() })
);
}
#[fuchsia_async::run_until_stalled(test)]
async fn test_channel_failure_watch2() {
let intl_service = create_intl_test_env_with_failures(InMemoryStorageFactory::create()).await;
let result = intl_service.watch2().await;
assert!(result.is_err());
assert_eq!(
ClientChannelClosed(Status::INTERNAL).to_string(),
result.err().unwrap().to_string()
);
}