From 5d69304b473369432da9fed04361d1b7dca8e52b Mon Sep 17 00:00:00 2001 From: Evgenii Matsiuk Date: Mon, 18 Nov 2024 13:31:21 +0300 Subject: [PATCH] feat: ios permission support (#65) --- src/api.rs | 7 ++++++- src/cli/android/mod.rs | 1 + src/cli/ios/mod.rs | 35 +++++++++++++++++++++++++++++++++++ src/cli/mod.rs | 10 ++++++++++ src/errors.rs | 4 ++++ src/interactor.rs | 2 ++ 6 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/api.rs b/src/api.rs index f2e5aeb..59ebdd7 100644 --- a/src/api.rs +++ b/src/api.rs @@ -59,6 +59,7 @@ pub trait RapiClient { project: Option, application_bundle: Option>, library_bundle: Option>, + granted_permission: Option>, ) -> Result; async fn get_run(&self, id: &str) -> Result; @@ -156,6 +157,7 @@ impl RapiClient for RapiReqwestClient { project: Option, application_bundle: Option>, library_bundle: Option>, + granted_permission: Option>, ) -> Result { let url = format!("{}/v2/run", self.base_url); let params = [("api_key", self.api_key.clone())]; @@ -281,7 +283,8 @@ impl RapiClient for RapiReqwestClient { test_timeout_max: test_timeout_max.clone(), env_args: env_args_map, test_env_args: test_env_args_map, - bundles, + bundles: bundles, + granted_permission: granted_permission.clone(), }; let response = self.client.post(url).json(&create_request).send().await?; @@ -612,6 +615,8 @@ struct CreateRunRequest { test_env_args: Option>, #[serde(rename = "bundles", default)] bundles: Option>, + #[serde(rename = "granted_permission", default)] + granted_permission: Option>, } #[derive(Serialize, Deserialize, Debug)] diff --git a/src/cli/android/mod.rs b/src/cli/android/mod.rs index f5a147d..cd53891 100644 --- a/src/cli/android/mod.rs +++ b/src/cli/android/mod.rs @@ -288,6 +288,7 @@ If you are interesting in library testing then please use advance mode with --li common.project, transformed_application_bundle, library_bundle, + None, ) .await } diff --git a/src/cli/ios/mod.rs b/src/cli/ios/mod.rs index 59c74ff..9ad8aea 100644 --- a/src/cli/ios/mod.rs +++ b/src/cli/ios/mod.rs @@ -2,6 +2,7 @@ use std::ffi::OsStr; use std::fmt::Display; use anyhow::Result; +use std::collections::HashSet; use tokio::fs::File; use walkdir::WalkDir; @@ -189,6 +190,23 @@ pub(crate) async fn infer_parameters( Ok((device.unwrap(), xcode_version.unwrap(), os_version.unwrap())) } +fn get_allowed_permissions() -> HashSet<&'static str> { + HashSet::from([ + "calendar", + "contacts-limited", + "contacts", + "location", + "location-always", + "photos-add", + "photos", + "media-library", + "microphone", + "motion", + "reminders", + "siri", + ]) +} + pub(crate) async fn run( application: std::path::PathBuf, test_application: std::path::PathBuf, @@ -205,6 +223,7 @@ pub(crate) async fn run( analytics_args: super::AnalyticsArgs, test_timeout_default: Option, test_timeout_max: Option, + granted_permission: Option>, ) -> Result { let (device, xcode_version, os_version) = if device.is_none() && xcode_version.is_none() @@ -278,6 +297,21 @@ Second example: If you choose --xcode-version 15.4 --os-version 17.5 then you wi } } + if let Some(granted_permission) = granted_permission.clone() { + let allowed_permissions = get_allowed_permissions(); + let invalid_permissions: Vec<_> = granted_permission + .iter() + .filter(|perm| !allowed_permissions.contains(perm.as_str())) + .cloned() + .collect(); + + if !invalid_permissions.is_empty() { + return Err(InputError::IncorrectPermission { + permissions: invalid_permissions, + })?; + } + } + let present_wait: bool = match common.wait { None => true, Some(true) => true, @@ -321,6 +355,7 @@ Second example: If you choose --xcode-version 15.4 --os-version 17.5 then you wi common.project, None, None, + granted_permission, ) .await } diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 3060862..a9371af 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -93,6 +93,7 @@ impl Cli { analytics_args, test_timeout_default, test_timeout_max, + granted_permission, } => { ios::run( application, @@ -110,6 +111,7 @@ impl Cli { analytics_args, test_timeout_default, test_timeout_max, + granted_permission, ) .await } @@ -547,5 +549,13 @@ Example: '--library-bundle apks/library1-debug-androidTest.apk --library-bundle help = "Maximum test timeout in seconds, overriding all other test timeout settings" )] test_timeout_max: Option, + + #[arg( + long, + help = "Grant permission to application. +Important: Granting is conducted before each test batch (not each test). If you need to grant before each test, please use --isolated mode. +Available permissions: calendar, contacts-limited, contacts, location, location-always, photos-add, photos, media-library, microphone, motion, reminders, siri." + )] + granted_permission: Option>, }, } diff --git a/src/errors.rs b/src/errors.rs index 13a7ef7..89d7e03 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -87,6 +87,10 @@ pub enum InputError { #[error("{arg} arg should be a positive number")] NonPositiveValue { arg: String }, + + #[error("The following permissions could not be granted: [{permissions:?}]. +Available permissions: calendar, contacts-limited, contacts, location, location-always, photos-add, photos, media-library, microphone, motion, reminders, siri.")] + IncorrectPermission { permissions: Vec }, } #[derive(Error, Debug)] diff --git a/src/interactor.rs b/src/interactor.rs index 29de38f..fa3b531 100644 --- a/src/interactor.rs +++ b/src/interactor.rs @@ -135,6 +135,7 @@ impl TriggerTestRunInteractor { project: Option, application_bundle: Option>, library_bundle: Option>, + granted_permission: Option>, ) -> Result { let client = RapiReqwestClient::new(base_url, api_key); let steps = match (wait, output) { @@ -178,6 +179,7 @@ impl TriggerTestRunInteractor { project, application_bundle, library_bundle, + granted_permission, ) .await?;