use crate::{
AuditEntry, ClearReason, OutputFrameKind, OutputKey, RebaselineReason, ResourceCommand,
ResourceKey, ScopeId, TransactionId, TransactionPhase, TransactionResult,
};
use crate::{NodeId, Revision};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TransactionTrace {
pub transaction_id: TransactionId,
pub revision: Revision,
pub changed_inputs: Vec<NodeId>,
pub changed_derived_nodes: Vec<NodeId>,
pub changed_collection_nodes: Vec<NodeId>,
pub resource_commands: Vec<ResourceCommandTrace>,
pub output_frames: Vec<OutputFrameTrace>,
pub audit_log: Vec<AuditEntry>,
pub phase_trace: Vec<TransactionPhase>,
}
impl TransactionTrace {
pub fn from_result<C, O>(result: &TransactionResult<C, O>) -> Self {
Self {
transaction_id: result.transaction_id,
revision: result.revision,
changed_inputs: result.changed_inputs.clone(),
changed_derived_nodes: result.changed_derived_nodes.clone(),
changed_collection_nodes: result.changed_collection_nodes.clone(),
resource_commands: result
.resource_plan
.commands()
.iter()
.map(ResourceCommandTrace::from_command)
.collect(),
output_frames: result
.output_frames
.iter()
.map(|frame| OutputFrameTrace {
output_key: frame.output_key,
scope: frame.scope,
transaction_id: frame.transaction_id,
revision: frame.revision,
kind: OutputFrameKindTrace::from_kind(&frame.kind),
})
.collect(),
audit_log: result.audit_log.clone(),
phase_trace: result.phase_trace.clone(),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ResourceCommandTrace {
pub key: ResourceKey,
pub scope: ScopeId,
pub kind: ResourceCommandKind,
}
impl ResourceCommandTrace {
fn from_command<C>(command: &ResourceCommand<C>) -> Self {
Self {
key: command.key().clone(),
scope: command.scope(),
kind: ResourceCommandKind::from_command(command),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ResourceCommandKind {
Open,
Close,
Replace,
Refresh,
}
impl ResourceCommandKind {
pub(crate) fn from_command<C>(command: &ResourceCommand<C>) -> Self {
match command {
ResourceCommand::Open { .. } => Self::Open,
ResourceCommand::Close { .. } => Self::Close,
ResourceCommand::Replace { .. } => Self::Replace,
ResourceCommand::Refresh { .. } => Self::Refresh,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OutputFrameTrace {
pub output_key: OutputKey,
pub scope: ScopeId,
pub transaction_id: TransactionId,
pub revision: Revision,
pub kind: OutputFrameKindTrace,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum OutputFrameKindTrace {
Baseline,
Delta,
Clear(ClearReason),
Rebaseline(RebaselineReason),
}
impl OutputFrameKindTrace {
pub(crate) fn from_kind<O>(kind: &OutputFrameKind<O>) -> Self {
match kind {
OutputFrameKind::Baseline(_) => Self::Baseline,
OutputFrameKind::Delta(_) => Self::Delta,
OutputFrameKind::Clear(reason) => Self::Clear(*reason),
OutputFrameKind::Rebaseline(_, reason) => Self::Rebaseline(*reason),
}
}
}
impl<C, O> TransactionResult<C, O> {
pub fn trace(&self) -> TransactionTrace {
TransactionTrace::from_result(self)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TraceMismatch {
pub expected: Vec<TransactionTrace>,
pub actual: Vec<TransactionTrace>,
}
pub fn assert_transaction_traces_match(
expected: &[TransactionTrace],
actual: &[TransactionTrace],
) -> Result<(), TraceMismatch> {
if expected == actual {
Ok(())
} else {
Err(TraceMismatch {
expected: expected.to_vec(),
actual: actual.to_vec(),
})
}
}