camel_component_http/
bundle.rs1use std::sync::Arc;
2
3use camel_component_api::{CamelError, ComponentBundle, ComponentRegistrar};
4
5use crate::static_config::HttpStaticConfig;
6use crate::static_endpoint::HttpStaticComponent;
7use crate::{HttpComponent, HttpsComponent, config::HttpConfig};
8
9pub struct HttpBundle {
10 config: HttpConfig,
11}
12
13impl ComponentBundle for HttpBundle {
14 fn config_key() -> &'static str {
15 "http"
16 }
17
18 fn from_toml(value: toml::Value) -> Result<Self, CamelError> {
19 let config: HttpConfig = value
20 .try_into()
21 .map_err(|e: toml::de::Error| CamelError::Config(e.to_string()))?;
22 Ok(Self { config })
23 }
24
25 fn register_all(self, ctx: &mut dyn ComponentRegistrar) {
26 ctx.register_component_dyn(Arc::new(HttpComponent::with_config(self.config.clone())));
27 ctx.register_component_dyn(Arc::new(HttpsComponent::with_config(self.config)));
28 }
29}
30
31#[derive(Debug)]
40pub struct HttpStaticBundle {
41 config: HttpStaticConfig,
42}
43
44impl ComponentBundle for HttpStaticBundle {
45 fn config_key() -> &'static str {
46 "http-static"
47 }
48
49 fn from_toml(value: toml::Value) -> Result<Self, CamelError> {
50 if let toml::Value::Table(ref table) = value
53 && table.is_empty()
54 {
55 return Ok(Self {
56 config: HttpStaticConfig::default(),
57 });
58 }
59 let config: HttpStaticConfig = value
60 .try_into()
61 .map_err(|e: toml::de::Error| CamelError::Config(e.to_string()))?;
62 Ok(Self { config })
63 }
64
65 fn register_all(self, ctx: &mut dyn ComponentRegistrar) {
66 ctx.register_component_dyn(Arc::new(HttpStaticComponent::with_config(self.config)));
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 struct TestRegistrar {
75 schemes: Vec<String>,
76 }
77
78 impl camel_component_api::ComponentRegistrar for TestRegistrar {
79 fn register_component_dyn(
80 &mut self,
81 component: std::sync::Arc<dyn camel_component_api::Component>,
82 ) {
83 self.schemes.push(component.scheme().to_string());
84 }
85 }
86
87 #[test]
88 fn http_bundle_from_toml_empty_uses_defaults() {
89 let value: toml::Value = toml::from_str("").unwrap();
90 let result = HttpBundle::from_toml(value);
91 assert!(
92 result.is_ok(),
93 "empty HTTP toml must use defaults: {:?}",
94 result.err()
95 );
96 }
97
98 #[test]
99 fn http_bundle_from_toml_custom_timeout() {
100 let value: toml::Value = toml::from_str("connect_timeout_ms = 1000").unwrap();
101 let bundle = HttpBundle::from_toml(value).unwrap();
102 assert_eq!(bundle.config.connect_timeout_ms, 1000);
103 }
104
105 #[test]
106 fn http_bundle_from_toml_returns_error_on_invalid_config() {
107 let mut table = toml::map::Map::new();
108 table.insert(
109 "connect_timeout_ms".to_string(),
110 toml::Value::String("not-a-number".to_string()),
111 );
112
113 let result = HttpBundle::from_toml(toml::Value::Table(table));
114 assert!(result.is_err(), "expected Err on malformed config");
115 let err_msg = match result {
116 Err(err) => err.to_string(),
117 Ok(_) => panic!("expected Err on malformed config"),
118 };
119 assert!(
120 err_msg.contains("Configuration error"),
121 "expected CamelError::Config, got: {err_msg}"
122 );
123 }
124
125 #[test]
126 fn http_bundle_registers_expected_schemes() {
127 let bundle = HttpBundle::from_toml(toml::Value::Table(toml::map::Map::new())).unwrap();
128 let mut registrar = TestRegistrar { schemes: vec![] };
129
130 bundle.register_all(&mut registrar);
131
132 assert_eq!(registrar.schemes, vec!["http", "https"]);
133 }
134
135 #[test]
138 fn http_static_bundle_config_key() {
139 assert_eq!(HttpStaticBundle::config_key(), "http-static");
140 }
141
142 #[test]
143 fn http_static_bundle_from_toml_empty_uses_defaults() {
144 let value: toml::Value = toml::from_str("").unwrap();
145 let result = HttpStaticBundle::from_toml(value);
146 assert!(
147 result.is_ok(),
148 "empty http-static toml must use defaults: {:?}",
149 result.err()
150 );
151 let bundle = result.unwrap();
152 assert!(bundle.config.dir.as_os_str().is_empty());
153 assert_eq!(bundle.config.port, 8080);
154 }
155
156 #[test]
157 fn http_static_bundle_from_toml_with_config() {
158 let toml_str = r#"
159 dir = "/app/spa/dist"
160 port = 3000
161 spaFallback = true
162 cacheControl = "public, max-age=3600"
163 "#;
164 let value: toml::Value = toml::from_str(toml_str).unwrap();
165 let bundle = HttpStaticBundle::from_toml(value).unwrap();
166 assert_eq!(bundle.config.dir, std::path::PathBuf::from("/app/spa/dist"));
167 assert_eq!(bundle.config.port, 3000);
168 assert!(bundle.config.spa_fallback);
169 assert_eq!(bundle.config.cache_control, "public, max-age=3600");
170 }
171
172 #[test]
173 fn http_static_bundle_from_toml_returns_error_on_invalid_config() {
174 let mut table = toml::map::Map::new();
175 table.insert(
176 "port".to_string(),
177 toml::Value::String("not-a-number".to_string()),
178 );
179
180 let result = HttpStaticBundle::from_toml(toml::Value::Table(table));
181 assert!(result.is_err(), "expected Err on malformed config");
182 let err_msg = match result {
183 Err(err) => err.to_string(),
184 Ok(_) => panic!("expected Err on malformed config"),
185 };
186 assert!(
187 err_msg.contains("Configuration error"),
188 "expected CamelError::Config, got: {err_msg}"
189 );
190 }
191
192 #[test]
193 fn http_static_bundle_registers_expected_scheme() {
194 let toml_str = r#"dir = "/tmp/static""#;
195 let value: toml::Value = toml::from_str(toml_str).unwrap();
196 let bundle = HttpStaticBundle::from_toml(value).unwrap();
197 let mut registrar = TestRegistrar { schemes: vec![] };
198
199 bundle.register_all(&mut registrar);
200
201 assert_eq!(registrar.schemes, vec!["http-static"]);
202 }
203}