mod condition;
mod evaluation;
mod fault_injecting_factory;
mod http_client;
mod result;
mod rule;
use std::fmt;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use crate::models::{OperationType, ResourceType};
pub use condition::{FaultInjectionCondition, FaultInjectionConditionBuilder};
pub use evaluation::FaultInjectionEvaluation;
pub(crate) use fault_injecting_factory::FaultInjectingHttpClientFactory;
pub use http_client::FaultClient;
pub use result::{
CustomResponse, CustomResponseBuilder, FaultInjectionResult, FaultInjectionResultBuilder,
};
pub use rule::{FaultInjectionRule, FaultInjectionRuleBuilder};
#[derive(Clone, Debug, Default)]
pub(crate) struct EvaluationCollector(Arc<Mutex<Vec<FaultInjectionEvaluation>>>);
impl EvaluationCollector {
pub fn push_all(&self, evals: &mut Vec<FaultInjectionEvaluation>) {
self.0
.lock()
.unwrap_or_else(|e| e.into_inner())
.append(evals);
}
pub fn take(self) -> Vec<FaultInjectionEvaluation> {
match Arc::try_unwrap(self.0) {
Ok(mutex) => mutex.into_inner().unwrap_or_else(|e| e.into_inner()),
Err(arc) => {
let mut evaluations = arc.lock().unwrap_or_else(|e| e.into_inner());
std::mem::take(&mut *evaluations)
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum FaultInjectionErrorType {
InternalServerError,
TooManyRequests,
ReadSessionNotAvailable,
Timeout,
ServiceUnavailable,
PartitionIsGone,
WriteForbidden,
DatabaseAccountNotFound,
ConnectionError,
ResponseTimeout,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum FaultOperationType {
ReadItem,
QueryItem,
CreateItem,
UpsertItem,
ReplaceItem,
DeleteItem,
PatchItem,
BatchItem,
ChangeFeedItem,
MetadataReadContainer,
MetadataReadDatabaseAccount,
MetadataQueryPlan,
MetadataPartitionKeyRanges,
}
impl FaultOperationType {
pub fn as_str(&self) -> &'static str {
match self {
FaultOperationType::ReadItem => "ReadItem",
FaultOperationType::QueryItem => "QueryItem",
FaultOperationType::CreateItem => "CreateItem",
FaultOperationType::UpsertItem => "UpsertItem",
FaultOperationType::ReplaceItem => "ReplaceItem",
FaultOperationType::DeleteItem => "DeleteItem",
FaultOperationType::PatchItem => "PatchItem",
FaultOperationType::BatchItem => "BatchItem",
FaultOperationType::ChangeFeedItem => "ChangeFeedItem",
FaultOperationType::MetadataReadContainer => "MetadataReadContainer",
FaultOperationType::MetadataReadDatabaseAccount => "MetadataReadDatabaseAccount",
FaultOperationType::MetadataQueryPlan => "MetadataQueryPlan",
FaultOperationType::MetadataPartitionKeyRanges => "MetadataPartitionKeyRanges",
}
}
pub fn from_operation_and_resource(
operation_type: &OperationType,
resource_type: &ResourceType,
) -> Option<Self> {
match (operation_type, resource_type) {
(OperationType::Read, ResourceType::Document) => Some(FaultOperationType::ReadItem),
(OperationType::Query, ResourceType::Document) => Some(FaultOperationType::QueryItem),
(OperationType::Create, ResourceType::Document) => Some(FaultOperationType::CreateItem),
(OperationType::Upsert, ResourceType::Document) => Some(FaultOperationType::UpsertItem),
(OperationType::Replace, ResourceType::Document) => {
Some(FaultOperationType::ReplaceItem)
}
(OperationType::Delete, ResourceType::Document) => Some(FaultOperationType::DeleteItem),
(OperationType::Batch, ResourceType::Document) => Some(FaultOperationType::BatchItem),
(OperationType::ReadFeed, ResourceType::Document) => {
Some(FaultOperationType::ChangeFeedItem)
}
(OperationType::Read, ResourceType::DocumentCollection) => {
Some(FaultOperationType::MetadataReadContainer)
}
(OperationType::Read, ResourceType::DatabaseAccount) => {
Some(FaultOperationType::MetadataReadDatabaseAccount)
}
(OperationType::QueryPlan, ResourceType::Document) => {
Some(FaultOperationType::MetadataQueryPlan)
}
(OperationType::ReadFeed, ResourceType::PartitionKeyRange) => {
Some(FaultOperationType::MetadataPartitionKeyRanges)
}
_ => None,
}
}
}
impl fmt::Display for FaultOperationType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for FaultOperationType {
type Err = azure_core::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"ReadItem" => Ok(FaultOperationType::ReadItem),
"QueryItem" => Ok(FaultOperationType::QueryItem),
"CreateItem" => Ok(FaultOperationType::CreateItem),
"UpsertItem" => Ok(FaultOperationType::UpsertItem),
"ReplaceItem" => Ok(FaultOperationType::ReplaceItem),
"DeleteItem" => Ok(FaultOperationType::DeleteItem),
"PatchItem" => Ok(FaultOperationType::PatchItem),
"BatchItem" => Ok(FaultOperationType::BatchItem),
"ChangeFeedItem" => Ok(FaultOperationType::ChangeFeedItem),
"MetadataReadContainer" => Ok(FaultOperationType::MetadataReadContainer),
"MetadataReadDatabaseAccount" => Ok(FaultOperationType::MetadataReadDatabaseAccount),
"MetadataQueryPlan" => Ok(FaultOperationType::MetadataQueryPlan),
"MetadataPartitionKeyRanges" => Ok(FaultOperationType::MetadataPartitionKeyRanges),
_ => Err(azure_core::Error::with_message(
azure_core::error::ErrorKind::DataConversion,
format!("unknown fault operation type: {s}"),
)),
}
}
}
impl fmt::Display for FaultInjectionErrorType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InternalServerError => write!(f, "InternalServerError"),
Self::TooManyRequests => write!(f, "TooManyRequests"),
Self::ReadSessionNotAvailable => write!(f, "ReadSessionNotAvailable"),
Self::Timeout => write!(f, "Timeout"),
Self::ServiceUnavailable => write!(f, "ServiceUnavailable"),
Self::PartitionIsGone => write!(f, "PartitionIsGone"),
Self::WriteForbidden => write!(f, "WriteForbidden"),
Self::DatabaseAccountNotFound => write!(f, "DatabaseAccountNotFound"),
Self::ConnectionError => write!(f, "ConnectionError"),
Self::ResponseTimeout => write!(f, "ResponseTimeout"),
}
}
}
impl FromStr for FaultInjectionErrorType {
type Err = azure_core::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"InternalServerError" => Ok(Self::InternalServerError),
"TooManyRequests" => Ok(Self::TooManyRequests),
"ReadSessionNotAvailable" => Ok(Self::ReadSessionNotAvailable),
"Timeout" => Ok(Self::Timeout),
"ServiceUnavailable" => Ok(Self::ServiceUnavailable),
"PartitionIsGone" => Ok(Self::PartitionIsGone),
"WriteForbidden" => Ok(Self::WriteForbidden),
"DatabaseAccountNotFound" => Ok(Self::DatabaseAccountNotFound),
"ConnectionError" => Ok(Self::ConnectionError),
"ResponseTimeout" => Ok(Self::ResponseTimeout),
_ => Err(azure_core::Error::with_message(
azure_core::error::ErrorKind::DataConversion,
format!("unknown fault injection error type: {s}"),
)),
}
}
}