use chrono::{DateTime, Utc};
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LambdaFunction {
pub function_name: String,
pub function_arn: String,
pub runtime: String,
pub role: String,
pub handler: String,
pub description: String,
pub timeout: i64,
pub memory_size: i64,
pub code_sha256: String,
pub code_size: i64,
pub version: String,
pub last_modified: DateTime<Utc>,
pub tags: BTreeMap<String, String>,
pub environment: BTreeMap<String, String>,
pub architectures: Vec<String>,
pub package_type: String,
pub code_zip: Option<Vec<u8>>,
#[serde(default)]
pub image_uri: Option<String>,
pub policy: Option<String>,
#[serde(default)]
pub layers: Vec<AttachedLayer>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttachedLayer {
pub arn: String,
#[serde(default)]
pub code_size: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventSourceMapping {
pub uuid: String,
pub function_arn: String,
pub event_source_arn: String,
pub batch_size: i64,
pub enabled: bool,
pub state: String,
pub last_modified: DateTime<Utc>,
#[serde(default)]
pub filter_patterns: Vec<String>,
#[serde(default)]
pub maximum_batching_window_in_seconds: Option<i64>,
#[serde(default)]
pub starting_position: Option<String>,
#[serde(default)]
pub starting_position_timestamp: Option<f64>,
#[serde(default)]
pub parallelization_factor: Option<i64>,
#[serde(default)]
pub function_response_types: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LambdaInvocation {
pub function_arn: String,
pub payload: String,
pub timestamp: DateTime<Utc>,
pub source: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LambdaState {
pub account_id: String,
pub region: String,
#[serde(default)]
pub functions: BTreeMap<String, LambdaFunction>,
#[serde(default)]
pub event_source_mappings: BTreeMap<String, EventSourceMapping>,
#[serde(default, skip)]
pub invocations: Vec<LambdaInvocation>,
#[serde(default)]
pub aliases: BTreeMap<String, FunctionAlias>,
#[serde(default)]
pub function_versions: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub layers: BTreeMap<String, Layer>,
#[serde(default)]
pub function_url_configs: BTreeMap<String, FunctionUrlConfig>,
#[serde(default)]
pub function_concurrency: BTreeMap<String, i64>,
#[serde(default)]
pub provisioned_concurrency: BTreeMap<String, ProvisionedConcurrencyConfig>,
#[serde(default)]
pub code_signing_configs: BTreeMap<String, CodeSigningConfig>,
#[serde(default)]
pub function_code_signing: BTreeMap<String, String>,
#[serde(default)]
pub event_invoke_configs: BTreeMap<String, EventInvokeConfig>,
#[serde(default)]
pub runtime_management: BTreeMap<String, RuntimeManagementConfig>,
#[serde(default)]
pub scaling_configs: BTreeMap<String, FunctionScalingConfig>,
#[serde(default)]
pub recursion_configs: BTreeMap<String, String>,
#[serde(default)]
pub tags: BTreeMap<String, Vec<(String, String)>>,
#[serde(default)]
pub capacity_providers: BTreeMap<String, CapacityProvider>,
#[serde(default)]
pub durable_executions: BTreeMap<String, DurableExecution>,
#[serde(default)]
pub account_settings: Option<AccountSettings>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionAlias {
pub alias_arn: String,
pub name: String,
pub function_version: String,
pub description: String,
pub revision_id: String,
pub routing_config: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Layer {
pub layer_name: String,
pub layer_arn: String,
pub versions: Vec<LayerVersion>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LayerVersion {
pub version: i64,
pub layer_version_arn: String,
pub description: String,
pub created_date: DateTime<Utc>,
pub compatible_runtimes: Vec<String>,
pub license_info: String,
pub policy: Option<String>,
#[serde(default)]
pub code_zip: Option<Vec<u8>>,
#[serde(default)]
pub code_sha256: String,
#[serde(default)]
pub code_size: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionUrlConfig {
pub function_arn: String,
pub function_url: String,
pub auth_type: String,
pub cors: Option<serde_json::Value>,
pub creation_time: DateTime<Utc>,
pub last_modified_time: DateTime<Utc>,
pub invoke_mode: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProvisionedConcurrencyConfig {
pub requested: i64,
pub allocated: i64,
pub status: String,
pub last_modified: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodeSigningConfig {
pub csc_id: String,
pub csc_arn: String,
pub description: String,
pub allowed_publishers: Vec<String>,
pub untrusted_artifact_action: String,
pub last_modified: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventInvokeConfig {
pub function_arn: String,
pub maximum_event_age: i64,
pub maximum_retry_attempts: i64,
pub destination_config: serde_json::Value,
pub last_modified: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RuntimeManagementConfig {
pub update_runtime_on: String,
pub runtime_version_arn: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionScalingConfig {
pub maximum_concurrency: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CapacityProvider {
pub name: String,
pub arn: String,
pub status: String,
pub created: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DurableExecution {
pub id: String,
pub function_arn: String,
pub status: String,
pub started: DateTime<Utc>,
pub stopped: Option<DateTime<Utc>>,
pub history: Vec<serde_json::Value>,
pub state: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct AccountSettings {
pub concurrent_executions: i64,
pub code_size_zipped: i64,
pub code_size_unzipped: i64,
pub total_code_size: i64,
}
impl LambdaState {
pub fn new(account_id: &str, region: &str) -> Self {
Self {
account_id: account_id.to_string(),
region: region.to_string(),
functions: BTreeMap::new(),
event_source_mappings: BTreeMap::new(),
invocations: Vec::new(),
aliases: BTreeMap::new(),
function_versions: BTreeMap::new(),
layers: BTreeMap::new(),
function_url_configs: BTreeMap::new(),
function_concurrency: BTreeMap::new(),
provisioned_concurrency: BTreeMap::new(),
code_signing_configs: BTreeMap::new(),
function_code_signing: BTreeMap::new(),
event_invoke_configs: BTreeMap::new(),
runtime_management: BTreeMap::new(),
scaling_configs: BTreeMap::new(),
recursion_configs: BTreeMap::new(),
tags: BTreeMap::new(),
capacity_providers: BTreeMap::new(),
durable_executions: BTreeMap::new(),
account_settings: None,
}
}
pub fn reset(&mut self) {
self.functions.clear();
self.event_source_mappings.clear();
self.invocations.clear();
self.aliases.clear();
self.function_versions.clear();
self.layers.clear();
self.function_url_configs.clear();
self.function_concurrency.clear();
self.provisioned_concurrency.clear();
self.code_signing_configs.clear();
self.function_code_signing.clear();
self.event_invoke_configs.clear();
self.runtime_management.clear();
self.scaling_configs.clear();
self.recursion_configs.clear();
self.tags.clear();
self.capacity_providers.clear();
self.durable_executions.clear();
self.account_settings = None;
}
}
pub type SharedLambdaState =
Arc<RwLock<fakecloud_core::multi_account::MultiAccountState<LambdaState>>>;
impl fakecloud_core::multi_account::AccountState for LambdaState {
fn new_for_account(account_id: &str, region: &str, _endpoint: &str) -> Self {
Self::new(account_id, region)
}
}
pub const LAMBDA_SNAPSHOT_SCHEMA_VERSION: u32 = 2;
#[derive(Debug, Serialize, Deserialize)]
pub struct LambdaSnapshot {
pub schema_version: u32,
#[serde(default)]
pub accounts: Option<fakecloud_core::multi_account::MultiAccountState<LambdaState>>,
#[serde(default)]
pub state: Option<LambdaState>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_has_empty_collections() {
let state = LambdaState::new("123456789012", "us-east-1");
assert_eq!(state.account_id, "123456789012");
assert_eq!(state.region, "us-east-1");
assert!(state.functions.is_empty());
assert!(state.event_source_mappings.is_empty());
assert!(state.invocations.is_empty());
}
#[test]
fn reset_clears_collections() {
let mut state = LambdaState::new("123456789012", "us-east-1");
state.invocations.push(LambdaInvocation {
function_arn: "arn".to_string(),
payload: "p".to_string(),
timestamp: Utc::now(),
source: "s".to_string(),
});
state.reset();
assert!(state.invocations.is_empty());
}
}