use std::collections::HashMap;
use std::fmt::Display;
use std::str::FromStr;
use super::identifiable::CloneIdentifiable;
use super::{NameValuePair, Selection};
use crate::{
Disabled, Identifiable, SelectedParameters, Validated, ValidationState, add_validation_error, remove_validation_error, utility::*
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use serde_with::base64::{Base64, Standard};
use serde_with::formats::Unpadded;
use serde_with::serde_as;
use xmltojson::to_json;
pub fn default_runs() -> usize {
1
}
fn default_redirects() -> usize {
10
}
#[derive(Serialize, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "UPPERCASE")]
pub enum RequestMethod {
Get,
Post,
Put,
Delete,
Patch,
Head,
Options,
}
#[serde_as]
#[derive(Serialize, Deserialize, PartialEq, Clone)]
#[serde(tag = "type")]
pub enum RequestBody {
Text {
data: String,
},
#[serde(rename = "JSON")]
JSON {
data: String,
},
#[serde(rename = "XML")]
XML {
data: String,
},
Form {
data: Vec<NameValuePair>,
},
Raw {
#[serde_as(as = "Base64<Standard, Unpadded>")]
data: Vec<u8>,
},
}
#[derive(Serialize, Deserialize, PartialEq, Clone, Default)]
#[serde(rename_all = "UPPERCASE")]
pub enum ExecutionConcurrency {
#[default]
Sequential,
Concurrent,
}
#[derive(Serialize, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Request {
#[serde(default = "generate_uuid")]
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "std::ops::Not::not", default="bool::default")]
pub disabled: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub key: Option<String>,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub method: Option<RequestMethod>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<Vec<NameValuePair>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_string_params: Option<Vec<NameValuePair>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<RequestBody>,
#[serde(default = "bool::default", skip_serializing_if = "std::ops::Not::not")]
pub keep_alive: bool,
#[serde(default = "bool::default", skip_serializing_if = "std::ops::Not::not")]
pub accept_invalid_certs: bool,
#[serde(default = "default_redirects")]
pub number_of_redirects: usize,
#[serde(default = "default_runs")]
pub runs: usize,
#[serde(default)]
pub multi_run_execution: ExecutionConcurrency,
#[serde(skip_serializing_if = "Option::is_none")]
pub test: Option<String>,
#[serde(default = "Selection::default")]
pub selected_scenario: Selection,
#[serde(default = "Selection::default")]
pub selected_authorization: Selection,
#[serde(default = "Selection::default")]
pub selected_certificate: Selection,
#[serde(default = "Selection::default")]
pub selected_proxy: Selection,
#[serde(default = "Selection::default")]
pub selected_data: Selection,
#[serde(default, skip_serializing_if = "ValidationState::is_empty")]
pub validation_state: ValidationState,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub validation_warnings: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub validation_errors: Option<HashMap<String, String>>,
}
#[derive(Serialize, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RequestGroup {
#[serde(default = "generate_uuid")]
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "std::ops::Not::not", default="bool::default")]
pub disabled: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub children: Option<Vec<RequestEntry>>,
#[serde(default)]
pub execution: ExecutionConcurrency,
#[serde(default = "default_runs")]
pub runs: usize,
#[serde(default)]
pub multi_run_execution: ExecutionConcurrency,
#[serde(skip_serializing_if = "Option::is_none")]
pub setup: Option<String>,
#[serde(default = "Selection::default")]
pub selected_scenario: Selection,
#[serde(default = "Selection::default")]
pub selected_authorization: Selection,
#[serde(default = "Selection::default")]
pub selected_certificate: Selection,
#[serde(default = "Selection::default")]
pub selected_proxy: Selection,
#[serde(default = "Selection::default")]
pub selected_data: Selection,
#[serde(default, skip_serializing_if = "ValidationState::is_empty")]
pub validation_state: ValidationState,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub validation_warnings: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub validation_errors: Option<HashMap<String, String>>,
}
#[derive(Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)]
pub enum RequestEntry {
Request(Request),
Group(RequestGroup),
}
impl Identifiable for RequestEntry {
fn get_id(&self) -> &str {
match self {
RequestEntry::Request(request) => request.get_id(),
RequestEntry::Group(group) => group.get_id(),
}
}
fn get_name(&self) -> &str {
match self {
RequestEntry::Request(request) => request.get_name(),
RequestEntry::Group(group) => group.get_name(),
}
}
fn get_title(&self) -> String {
match self {
RequestEntry::Request(request) => request.get_title(),
RequestEntry::Group(group) => group.get_title(),
}
}
}
impl Disabled for RequestEntry {
fn get_disabled(&self) -> bool {
match self {
RequestEntry::Request(request) => request.get_disabled(),
RequestEntry::Group(group) => group.get_disabled(),
}
}
}
impl Validated for RequestEntry {
fn get_validation_state(&self) -> ValidationState {
match self {
RequestEntry::Request(request) => request.validation_state,
RequestEntry::Group(group) => group.validation_state,
}
}
fn get_validation_warnings(&self) -> &Option<Vec<String>> {
match self {
RequestEntry::Request(request) => &request.validation_warnings,
RequestEntry::Group(group) => &group.validation_warnings,
}
}
fn set_validation_warnings(&mut self, warnings: Option<Vec<String>>) {
match self {
RequestEntry::Request(request) => request.set_validation_warnings(warnings),
RequestEntry::Group(group) => group.set_validation_warnings(warnings),
}
}
fn get_validation_errors(&self) -> &Option<HashMap<String, String>> {
match self {
RequestEntry::Request(request) => &request.validation_errors,
RequestEntry::Group(group) => &group.validation_errors,
}
}
fn set_validation_errors(&mut self, errors: Option<HashMap<String, String>>) {
match self {
RequestEntry::Request(request) => request.set_validation_errors(errors),
RequestEntry::Group(group) => group.set_validation_errors(errors),
}
}
}
impl CloneIdentifiable for RequestEntry {
fn clone_as_new(&self, new_name: String) -> Self {
match self {
RequestEntry::Request(request) => RequestEntry::Request(request.clone_as_new(new_name)),
RequestEntry::Group(group) => RequestEntry::Group(group.clone_as_new(new_name)),
}
}
}
impl RequestMethod {
pub fn as_str(&self) -> &'static str {
match self {
RequestMethod::Get => "GET",
RequestMethod::Post => "POST",
RequestMethod::Put => "PUT",
RequestMethod::Delete => "DELETE",
RequestMethod::Patch => "PATCH",
RequestMethod::Head => "HEAD",
RequestMethod::Options => "OPTIONS",
}
}
}
impl Display for Request {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}
impl Display for RequestGroup {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}
impl Default for Request {
fn default() -> Self {
Self {
id: generate_uuid(),
name: Default::default(),
disabled: false,
key: Default::default(),
validation_state: Default::default(),
test: Some(
r#"describe('status', () => {
it('equals 200', () => {
expect(response.status).to.equal(200)
})
})"#
.to_string(),
),
url: Default::default(),
method: Default::default(),
timeout: Default::default(),
headers: Default::default(),
query_string_params: Default::default(),
body: Default::default(),
keep_alive: Default::default(),
runs: 1,
multi_run_execution: ExecutionConcurrency::Sequential,
selected_scenario: Default::default(),
selected_authorization: Default::default(),
selected_certificate: Default::default(),
selected_proxy: Default::default(),
selected_data: Default::default(),
validation_warnings: Default::default(),
validation_errors: None,
accept_invalid_certs: false,
number_of_redirects: default_redirects(),
}
}
}
impl Identifiable for Request {
fn get_id(&self) -> &str {
&self.id
}
fn get_name(&self) -> &str {
&self.name
}
fn get_title(&self) -> String {
let name = self.get_name();
if name.is_empty() {
"(Unnamed)".to_string()
} else {
name.to_string()
}
}
}
impl CloneIdentifiable for Request {
fn clone_as_new(&self, new_name: String) -> Self {
let mut cloned = self.clone();
cloned.id = generate_uuid();
cloned.name = new_name;
cloned
}
}
impl Disabled for Request {
fn get_disabled(&self) -> bool {
self.disabled
}
}
impl Validated for Request {
fn get_validation_state(&self) -> ValidationState {
self.validation_state
}
fn get_validation_warnings(&self) -> &Option<Vec<String>> {
&self.validation_warnings
}
fn set_validation_warnings(&mut self, warnings: Option<Vec<String>>) {
self.validation_warnings = warnings;
self.validation_state =
ValidationState::from(&self.validation_warnings, &self.validation_errors);
}
fn get_validation_errors(&self) -> &Option<HashMap<String, String>> {
&self.validation_errors
}
fn set_validation_errors(&mut self, errors: Option<HashMap<String, String>>) {
self.validation_errors = errors;
self.validation_state =
ValidationState::from(&self.validation_warnings, &self.validation_errors);
}
}
impl Request {
pub fn perform_validation(&mut self) {
self.validate_name();
self.validate_url();
}
pub fn validate_name(&mut self) {
let name_ok = ! self.name.trim().is_empty();
if name_ok {
remove_validation_error(&mut self.validation_errors, "name");
} else {
add_validation_error(&mut self.validation_errors, "name", "Name is required");
}
self.validation_state.set(ValidationState::ERROR, self.validation_errors.is_some());
}
pub fn validate_url(&mut self) {
let url_ok = ! self.url.trim().is_empty();
if url_ok {
remove_validation_error(&mut self.validation_errors, "url");
} else {
add_validation_error(&mut self.validation_errors, "url", "URL is required");
}
self.validation_state.set(ValidationState::ERROR, self.validation_errors.is_some());
}
}
impl Identifiable for RequestGroup {
fn get_id(&self) -> &str {
&self.id
}
fn get_name(&self) -> &str {
&self.name
}
fn get_title(&self) -> String {
let name = self.get_name();
if name.is_empty() {
"(Unnamed)".to_string()
} else {
name.to_string()
}
}
}
impl CloneIdentifiable for RequestGroup {
fn clone_as_new(&self, new_name: String) -> Self {
let mut cloned = self.clone();
cloned.id = generate_uuid();
cloned.name = new_name;
cloned
}
}
impl Disabled for RequestGroup {
fn get_disabled(&self) -> bool {
self.disabled
}
}
impl Default for RequestGroup {
fn default() -> Self {
Self {
id: generate_uuid(),
name: Default::default(),
disabled: false,
key: Default::default(),
children: Default::default(),
execution: ExecutionConcurrency::Sequential,
runs: 1,
multi_run_execution: ExecutionConcurrency::Sequential,
setup: None,
selected_scenario: Default::default(),
selected_authorization: Default::default(),
selected_certificate: Default::default(),
selected_proxy: Default::default(),
selected_data: Default::default(),
validation_state: Default::default(),
validation_warnings: None,
validation_errors: None,
}
}
}
impl Validated for RequestGroup {
fn get_validation_state(&self) -> ValidationState {
self.validation_state
}
fn get_validation_warnings(&self) -> &Option<Vec<String>> {
&self.validation_warnings
}
fn set_validation_warnings(&mut self, warnings: Option<Vec<String>>) {
self.validation_warnings = warnings;
self.validation_state =
ValidationState::from(&self.validation_warnings, &self.validation_errors);
}
fn get_validation_errors(&self) -> &Option<HashMap<String, String>> {
&self.validation_errors
}
fn set_validation_errors(&mut self, errors: Option<HashMap<String, String>>) {
self.validation_errors = errors;
self.validation_state =
ValidationState::from(&self.validation_warnings, &self.validation_errors);
}
}
impl RequestGroup {
pub fn perform_validation(&mut self) {
self.validate_name();
}
pub fn validate_name(&mut self) {
let name_ok = ! self.name.trim().is_empty();
if name_ok {
remove_validation_error(&mut self.validation_errors, "name");
} else {
add_validation_error(&mut self.validation_errors, "name", "Name is required");
}
self.validation_state.set(ValidationState::ERROR, self.validation_errors.is_some());
}
}
impl RequestEntry {
pub fn perform_validation(&mut self) {
match self {
RequestEntry::Request(request) => request.perform_validation(),
RequestEntry::Group(group) => group.perform_validation(),
}
}
pub fn get_runs(&self) -> usize {
match self {
RequestEntry::Request(info) => info.runs,
RequestEntry::Group(group) => group.runs,
}
}
pub fn set_runs(&mut self, runs: usize) {
match self {
RequestEntry::Request(info) => {
info.runs = runs;
}
RequestEntry::Group(group) => {
group.runs = runs;
}
}
}
}
impl Display for RequestEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RequestEntry::Request(i) => write!(f, "{}", i.name),
RequestEntry::Group(g) => write!(f, "{}", g.name),
}
}
}
impl SelectedParameters for RequestEntry {
fn selected_scenario(&self) -> &Selection {
match self {
RequestEntry::Request(info) => &info.selected_scenario,
RequestEntry::Group(group) => &group.selected_scenario,
}
}
fn selected_authorization(&self) -> &Selection {
match self {
RequestEntry::Request(info) => &info.selected_authorization,
RequestEntry::Group(group) => &group.selected_authorization,
}
}
fn selected_certificate(&self) -> &Selection {
match self {
RequestEntry::Request(info) => &info.selected_certificate,
RequestEntry::Group(group) => &group.selected_certificate,
}
}
fn selected_proxy(&self) -> &Selection {
match self {
RequestEntry::Request(info) => &info.selected_proxy,
RequestEntry::Group(group) => &group.selected_proxy,
}
}
fn selected_data(&self) -> &Selection {
match self {
RequestEntry::Request(info) => &info.selected_data,
RequestEntry::Group(group) => &group.selected_data,
}
}
fn selected_scenario_as_mut(&mut self) -> &mut Selection {
match self {
RequestEntry::Request(info) => &mut info.selected_scenario,
RequestEntry::Group(group) => &mut group.selected_scenario,
}
}
fn selected_authorization_as_mut(&mut self) -> &mut Selection {
match self {
RequestEntry::Request(info) => &mut info.selected_authorization,
RequestEntry::Group(group) => &mut group.selected_authorization,
}
}
fn selected_certificate_as_mut(&mut self) -> &mut Selection {
match self {
RequestEntry::Request(info) => &mut info.selected_certificate,
RequestEntry::Group(group) => &mut group.selected_certificate,
}
}
fn selected_proxy_as_mut(&mut self) -> &mut Selection {
match self {
RequestEntry::Request(info) => &mut info.selected_proxy,
RequestEntry::Group(group) => &mut group.selected_proxy,
}
}
fn selected_data_as_mut(&mut self) -> &mut Selection {
match self {
RequestEntry::Request(info) => &mut info.selected_data,
RequestEntry::Group(group) => &mut group.selected_data,
}
}
}
#[serde_as]
#[derive(Serialize, Deserialize, PartialEq, Clone)]
#[serde(tag = "type")]
pub enum StoredRequestBody {
Text {
data: String,
},
#[serde(rename = "JSON")]
JSON {
data: Option<Value>,
formatted: Option<String>,
},
#[serde(rename = "XML")]
XML {
formatted: Option<String>,
},
Form {
data: Vec<NameValuePair>,
},
Raw {
#[serde_as(as = "Base64<Standard, Unpadded>")]
data: Vec<u8>,
},
}
#[derive(Serialize, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct StoredRequest {
#[serde(default = "generate_uuid")]
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "std::ops::Not::not", default="bool::default")]
pub disabled: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub test: Option<String>,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub method: Option<RequestMethod>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<Vec<NameValuePair>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_string_params: Option<Vec<NameValuePair>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<StoredRequestBody>,
#[serde(default = "bool::default", skip_serializing_if = "std::ops::Not::not")]
pub keep_alive: bool,
#[serde(default = "bool::default", skip_serializing_if = "std::ops::Not::not")]
pub accept_invalid_certs: bool,
#[serde(default = "default_redirects")]
pub number_of_redirects: usize,
#[serde(default = "default_runs")]
pub runs: usize,
#[serde(default)]
pub multi_run_execution: ExecutionConcurrency,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_scenario: Selection,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_authorization: Selection,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_certificate: Selection,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_proxy: Selection,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_data: Selection,
}
#[derive(Serialize, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct StoredRequestGroup {
#[serde(default = "generate_uuid")]
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "std::ops::Not::not", default="bool::default")]
pub disabled: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub key: Option<String>,
pub children: Option<Vec<StoredRequestEntry>>,
#[serde(default)]
pub execution: ExecutionConcurrency,
#[serde(default = "default_runs")]
pub runs: usize,
#[serde(default)]
pub multi_run_execution: ExecutionConcurrency,
#[serde(skip_serializing_if = "Option::is_none")]
pub setup: Option<String>,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_scenario: Selection,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_authorization: Selection,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_certificate: Selection,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_proxy: Selection,
#[serde(skip_serializing_if = "Selection::is_default", default = "Selection::default")]
pub selected_data: Selection,
}
#[derive(Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)]
pub enum StoredRequestEntry {
Request(StoredRequest),
Group(StoredRequestGroup),
}
impl From<RequestEntry> for StoredRequestEntry {
fn from(entry: RequestEntry) -> Self {
match entry {
RequestEntry::Request(request) => StoredRequestEntry::Request(StoredRequest {
id: request.id,
name: request.name,
disabled: request.disabled,
key: request.key,
test: request.test,
url: request.url,
method: request.method,
timeout: request.timeout,
headers: request.headers,
query_string_params: request.query_string_params,
body: match request.body {
Some(body) => match body {
RequestBody::Text { data } => Some(StoredRequestBody::Text { data }),
RequestBody::JSON { data } => {
let data_to_save = Value::from_str(&data).ok();
Some(StoredRequestBody::JSON {
data: data_to_save,
formatted: Some(data),
})
}
RequestBody::XML { data } => {
let data_to_save = to_json(&data).ok();
Some(StoredRequestBody::JSON {
data: data_to_save,
formatted: Some(data),
})
}
RequestBody::Form { data } => Some(StoredRequestBody::Form { data }),
RequestBody::Raw { data } => Some(StoredRequestBody::Raw { data }),
},
None => None,
},
keep_alive: request.keep_alive,
accept_invalid_certs: request.accept_invalid_certs,
number_of_redirects: request.number_of_redirects,
runs: request.runs,
multi_run_execution: request.multi_run_execution,
selected_scenario: request.selected_scenario,
selected_authorization: request.selected_authorization,
selected_certificate: request.selected_certificate,
selected_proxy: request.selected_proxy,
selected_data: request.selected_data,
}),
RequestEntry::Group(group) => StoredRequestEntry::Group(StoredRequestGroup {
id: group.id,
name: group.name,
disabled: group.disabled,
key: group.key,
children: if let Some(children) = group.children && ! children.is_empty() {
Some(
children
.into_iter()
.map(StoredRequestEntry::from)
.collect()
)
} else {
None
},
execution: group.execution,
runs: group.runs,
multi_run_execution: group.multi_run_execution,
setup: group.setup,
selected_scenario: group.selected_scenario,
selected_authorization: group.selected_authorization,
selected_certificate: group.selected_certificate,
selected_proxy: group.selected_proxy,
selected_data: group.selected_data,
}),
}
}
}
impl From<StoredRequestEntry> for RequestEntry {
fn from(stored_entry: StoredRequestEntry) -> Self {
match stored_entry {
StoredRequestEntry::Request(stored_request) => RequestEntry::Request(Request {
id: stored_request.id,
name: stored_request.name,
disabled: stored_request.disabled,
key: stored_request.key,
validation_state: Default::default(),
test: stored_request.test,
url: stored_request.url,
method: stored_request.method,
timeout: stored_request.timeout,
headers: stored_request.headers,
query_string_params: stored_request.query_string_params,
body: match stored_request.body {
Some(body) => match body {
StoredRequestBody::Text { data } => Some(RequestBody::Text { data }),
StoredRequestBody::JSON { formatted, data } => {
let result_data: Option<String>;
if let Some(s) = formatted {
result_data = Some(s);
} else if let Some(v) = data {
if let Ok(s) = serde_json::to_string_pretty(&v) {
result_data = Some(s);
} else {
result_data = None;
}
} else {
result_data = None;
}
result_data.map(|d| RequestBody::JSON { data: d })
}
StoredRequestBody::XML { formatted } => Some(RequestBody::XML {
data: match formatted {
Some(text) => text,
None => "".to_string(),
},
}),
StoredRequestBody::Form { data } => Some(RequestBody::Form { data }),
StoredRequestBody::Raw { data } => Some(RequestBody::Raw { data }),
},
None => None,
},
keep_alive: stored_request.keep_alive,
accept_invalid_certs: stored_request.accept_invalid_certs,
number_of_redirects: stored_request.number_of_redirects,
runs: stored_request.runs,
multi_run_execution: stored_request.multi_run_execution,
selected_scenario: stored_request.selected_scenario,
selected_authorization: stored_request.selected_authorization,
selected_certificate: stored_request.selected_certificate,
selected_proxy: stored_request.selected_proxy,
selected_data: stored_request.selected_data,
validation_warnings: None,
validation_errors: None,
}),
StoredRequestEntry::Group(stored_group) => RequestEntry::Group(RequestGroup {
id: stored_group.id,
name: stored_group.name,
disabled: stored_group.disabled,
key: stored_group.key,
validation_state: Default::default(),
children: if let Some(children) = stored_group.children && ! children.is_empty() {
Some(
children
.into_iter()
.map(RequestEntry::from)
.collect()
)
} else {
None
},
execution: stored_group.execution,
runs: stored_group.runs,
multi_run_execution: stored_group.multi_run_execution,
setup: stored_group.setup,
selected_scenario: stored_group.selected_scenario,
selected_authorization: stored_group.selected_authorization,
selected_certificate: stored_group.selected_certificate,
selected_proxy: stored_group.selected_proxy,
selected_data: stored_group.selected_data,
validation_warnings: None,
validation_errors: None,
}),
}
}
}