lambda_simulator/lib.rs
1//! # Lambda Runtime Simulator
2//!
3//! A high-fidelity AWS Lambda Runtime API simulator for testing Lambda runtimes
4//! and extensions in a local development environment.
5//!
6//! ## Overview
7//!
8//! This crate provides a simulator that implements the AWS Lambda Runtime API,
9//! allowing you to test Lambda runtimes and extensions without deploying to AWS.
10//! It's particularly useful for testing Lambda extensions like OpenTelemetry
11//! collectors, custom extensions, and runtime implementations.
12//!
13//! ## Features
14//!
15//! - **Runtime API**: Full implementation of the Lambda Runtime Interface
16//! - **High Fidelity**: Accurately simulates Lambda behavior including timeouts
17//! - **Test-Friendly**: Easy to use in test harnesses with state inspection
18//! - **Async**: Built on tokio for efficient async execution
19//!
20//! ## Quick Start
21//!
22//! ```no_run
23//! use lambda_simulator::{Simulator, InvocationBuilder};
24//! use serde_json::json;
25//!
26//! #[tokio::main]
27//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
28//! // Create a simulator
29//! let simulator = Simulator::builder()
30//! .function_name("my-test-function")
31//! .build()
32//! .await?;
33//!
34//! // Get the Runtime API URL
35//! let runtime_api = simulator.runtime_api_url();
36//! println!("Runtime API available at: {}", runtime_api);
37//!
38//! // Enqueue an invocation
39//! simulator.enqueue_payload(json!({
40//! "message": "Hello, Lambda!"
41//! })).await;
42//!
43//! // Your runtime would connect to runtime_api and process the invocation
44//! // ...
45//!
46//! Ok(())
47//! }
48//! ```
49//!
50//! ## Testing Lambda Runtimes
51//!
52//! The simulator provides efficient, event-driven wait helpers that eliminate
53//! flaky sleep-based synchronisation:
54//!
55//! ```no_run
56//! use lambda_simulator::{Simulator, InvocationStatus};
57//! use serde_json::json;
58//! use std::time::Duration;
59//!
60//! #[tokio::test]
61//! async fn test_my_runtime() {
62//! let simulator = Simulator::builder()
63//! .function_name("test-function")
64//! .build()
65//! .await
66//! .unwrap();
67//!
68//! // Set the runtime API URL for your runtime
69//! std::env::set_var("AWS_LAMBDA_RUNTIME_API", simulator.runtime_api_url());
70//!
71//! // Enqueue returns the request ID for tracking
72//! let request_id = simulator.enqueue_payload(json!({"key": "value"})).await;
73//!
74//! // Start your runtime in a background task
75//! // tokio::spawn(async { my_runtime::run().await });
76//!
77//! // Wait for completion with timeout - no polling loops needed!
78//! let state = simulator
79//! .wait_for_invocation_complete(&request_id, Duration::from_secs(5))
80//! .await
81//! .expect("Invocation should complete");
82//!
83//! assert_eq!(state.status, InvocationStatus::Success);
84//! }
85//! ```
86//!
87//! ## Testing with Telemetry Capture
88//!
89//! Capture telemetry events in memory without setting up HTTP servers:
90//!
91//! ```no_run
92//! use lambda_simulator::Simulator;
93//! use serde_json::json;
94//!
95//! #[tokio::test]
96//! async fn test_telemetry_events() {
97//! let simulator = Simulator::builder().build().await.unwrap();
98//!
99//! // Enable in-memory capture
100//! simulator.enable_telemetry_capture().await;
101//!
102//! // Enqueue and process invocations...
103//! simulator.enqueue_payload(json!({"test": "data"})).await;
104//!
105//! // Assert on captured events
106//! let start_events = simulator.get_telemetry_events_by_type("platform.start").await;
107//! assert_eq!(start_events.len(), 1);
108//! }
109//! ```
110//!
111//! ## Predicate-Based Waiting
112//!
113//! Wait for arbitrary conditions with `wait_for`:
114//!
115//! ```no_run
116//! use lambda_simulator::Simulator;
117//! use std::time::Duration;
118//!
119//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
120//! let simulator = Simulator::builder().build().await?;
121//!
122//! // Wait for extensions to register
123//! simulator.wait_for(
124//! || async { simulator.extension_count().await >= 2 },
125//! Duration::from_secs(5)
126//! ).await?;
127//! # Ok(())
128//! # }
129//! ```
130//!
131//! ## Architecture
132//!
133//! The simulator uses an HTTP server built with `axum` and `tokio` to implement
134//! the Lambda Runtime API endpoints. Invocations are queued and delivered to
135//! runtimes via long-polling on the `/runtime/invocation/next` endpoint.
136//!
137//! ## AWS Lambda Runtime API
138//!
139//! The simulator implements these endpoints:
140//!
141//! - `GET /2018-06-01/runtime/invocation/next` - Get next invocation (long-poll)
142//! - `POST /2018-06-01/runtime/invocation/{requestId}/response` - Submit response
143//! - `POST /2018-06-01/runtime/invocation/{requestId}/error` - Report error
144//! - `POST /2018-06-01/runtime/init/error` - Report initialization error
145//!
146//! For more details on the Lambda Runtime API, see:
147//! <https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html>
148
149pub mod error;
150pub mod extension;
151pub(crate) mod extension_readiness;
152pub mod extensions_api;
153pub mod freeze;
154pub mod invocation;
155pub mod process;
156pub mod runtime_api;
157pub mod simulator;
158pub mod state;
159pub mod telemetry;
160pub(crate) mod telemetry_api;
161pub(crate) mod telemetry_state;
162
163pub use error::{BuilderError, RuntimeError, SimulatorError, SimulatorResult};
164pub use extension::{EventType, ExtensionId, LifecycleEvent, RegisteredExtension, ShutdownReason};
165pub use freeze::{FreezeError, FreezeMode, FreezeState};
166pub use invocation::{
167 Invocation, InvocationBuilder, InvocationError, InvocationResponse, InvocationStatus,
168};
169pub use simulator::{Simulator, SimulatorBuilder, SimulatorConfig, SimulatorPhase};
170pub use state::InvocationState;
171pub use telemetry::{TelemetryEvent, TelemetryEventType, TelemetrySubscription};