- Extract ipl() from main() with env-aware error handling (fatal in prod, warn in dev) - Add amqp::validate() — TCP reachability check for RabbitMQ at IPL - Refactor config::load() into load() + load_from() for testability - Add lib.rs to expose public API to integration test harness - Add test fixture scaffolding: tests/fixtures/beds_test.toml, tests/common/mod.rs - Add unit tests for amqp::validate() error paths (closed port, bad address) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
87 lines
2.7 KiB
Rust
87 lines
2.7 KiB
Rust
//! # amqp.rs — RabbitMQ Transport Layer
|
|
//!
|
|
//! Manages all AMQP interactions for the BEDS node. At IPL, validates that
|
|
//! the RabbitMQ broker is reachable before the node proceeds. Future phases
|
|
//! will add channel acquisition, queue declaration, and message dispatch.
|
|
//!
|
|
//! ## Calling Agents
|
|
//! - `ipl()` in main.rs — calls `validate()` during the IPL sequence
|
|
//!
|
|
//! ## Inputs
|
|
//! - `BrokerServicesConfig` from the loaded BEDS configuration
|
|
//!
|
|
//! ## Outputs
|
|
//! - `Ok(())` if the broker is reachable
|
|
//! - `Err(String)` with host:port and OS error if the broker cannot be reached
|
|
//!
|
|
//! **Author:** mks
|
|
//! **Version:** 1.0
|
|
//!
|
|
//! ## History
|
|
//! * `2026-04-02` - mks - original coding
|
|
|
|
use std::net::TcpStream;
|
|
use std::time::Duration;
|
|
|
|
use crate::config::BrokerServicesConfig;
|
|
|
|
/// Validates that the RabbitMQ broker is reachable.
|
|
///
|
|
/// Opens a TCP connection to the configured broker host and port. Does not
|
|
/// authenticate or open an AMQP channel — reachability only. The connection
|
|
/// is closed immediately after a successful connect.
|
|
///
|
|
/// # Arguments
|
|
///
|
|
/// * `cfg` — broker services configuration block from `BedsConfig`
|
|
///
|
|
/// # Returns
|
|
///
|
|
/// `Ok(())` if the TCP handshake succeeds.
|
|
/// `Err(String)` with a descriptive message if the broker cannot be reached
|
|
/// or if the configured address is malformed.
|
|
///
|
|
/// # History
|
|
///
|
|
/// * `2026-04-02` - mks - original coding
|
|
pub fn validate(cfg: &BrokerServicesConfig) -> Result<(), String> {
|
|
let addr_str = format!("{}:{}", cfg.app_server.host, cfg.app_server.port);
|
|
|
|
let addr: std::net::SocketAddr = addr_str
|
|
.parse()
|
|
.map_err(|e| format!("Invalid broker address {}: {}", addr_str, e))?;
|
|
|
|
TcpStream::connect_timeout(&addr, Duration::from_secs(5))
|
|
.map_err(|e| format!("RabbitMQ unreachable at {}: {}", addr_str, e))?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::config::load_from;
|
|
|
|
/// Loads the test fixture config. Panics if the fixture is missing or malformed.
|
|
fn test_cfg() -> crate::config::BedsConfig {
|
|
load_from("tests/fixtures/beds_test.toml", "")
|
|
.expect("test fixture beds_test.toml failed to load")
|
|
}
|
|
|
|
#[test]
|
|
fn validate_err_on_closed_port() {
|
|
// port 1 is reserved and always closed — guarantees a connection refusal
|
|
// without requiring any live service
|
|
let mut cfg = test_cfg();
|
|
cfg.broker_services.app_server.port = 1;
|
|
assert!(validate(&cfg.broker_services).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn validate_err_on_bad_address() {
|
|
let mut cfg = test_cfg();
|
|
cfg.broker_services.app_server.host = "not_a_valid_host!!!".to_string();
|
|
assert!(validate(&cfg.broker_services).is_err());
|
|
}
|
|
}
|