use std::collections::HashMap;
use url::Url;
#[cfg_attr(docsrs, doc(cfg(feature = "error-client")))]
#[cfg(feature = "error-client")]
use crate::error::error_client_builder::ErrorClientBuilder;
#[cfg_attr(docsrs, doc(cfg(feature = "session-client")))]
#[cfg(feature = "session-client")]
use crate::session::session_client_builder::SessionClientBuilder;
use super::builder_options::BuilderOptions;
use crate::common::client::client_type::ClientType;
#[derive(Debug)]
pub struct ClientBuilder;
impl ClientBuilder {
#[cfg_attr(docsrs, doc(cfg(feature = "error-client")))]
#[cfg(feature = "error-client")]
pub fn error() -> ErrorClientBuilder {
ErrorClientBuilder {
builder_internal: ClientBuilderInternal {
options: BuilderOptions {
client_type: ClientType::Error,
scheme: None,
url: Some(
Url::parse("https://notify.bugsnag.com/").unwrap(),
),
host: None,
port: None,
endpoint: None,
headers: Some(HashMap::new()),
},
api_key: None,
payload_version: "5".into(),
payload_version_override: None,
},
notifier: None,
events: None,
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "session-client")))]
#[cfg(feature = "session-client")]
pub fn session() -> SessionClientBuilder {
SessionClientBuilder {
builder_internal: ClientBuilderInternal {
options: BuilderOptions {
client_type: ClientType::Session,
scheme: None,
url: Some(
Url::parse("https://sessions.bugsnag.com/").unwrap(),
),
host: None,
port: None,
endpoint: None,
headers: Some(HashMap::new()),
},
api_key: None,
payload_version: "1.0".into(),
payload_version_override: None,
},
notifier: None,
app: None,
device: None,
sessions: None,
session_counts: None,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ClientBuilderInternal {
pub(crate) options: BuilderOptions,
pub(crate) api_key: Option<String>,
pub(crate) payload_version: String,
pub(crate) payload_version_override: Option<String>,
}
impl ClientBuilderInternal {
pub fn api_key(&self) -> Option<String> {
self.api_key.clone()
}
pub fn set_api_key<'a>(
&mut self,
key: impl Into<Option<&'a str>>,
) -> &mut Self {
self.api_key = key.into().map(|s| s.to_string());
self
}
pub fn client_type(&self) -> ClientType {
self.options.client_type
}
pub fn endpoint(&self) -> Option<String> {
self.options.endpoint.clone()
}
pub fn set_endpoint<'a>(
&mut self,
endpoint: impl Into<Option<&'a str>>,
) -> &mut Self {
self.options.endpoint = endpoint.into().map(|s| s.to_string());
self
}
pub fn headers(&self) -> Option<HashMap<String, String>> {
self.options.headers.clone()
}
pub fn add_header(
&mut self,
header_name: impl Into<String>,
header_value: impl Into<String>,
) -> &mut Self {
if self.options.headers.is_none() {
self.options.headers = Some(HashMap::new());
}
self.options
.headers
.as_mut()
.unwrap()
.insert(header_name.into(), header_value.into());
self
}
pub fn host(&self) -> Option<String> {
self.options.host.clone()
}
pub fn set_host<'a>(
&mut self,
host: impl Into<Option<&'a str>>,
) -> &mut Self {
self.options.host = host.into().map(|s| s.to_string());
self
}
pub fn payload_version(&self) -> String {
if self.payload_version_override.is_some() {
self.payload_version_override.clone().unwrap()
} else {
self.payload_version.clone()
}
}
pub fn set_payload_version<'a>(
&mut self,
payload_version: impl Into<Option<&'a str>>,
) -> &mut Self {
self.payload_version_override =
payload_version.into().map(|s| s.to_string());
self
}
pub fn port(&self) -> Option<u16> {
self.options.port
}
pub fn set_port(&mut self, port: impl Into<Option<u16>>) -> &mut Self {
self.options.port = port.into();
self
}
pub fn scheme(&self) -> Option<String> {
self.options.scheme.clone()
}
pub fn set_scheme<'a>(
&mut self,
scheme: impl Into<Option<&'a str>>,
) -> &mut Self {
self.options.scheme = scheme.into().map(|s| s.to_string());
self
}
pub fn url(&self) -> Option<Url> {
self.options.url.clone()
}
pub fn set_url(&mut self, url: impl Into<Option<Url>>) -> &mut Self {
self.options.url = url.into();
self
}
}
#[cfg(test)]
mod test {
pub mod client_builder_internal_build {
use crate::common::builder::client_builder::ClientBuilder;
use crate::common::{
builder::{
builder_options::BuilderOptions,
client_builder::ClientBuilderInternal,
},
client::client_type::ClientType,
};
use std::collections::HashMap;
use url::Url;
#[cfg(feature = "error-client")]
use crate::error::error_client_builder::ErrorClientBuilder;
#[cfg(feature = "session-client")]
use crate::session::session_client_builder::SessionClientBuilder;
#[test]
#[cfg(feature = "error-client")]
pub fn build_error_client_internal() {
let builder = ClientBuilder::error();
assert_eq!(
builder,
ErrorClientBuilder {
builder_internal: ClientBuilderInternal {
options: BuilderOptions {
client_type: ClientType::Error,
scheme: None,
url: Some(
Url::parse("https://notify.bugsnag.com/")
.unwrap()
),
host: None,
port: None,
endpoint: None,
headers: Some(HashMap::new()),
},
api_key: None,
payload_version: "5".into(),
payload_version_override: None,
},
notifier: None,
events: None,
}
)
}
#[cfg(feature = "session-client")]
#[test]
pub fn build_session_client_internal() {
let builder = ClientBuilder::session();
assert_eq!(
builder,
SessionClientBuilder {
builder_internal: ClientBuilderInternal {
options: BuilderOptions {
client_type: ClientType::Session,
scheme: None,
url: Some(
Url::parse("https://sessions.bugsnag.com/")
.unwrap()
),
host: None,
port: None,
endpoint: None,
headers: Some(HashMap::new()),
},
api_key: None,
payload_version: "1.0".into(),
payload_version_override: None,
},
notifier: None,
app: None,
device: None,
sessions: None,
session_counts: None,
}
)
}
}
pub mod client_builder_setters {
#[cfg(any(feature = "error-client", feature = "session-client"))]
use super::super::{ClientBuilder, ClientBuilderInternal};
#[cfg(any(feature = "error-client", feature = "session-client"))]
use crate::common::{
builder::builder_options::BuilderOptions,
client::client_type::ClientType,
};
#[cfg(any(feature = "error-client", feature = "session-client"))]
use std::collections::HashMap;
#[cfg(any(feature = "error-client", feature = "session-client"))]
use url::Url;
#[cfg(feature = "error-client")]
use crate::error::{
error_client_builder::ErrorClientBuilder,
payload::{
events::{Event, Exception, StackTrace},
notifier::Notifier,
},
};
#[cfg(feature = "error-client")]
#[test]
pub fn error_client_builder() {
let mut headers = HashMap::new();
let header_name = "fake header name".to_string();
let header_value = "fake header value".to_string();
let payload_version_override = "0.2.4";
headers.insert(header_name.clone(), header_value);
let reference_error_builder = ErrorClientBuilder {
builder_internal: ClientBuilderInternal {
options: BuilderOptions {
client_type: ClientType::Error,
scheme: Some("http".to_string()),
url: Some(Url::parse("https://google.com/").unwrap()),
host: Some("Fake Host".to_string()),
port: Some(4000),
endpoint: Some("https://google.com/".to_string()),
headers: Some(headers),
},
api_key: Some("FakeApiKey0123".to_string()),
payload_version: "5".to_string(),
payload_version_override: Some(
payload_version_override.to_string(),
),
},
notifier: Some(Notifier {
name: "Fake Notifier".to_string(),
version: "0.0.1".to_string(),
url: "https://fake.com".to_string(),
dependencies: None,
}),
events: Some(
[Event {
app: None,
breadcrumbs: None,
context: None,
device: None,
exceptions: [Exception {
error_class: "Fake error class".to_string(),
message: None,
stack_trace: [StackTrace {
file: "Fake File".to_string(),
line_number: 10,
column_number: None,
method: "Fake Method".to_string(),
in_project: None,
code: None,
frame_address: None,
load_address: None,
is_lr: None,
is_pc: None,
symbol_address: None,
macho_file: None,
macho_load_address: None,
macho_uuid: None,
macho_vm_address: None,
code_identifier: None,
}]
.into(),
runtime_type: None,
}]
.into(),
feature_flags: None,
grouping_hash: None,
meta_data: None,
project_packages: None,
request: None,
session: None,
severity: None,
severity_reason: None,
threads: None,
unhandled: None,
user: None,
}]
.into(),
),
};
assert_ne!(
reference_error_builder.payload_version,
reference_error_builder
.payload_version_override
.clone()
.unwrap()
);
let mut test_error_builder = ClientBuilder::error();
test_error_builder
.set_api_key(
reference_error_builder.api_key().unwrap().as_str(),
)
.set_endpoint(
reference_error_builder.endpoint().unwrap().as_str(),
)
.add_header(
header_name.clone(),
reference_error_builder
.headers()
.unwrap()
.get(&header_name)
.unwrap(),
)
.set_host(reference_error_builder.host().unwrap().as_str())
.set_payload_version(
reference_error_builder
.payload_version_override
.clone()
.unwrap()
.as_str(),
)
.set_port(reference_error_builder.port().unwrap())
.set_scheme(reference_error_builder.scheme().unwrap().as_str())
.set_url(reference_error_builder.url().unwrap());
test_error_builder
.set_notifier(
reference_error_builder.notifier().unwrap().clone(),
)
.set_events(reference_error_builder.events().clone());
assert_eq!(test_error_builder, reference_error_builder)
}
#[cfg(feature = "session-client")]
#[test]
pub fn session_client_builder() {
use crate::session::{
payload::{
device::Device, notifier::Notifier as SessionNotifier,
session_counts::session_count::SessionCount,
sessions::Session, App,
},
session_client_builder::SessionClientBuilder,
};
use chrono::Timelike;
let mut headers = HashMap::new();
let header_name = "fake header name".to_string();
let header_value = "fake header value".to_string();
let payload_version_override = "0.2.4";
headers.insert(header_name.clone(), header_value);
let mut reference_session_builder = SessionClientBuilder {
builder_internal: ClientBuilderInternal {
options: BuilderOptions {
client_type: ClientType::Session,
scheme: Some("https".to_string()),
url: Some(Url::parse("https://some.host/api").unwrap()),
host: Some("my.host".to_string()),
port: Some(128),
endpoint: Some("/endpoint".to_string()),
headers: Some(headers),
},
api_key: Some("FakeApiKey0123".to_string()),
payload_version: "1.0".to_string(),
payload_version_override: Some(
payload_version_override.to_string(),
),
},
notifier: Some(SessionNotifier {
name: "Fake Name".to_string(),
version: "0.2.3".to_string(),
url: None,
}),
app: Some(App {
app_type: None,
release_stage: None,
version: None,
version_code: None,
bundle_version: None,
code_bundle_id: None,
}),
device: Some(Device {
hostname: None,
id: None,
manufacturer: None,
model: None,
model_number: None,
jailbroken: None,
os_name: None,
os_version: None,
user_agent: None,
runtime_versions: None,
}),
sessions: Some(vec![Session {
id: "1".to_string(),
started_at: chrono::Utc::now().with_minute(10).unwrap(),
user: None,
}]),
session_counts: Some((|| {
let time = chrono::Utc::now();
let mut session_counts = HashMap::new();
let session_count =
SessionCount { started_at: time, sessions_started: 2 };
session_counts.insert(time.to_string(), session_count);
session_counts
})()),
};
assert_ne!(
reference_session_builder.payload_version,
reference_session_builder
.payload_version_override
.clone()
.unwrap()
);
let mut test_session_builder = ClientBuilder::session();
test_session_builder
.set_api_key(
reference_session_builder.api_key().unwrap().as_str(),
)
.set_endpoint(
reference_session_builder.endpoint().unwrap().as_str(),
)
.add_header(
header_name.clone(),
reference_session_builder
.headers()
.unwrap()
.get(&header_name)
.unwrap(),
)
.set_host(reference_session_builder.host().unwrap().as_str())
.set_payload_version(
reference_session_builder
.payload_version_override
.clone()
.unwrap()
.as_str(),
)
.set_port(reference_session_builder.port().unwrap())
.set_scheme(
reference_session_builder.scheme().unwrap().as_str(),
)
.set_url(reference_session_builder.url().unwrap());
test_session_builder
.set_notifier(
reference_session_builder.notifier().unwrap().clone(),
)
.set_app(reference_session_builder.app().unwrap().clone())
.set_device(reference_session_builder.device().unwrap().clone())
.set_sessions(
reference_session_builder.sessions().unwrap().clone(),
)
.set_session_counts(
reference_session_builder.session_counts().unwrap().clone(),
);
assert_eq!(reference_session_builder, test_session_builder);
reference_session_builder.sessions = None;
test_session_builder.set_sessions(None);
let mut session_count = HashMap::new();
session_count.insert(
"01:23:34".to_string(),
SessionCount {
started_at: chrono::Utc::now(),
sessions_started: 2,
},
);
reference_session_builder.session_counts =
Some(session_count.clone());
test_session_builder.set_session_counts(session_count);
}
}
}