| // Copyright 2020 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 crate::agent::storage::storage_factory::testing::InMemoryStorageFactory; |
| use crate::base::{SettingInfo, SettingType, UnknownInfo as SettingUnknownInfo}; |
| use crate::handler::base::{Payload, Request, Response as SettingResponse}; |
| use crate::handler::setting_handler::SettingHandlerResult; |
| use crate::message::base::{Audience, MessengerType}; |
| use crate::message::MessageHubUtil; |
| use crate::policy::policy_handler::{PolicyHandler, RequestTransform, ResponseTransform}; |
| use crate::policy::policy_handler_factory_impl::PolicyHandlerFactoryImpl; |
| use crate::policy::policy_proxy::PolicyProxy; |
| use crate::policy::{ |
| self as policy_base, BoxedHandler, PolicyHandlerFactory, PolicyType, UnknownInfo, |
| }; |
| use crate::service; |
| use crate::tests::message_utils::verify_payload; |
| use async_trait::async_trait; |
| use futures::future::BoxFuture; |
| use futures::lock::Mutex; |
| use std::convert::TryFrom; |
| use std::sync::atomic::AtomicU64; |
| use std::sync::Arc; |
| |
| static POLICY_TYPE: PolicyType = PolicyType::Unknown; |
| static SETTING_TYPE: SettingType = SettingType::Unknown; |
| static SETTING_REQUEST: Request = Request::Get; |
| static SETTING_REQUEST_PAYLOAD: Payload = Payload::Request(Request::Get); |
| static SETTING_REQUEST_PAYLOAD_2: Payload = Payload::Request(Request::Listen); |
| |
| static SETTING_RESPONSE: SettingResponse = Ok(Some(SettingInfo::Unknown(SettingUnknownInfo(true)))); |
| |
| static SETTING_RESPONSE_PAYLOAD: Payload = |
| Payload::Response(Ok(Some(SettingInfo::Unknown(SettingUnknownInfo(true))))); |
| |
| static SETTING_RESPONSE_MODIFIED: SettingResponse = |
| Ok(Some(SettingInfo::Unknown(SettingUnknownInfo(false)))); |
| |
| static SETTING_RESULT_NO_RESPONSE: SettingResponse = Ok(None); |
| static SETTING_RESULT_NO_RESPONSE_SWITCHBOARD: SettingHandlerResult = Ok(None); |
| |
| /// `FakePolicyHandler` always returns the provided responses for handling policy/setting requests. |
| /// The following mappings are Vectors rather than HashMaps as some of the represented values do not |
| /// implement Hash (such as f32). |
| #[derive(Clone)] |
| struct FakePolicyHandlerBuilder { |
| policy_request_mapping: Vec<(policy_base::Request, policy_base::response::Response)>, |
| policy_response: policy_base::response::Response, |
| setting_request_mapping: Vec<(Request, RequestTransform)>, |
| setting_request_transform: Option<RequestTransform>, |
| setting_response_mapping: Vec<(SettingResponse, ResponseTransform)>, |
| setting_response_transform: Option<ResponseTransform>, |
| } |
| |
| impl FakePolicyHandlerBuilder { |
| fn new() -> Self { |
| Self { |
| policy_request_mapping: Vec::new(), |
| policy_response: Err(policy_base::response::Error::Unexpected), |
| setting_request_mapping: Vec::new(), |
| setting_request_transform: None, |
| setting_response_mapping: Vec::new(), |
| setting_response_transform: None, |
| } |
| } |
| |
| #[allow(dead_code)] |
| fn add_policy_request_mapping( |
| mut self, |
| request: policy_base::Request, |
| response: policy_base::response::Response, |
| ) -> Self { |
| self.policy_request_mapping.retain(|(key, _)| *key != request); |
| self.policy_request_mapping.push((request, response)); |
| |
| self |
| } |
| |
| fn set_policy_response(mut self, response: policy_base::response::Response) -> Self { |
| self.policy_response = response; |
| |
| self |
| } |
| |
| fn add_request_mapping(mut self, request: Request, transform: RequestTransform) -> Self { |
| self.setting_request_mapping.retain(|(key, _)| *key != request); |
| self.setting_request_mapping.push((request, transform)); |
| |
| self |
| } |
| |
| fn set_request_transform(mut self, transform: RequestTransform) -> Self { |
| self.setting_request_transform = Some(transform); |
| |
| self |
| } |
| |
| fn add_response_mapping( |
| mut self, |
| response: SettingResponse, |
| transform: ResponseTransform, |
| ) -> Self { |
| self.setting_response_mapping.retain(|(key, _)| *key != response); |
| self.setting_response_mapping.push((response, transform)); |
| |
| self |
| } |
| |
| fn build(self) -> FakePolicyHandler { |
| FakePolicyHandler { |
| policy_request_mapping: self.policy_request_mapping, |
| policy_response: self.policy_response, |
| setting_request_mapping: self.setting_request_mapping, |
| setting_request_transform: self.setting_request_transform, |
| setting_response_mapping: self.setting_response_mapping, |
| setting_response_transform: self.setting_response_transform, |
| } |
| } |
| } |
| |
| /// `FakePolicyHandler` always returns the provided responses for handling policy/setting requests. |
| #[derive(Clone)] |
| struct FakePolicyHandler { |
| policy_request_mapping: Vec<(policy_base::Request, policy_base::response::Response)>, |
| policy_response: policy_base::response::Response, |
| setting_request_mapping: Vec<(Request, RequestTransform)>, |
| setting_request_transform: Option<RequestTransform>, |
| setting_response_mapping: Vec<(SettingResponse, ResponseTransform)>, |
| setting_response_transform: Option<ResponseTransform>, |
| } |
| |
| #[async_trait] |
| impl PolicyHandler for FakePolicyHandler { |
| async fn handle_policy_request( |
| &mut self, |
| request: policy_base::Request, |
| ) -> policy_base::response::Response { |
| self.policy_request_mapping |
| .iter() |
| .find(|(key, _)| *key == request) |
| .map_or(self.policy_response.clone(), |x| x.1.clone()) |
| } |
| |
| async fn handle_setting_request(&mut self, request: Request) -> Option<RequestTransform> { |
| self.setting_request_transform.clone().or_else(|| { |
| self.setting_request_mapping |
| .iter() |
| .find(|(key, _)| *key == request) |
| .map(|x| x.1.clone()) |
| }) |
| } |
| |
| async fn handle_setting_response( |
| &mut self, |
| response: SettingResponse, |
| ) -> Option<ResponseTransform> { |
| self.setting_response_transform.clone().or_else(|| { |
| self.setting_response_mapping |
| .iter() |
| .find(|(key, _)| *key == response) |
| .map(|x| x.1.clone()) |
| }) |
| } |
| } |
| |
| /// Creates a handler factory with the given `FakePolicyHandler`. |
| fn create_handler_factory( |
| storage_factory: InMemoryStorageFactory, |
| policy_handler: FakePolicyHandler, |
| ) -> Arc<Mutex<dyn PolicyHandlerFactory + Send + Sync>> { |
| let mut handler_factory = PolicyHandlerFactoryImpl::new( |
| [POLICY_TYPE].iter().copied().collect(), |
| [SETTING_TYPE].iter().copied().collect(), |
| Arc::new(storage_factory), |
| Arc::new(AtomicU64::new(1)), |
| ); |
| handler_factory.register( |
| POLICY_TYPE, |
| Box::new(move |_| { |
| let handler_clone = policy_handler.clone(); |
| Box::pin(async move { Ok(Box::new(handler_clone) as BoxedHandler) }) |
| }), |
| ); |
| Arc::new(Mutex::new(handler_factory)) |
| } |
| |
| // Simple test that verifies the constructor succeeds. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_policy_proxy_creation() { |
| // Create the policy proxy. |
| let policy_proxy_result = PolicyProxy::create( |
| POLICY_TYPE, |
| create_handler_factory( |
| InMemoryStorageFactory::new(), |
| FakePolicyHandlerBuilder::new() |
| .set_policy_response(Ok(policy_base::response::Payload::PolicyInfo( |
| UnknownInfo(true).into(), |
| ))) |
| .build(), |
| ), |
| service::MessageHub::create_hub(), |
| ) |
| .await; |
| |
| // Creation is successful. |
| assert!(policy_proxy_result.is_ok()); |
| } |
| |
| // Verify that policy messages sent to the proxy are passed to the handler, then that the handler's |
| // response is returned via the proxy. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_policy_messages_passed_to_handler() { |
| let policy_request = policy_base::Request::Get; |
| let policy_payload = policy_base::response::Payload::PolicyInfo(UnknownInfo(true).into()); |
| |
| let service_delegate = service::MessageHub::create_hub(); |
| // Initialize the policy proxy and a messenger to communicate with it. |
| let _ = PolicyProxy::create( |
| POLICY_TYPE, |
| create_handler_factory( |
| InMemoryStorageFactory::new(), |
| FakePolicyHandlerBuilder::new().set_policy_response(Ok(policy_payload.clone())).build(), |
| ), |
| service_delegate.clone(), |
| ) |
| .await; |
| |
| let (policy_messenger, _) = |
| service_delegate.create(MessengerType::Unbound).await.expect("policy messenger created"); |
| |
| // Send a policy request to the policy proxy. |
| let mut policy_send_receptor = policy_messenger |
| .message( |
| policy_base::Payload::Request(policy_request).into(), |
| Audience::Address(service::Address::PolicyHandler(POLICY_TYPE)), |
| ) |
| .send(); |
| |
| // Wait for a response. |
| let (policy_response, _) = policy_send_receptor |
| .next_of::<policy_base::Payload>() |
| .await |
| .expect("policy response received"); |
| |
| // Policy handler returned its response through the policy proxy, back to the client. |
| assert_eq!(policy_response, policy_base::Payload::Response(Ok(policy_payload))); |
| } |
| |
| // Verify that when the policy handler doesn't take any action on a setting request, it will |
| // continue on to its intended destination without interference. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_setting_message_pass_through() { |
| let delegate = service::MessageHub::create_hub(); |
| let (_, mut setting_proxy_receptor) = delegate |
| .create(MessengerType::Addressable(service::Address::Handler(SETTING_TYPE))) |
| .await |
| .expect("setting_proxy created"); |
| |
| let _ = PolicyProxy::create( |
| POLICY_TYPE, |
| create_handler_factory( |
| InMemoryStorageFactory::new(), |
| FakePolicyHandlerBuilder::new().build(), |
| ), |
| delegate.clone(), |
| ) |
| .await; |
| |
| // Create a messenger that represents the setting caller. |
| let (messenger, _) = delegate.create(MessengerType::Unbound).await.expect("messenger created"); |
| |
| // Send a setting request to the setting handler. |
| let mut settings_send_receptor = messenger |
| .message( |
| SETTING_REQUEST_PAYLOAD.clone().into(), |
| service::message::Audience::Address(service::Address::Handler(SETTING_TYPE)), |
| ) |
| .send(); |
| |
| // Verify the setting handler received the original payload, then reply with a response. |
| verify_payload( |
| SETTING_REQUEST_PAYLOAD.clone().into(), |
| &mut setting_proxy_receptor, |
| Some(Box::new(|client| -> BoxFuture<'_, ()> { |
| Box::pin(async move { |
| let _ = client.reply(SETTING_RESPONSE_PAYLOAD.clone().into()).send(); |
| }) |
| })), |
| ) |
| .await; |
| |
| // Verify that the requestor receives the response the setting handler sent. |
| verify_payload( |
| service::Payload::try_from(SETTING_RESPONSE_PAYLOAD.clone()) |
| .expect("should derive payload"), |
| &mut settings_send_receptor, |
| None, |
| ) |
| .await; |
| } |
| |
| // Verify that when the policy handler returns a result to give directly to the client, that the |
| // given result is provided back to the requestor without reaching the setting handler. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_setting_message_result_replacement() { |
| let delegate = service::MessageHub::create_hub(); |
| |
| let (_, mut setting_proxy_receptor) = delegate |
| .create(MessengerType::Addressable(service::Address::Handler(SETTING_TYPE))) |
| .await |
| .expect("setting_proxy created"); |
| |
| let _ = PolicyProxy::create( |
| POLICY_TYPE, |
| create_handler_factory( |
| InMemoryStorageFactory::new(), |
| FakePolicyHandlerBuilder::new() |
| // Include a different response than the original as the |
| // transform result, so that the original request is ignored. |
| .add_request_mapping( |
| SETTING_REQUEST.clone(), |
| RequestTransform::Result(SETTING_RESULT_NO_RESPONSE_SWITCHBOARD.clone()), |
| ) |
| .build(), |
| ), |
| delegate.clone(), |
| ) |
| .await; |
| |
| // the address of the setting handler |
| let setting_handler_address = service::Address::Handler(SETTING_TYPE); |
| |
| // Create a messenger that represents an outside caller. |
| let (messenger, _) = delegate.create(MessengerType::Unbound).await.expect("messenger created"); |
| |
| // Send a setting request from the requestor to the setting handler. |
| let mut settings_send_receptor = messenger |
| .message( |
| SETTING_REQUEST_PAYLOAD.clone().into(), |
| service::message::Audience::Address(setting_handler_address), |
| ) |
| .send(); |
| |
| // We want to verify that the setting handler didn't receive the original message from the |
| // client. To do this, we create a new messenger and send a message to the setting handler |
| // and wait for it to be received. Since messages are delivered in-order, if the setting handler |
| // received the original message, this will fail. |
| let (test_messenger, _) = |
| delegate.create(MessengerType::Unbound).await.expect("messenger created"); |
| |
| let _ = test_messenger |
| .message( |
| SETTING_REQUEST_PAYLOAD_2.clone().into(), |
| service::message::Audience::Address(setting_handler_address), |
| ) |
| .send(); |
| |
| verify_payload( |
| service::Payload::try_from(SETTING_REQUEST_PAYLOAD_2.clone()) |
| .expect("should derive payload"), |
| &mut setting_proxy_receptor, |
| None, |
| ) |
| .await; |
| |
| // Verify that the client receives the response that the policy handler returned. |
| verify_payload( |
| service::Payload::try_from(Payload::Response(SETTING_RESULT_NO_RESPONSE.clone())) |
| .expect("should derive payload"), |
| &mut settings_send_receptor, |
| None, |
| ) |
| .await; |
| } |
| |
| // Verify that when the policy handler returns a new request payload, that the payload is sent to |
| // the setting handler in place of the original message. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_setting_message_payload_replacement() { |
| // Original request that will be sent by the client. |
| let setting_request_1 = Request::Get; |
| let setting_request_1_payload = Payload::Request(setting_request_1.clone()); |
| |
| // Modified request that the policy handler will return. |
| let setting_request_2 = Request::Restore; |
| let setting_request_2_payload = Payload::Request(setting_request_2.clone()); |
| |
| let delegate = service::MessageHub::create_hub(); |
| |
| let setting_handler_address = service::Address::Handler(SETTING_TYPE); |
| |
| let (_, mut setting_proxy_receptor) = delegate |
| .create(MessengerType::Addressable(setting_handler_address)) |
| .await |
| .expect("setting proxy messenger created"); |
| |
| let _ = PolicyProxy::create( |
| POLICY_TYPE, |
| create_handler_factory( |
| InMemoryStorageFactory::new(), |
| // Fake handler will return request 2 to be sent to the setting handler |
| FakePolicyHandlerBuilder::new() |
| .set_request_transform(RequestTransform::Request(setting_request_2)) |
| .build(), |
| ), |
| delegate.clone(), |
| ) |
| .await; |
| |
| // Create a messenger that represents the client. |
| let (messenger, _) = delegate.create(MessengerType::Unbound).await.expect("messenger created"); |
| |
| // Send a setting request from the client to the setting handler. |
| let mut settings_send_receptor = messenger |
| .message(setting_request_1_payload.into(), Audience::Address(setting_handler_address)) |
| .send(); |
| |
| // Verify the setting handler receives the payload that the policy handler specifies, not the |
| // original sent by the client. |
| verify_payload( |
| setting_request_2_payload.into(), |
| &mut setting_proxy_receptor, |
| Some(Box::new(|client| -> BoxFuture<'_, ()> { |
| Box::pin(async move { |
| let _ = client.reply(SETTING_RESPONSE_PAYLOAD.clone().into()).send(); |
| }) |
| })), |
| ) |
| .await; |
| |
| // Verify that the requestor receives the response that the setting handler returned. |
| verify_payload(SETTING_RESPONSE_PAYLOAD.clone().into(), &mut settings_send_receptor, None) |
| .await; |
| } |
| |
| // Verify that when the policy handler doesn't take any action on a setting event, it will |
| // continue on to its intended destination without interference. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_setting_response_pass_through() { |
| let delegate = service::MessageHub::create_hub(); |
| |
| let (setting_proxy_messenger, _) = delegate |
| .create(MessengerType::Addressable(service::Address::Handler(SETTING_TYPE))) |
| .await |
| .expect("setting proxy messenger created"); |
| |
| let _ = PolicyProxy::create( |
| POLICY_TYPE, |
| create_handler_factory( |
| InMemoryStorageFactory::new(), |
| FakePolicyHandlerBuilder::new().build(), |
| ), |
| delegate.clone(), |
| ) |
| .await; |
| |
| // Create a messenger that represents the client. |
| let (_, mut receptor) = |
| delegate.create(MessengerType::Unbound).await.expect("messenger created"); |
| |
| // Send a setting event from the setting proxy to the client. |
| let _ = setting_proxy_messenger |
| .message( |
| SETTING_RESPONSE_PAYLOAD.clone().into(), |
| Audience::Messenger(receptor.get_signature()), |
| ) |
| .send(); |
| |
| // Verify the client receives the event. |
| verify_payload(SETTING_RESPONSE_PAYLOAD.clone().into(), &mut receptor, None).await; |
| } |
| |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_setting_response_replace() { |
| let delegate = service::MessageHub::create_hub(); |
| let (setting_proxy_messenger, _) = delegate |
| .create(MessengerType::Addressable(service::Address::Handler(SETTING_TYPE))) |
| .await |
| .expect("setting proxy messenger created"); |
| |
| let _ = PolicyProxy::create( |
| POLICY_TYPE, |
| create_handler_factory( |
| InMemoryStorageFactory::new(), |
| FakePolicyHandlerBuilder::new() |
| .add_response_mapping( |
| SETTING_RESPONSE.clone(), |
| ResponseTransform::Response(SETTING_RESPONSE_MODIFIED.clone()), |
| ) |
| .build(), |
| ), |
| delegate.clone(), |
| ) |
| .await; |
| |
| // Create a messenger that represents the client. |
| let (_, mut receptor) = |
| delegate.create(MessengerType::Unbound).await.expect("messenger created"); |
| |
| // Send a setting request from the setting proxy to the client. |
| let _ = setting_proxy_messenger |
| .message( |
| SETTING_RESPONSE_PAYLOAD.clone().into(), |
| Audience::Messenger(receptor.get_signature()), |
| ) |
| .send(); |
| |
| // Verify the client receives the event. |
| verify_payload( |
| Payload::Response(SETTING_RESPONSE_MODIFIED.clone()).into(), |
| &mut receptor, |
| None, |
| ) |
| .await; |
| } |
| |
| // Exercises the main loop in the policy proxy by sending a series of messages |
| // and ensuring they're all answered. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_multiple_messages() { |
| let policy_request = policy_base::Request::Get; |
| let policy_payload = policy_base::response::Payload::PolicyInfo(UnknownInfo(true).into()); |
| |
| let delegate = service::MessageHub::create_hub(); |
| |
| let (_, _setting_proxy_receptor) = delegate |
| .create(MessengerType::Addressable(service::Address::Handler(SETTING_TYPE))) |
| .await |
| .expect("setting proxy messenger created"); |
| |
| // Initialize the policy proxy and a messenger to communicate with it. |
| let _ = PolicyProxy::create( |
| POLICY_TYPE, |
| create_handler_factory( |
| InMemoryStorageFactory::new(), |
| FakePolicyHandlerBuilder::new() |
| .set_policy_response(Ok(policy_payload.clone())) |
| .add_request_mapping( |
| SETTING_REQUEST.clone(), |
| RequestTransform::Result(SETTING_RESULT_NO_RESPONSE_SWITCHBOARD.clone()), |
| ) |
| .build(), |
| ), |
| delegate.clone(), |
| ) |
| .await; |
| |
| // Create a messenger for sending messages directly to the policy proxy. |
| let (policy_messenger, _) = |
| delegate.create(MessengerType::Unbound).await.expect("policy messenger created"); |
| |
| // Create a messenger that represents the client. |
| let (messenger, _) = delegate.create(MessengerType::Unbound).await.expect("messenger created"); |
| |
| // Send a few requests to the policy proxy. |
| for _ in 0..3 { |
| // Send a policy request. |
| let mut policy_send_receptor = policy_messenger |
| .message( |
| policy_base::Payload::Request(policy_request.clone()).into(), |
| Audience::Address(service::Address::PolicyHandler(POLICY_TYPE)), |
| ) |
| .send(); |
| |
| // Verify a policy response is returned each time. |
| verify_payload( |
| policy_base::Payload::Response(Ok(policy_payload.clone())).into(), |
| &mut policy_send_receptor, |
| None, |
| ) |
| .await; |
| |
| // Send a request that the policy proxy intercepts. |
| let mut settings_send_receptor = messenger |
| .message( |
| SETTING_REQUEST_PAYLOAD.clone().into(), |
| Audience::Address(service::Address::Handler(SETTING_TYPE)), |
| ) |
| .send(); |
| |
| // Verify that the client receives the response that the policy handler returns |
| // each time. |
| verify_payload( |
| Payload::Response(SETTING_RESULT_NO_RESPONSE.clone()).into(), |
| &mut settings_send_receptor, |
| None, |
| ) |
| .await; |
| } |
| } |