rabbitmq_stream_client/client/
options.rs

1use std::{convert::TryFrom, fmt::Debug, path::PathBuf, sync::Arc};
2
3use tokio::net::TcpStream;
4use tokio_rustls::rustls::pki_types::ServerName;
5use tokio_rustls::{
6    rustls::{
7        self,
8        pki_types::{CertificateDer, PrivateKeyDer},
9        ClientConfig,
10    },
11    TlsConnector,
12};
13
14use crate::error::ClientError;
15
16use super::{
17    metrics::{MetricsCollector, NopMetricsCollector},
18    GenericTcpStream,
19};
20
21#[derive(Clone)]
22#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
23pub struct ClientOptions {
24    #[cfg_attr(feature = "serde", serde(default = "default_host"))]
25    pub(crate) host: String,
26    #[cfg_attr(feature = "serde", serde(default = "default_port"))]
27    pub(crate) port: u16,
28    #[cfg_attr(feature = "serde", serde(default = "default_user"))]
29    pub(crate) user: String,
30    #[cfg_attr(feature = "serde", serde(default = "default_password"))]
31    pub(crate) password: String,
32    #[cfg_attr(feature = "serde", serde(default = "default_v_host"))]
33    pub(crate) v_host: String,
34    #[cfg_attr(feature = "serde", serde(default = "default_heartbeat"))]
35    pub(crate) heartbeat: u32,
36    #[cfg_attr(feature = "serde", serde(default = "default_max_frame_size"))]
37    pub(crate) max_frame_size: u32,
38    #[cfg_attr(feature = "serde", serde(default = "default_load_balancer_mode"))]
39    pub(crate) load_balancer_mode: bool,
40    #[cfg_attr(feature = "serde", serde(default))]
41    pub(crate) tls: TlsConfiguration,
42    #[cfg_attr(feature = "serde", serde(skip, default = "default_collector"))]
43    pub(crate) collector: Arc<dyn MetricsCollector>,
44    #[cfg_attr(feature = "serde", serde(default = "default_client_provided_name"))]
45    pub(crate) client_provided_name: String,
46}
47
48impl Debug for ClientOptions {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        f.debug_struct("ClientOptions")
51            .field("host", &self.host)
52            .field("port", &self.port)
53            .field("user", &self.user)
54            .field("password", &self.password)
55            .field("v_host", &self.v_host)
56            .field("heartbeat", &self.heartbeat)
57            .field("max_frame_size", &self.max_frame_size)
58            .field("client_provided_name", &self.client_provided_name)
59            .finish()
60    }
61}
62
63impl Default for ClientOptions {
64    fn default() -> Self {
65        ClientOptions {
66            host: default_host(),
67            port: default_port(),
68            user: default_user(),
69            password: default_password(),
70            v_host: default_v_host(),
71            heartbeat: default_heartbeat(),
72            max_frame_size: default_max_frame_size(),
73            load_balancer_mode: default_load_balancer_mode(),
74            collector: default_collector(),
75            tls: Default::default(),
76            client_provided_name: default_client_provided_name(),
77        }
78    }
79}
80
81fn default_host() -> String {
82    "localhost".to_owned()
83}
84fn default_port() -> u16 {
85    5552
86}
87fn default_user() -> String {
88    "guest".to_owned()
89}
90fn default_password() -> String {
91    "guest".to_owned()
92}
93fn default_v_host() -> String {
94    "/".to_owned()
95}
96fn default_heartbeat() -> u32 {
97    60
98}
99fn default_max_frame_size() -> u32 {
100    1048576
101}
102fn default_load_balancer_mode() -> bool {
103    false
104}
105fn default_collector() -> Arc<dyn MetricsCollector> {
106    Arc::new(NopMetricsCollector {})
107}
108fn default_client_provided_name() -> String {
109    "rust-stream".to_owned()
110}
111
112impl ClientOptions {
113    pub fn builder() -> ClientOptionsBuilder {
114        ClientOptionsBuilder(ClientOptions::default())
115    }
116
117    pub fn set_port(&mut self, port: u16) {
118        self.port = port;
119    }
120
121    pub fn set_client_provided_name(&mut self, name: &str) {
122        self.client_provided_name = name.to_owned();
123    }
124
125    pub(crate) async fn build_generic_tcp_stream(&self) -> Result<GenericTcpStream, ClientError> {
126        async fn create_tls_connection(
127            host: String,
128            port: u16,
129            config: ClientConfig,
130        ) -> Result<GenericTcpStream, ClientError> {
131            let stream = TcpStream::connect((host.clone(), port)).await?;
132            let domain = ServerName::try_from(host.clone()).unwrap();
133            let connector = TlsConnector::from(Arc::new(config));
134            let conn = connector.connect(domain, stream).await?;
135            Ok(GenericTcpStream::SecureTcp(Box::new(conn)))
136        }
137        match &self.tls {
138            TlsConfiguration::Trusted {
139                root_certificates_path,
140                client_certificates,
141            } => {
142                let roots = build_root_store(root_certificates_path).await?;
143
144                let builder = ClientConfig::builder().with_root_certificates(roots);
145                let config = match client_certificates {
146                    Some(client_certificates) => {
147                        let client_certs = match build_client_certificates(
148                            &client_certificates.client_certificates_path,
149                        ) {
150                            Ok(certs) => certs,
151                            Err(e) => return Err(ClientError::Io(e)),
152                        };
153                        let client_keys = match build_client_private_keys(
154                            &client_certificates.client_private_key_path,
155                        ) {
156                            Ok(keys) => keys,
157                            Err(e) => return Err(ClientError::Io(e)),
158                        };
159                        match builder.with_client_auth_cert(
160                            client_certs,
161                            client_keys.into_iter().next().unwrap(),
162                        ) {
163                            Ok(config) => config,
164                            Err(e) => return Err(ClientError::GenericError(Box::new(e))),
165                        }
166                    }
167                    None => builder.with_no_client_auth(),
168                };
169                create_tls_connection(self.host.clone(), self.port, config).await
170            }
171            TlsConfiguration::Untrusted => {
172                let config: ClientConfig = build_tls_client_configuration_untrusted().await?;
173                create_tls_connection(self.host.clone(), self.port, config).await
174            }
175            TlsConfiguration::Disabled => {
176                let stream = TcpStream::connect((self.host.as_str(), self.port)).await?;
177                Ok(GenericTcpStream::Tcp(stream))
178            }
179        }
180    }
181}
182
183pub struct ClientOptionsBuilder(ClientOptions);
184
185impl ClientOptionsBuilder {
186    pub fn host(mut self, host: &str) -> Self {
187        self.0.host = host.to_owned();
188        self
189    }
190
191    pub fn port(mut self, port: u16) -> Self {
192        self.0.port = port;
193        self
194    }
195
196    pub fn user(mut self, user: &str) -> Self {
197        self.0.user = user.to_owned();
198        self
199    }
200
201    pub fn password(mut self, password: &str) -> Self {
202        self.0.password = password.to_owned();
203        self
204    }
205
206    pub fn v_host(mut self, v_host: &str) -> Self {
207        self.0.v_host = v_host.to_owned();
208        self
209    }
210
211    pub fn heartbeat(mut self, heartbeat: u32) -> Self {
212        self.0.heartbeat = heartbeat;
213        self
214    }
215
216    pub fn max_frame_size(mut self, max_frame_size: u32) -> Self {
217        self.0.max_frame_size = max_frame_size;
218        self
219    }
220
221    pub fn tls(mut self, tls: TlsConfiguration) -> Self {
222        self.0.tls = tls;
223        self
224    }
225
226    pub fn client_provided_name(mut self, client_provided_name: String) -> Self {
227        self.0.client_provided_name = client_provided_name;
228        self
229    }
230
231    pub fn collector(mut self, collector: Arc<dyn MetricsCollector>) -> Self {
232        self.0.collector = collector;
233        self
234    }
235
236    pub fn load_balancer_mode(mut self, load_balancer_mode: bool) -> Self {
237        self.0.load_balancer_mode = load_balancer_mode;
238        self
239    }
240
241    pub fn build(self) -> ClientOptions {
242        self.0
243    }
244}
245
246/** Helper for tls configuration */
247#[derive(Clone, Default)]
248pub enum TlsConfiguration {
249    #[default]
250    Disabled,
251    Untrusted,
252    Trusted {
253        root_certificates_path: PathBuf,
254        client_certificates: Option<ClientTlsConfiguration>,
255    },
256}
257
258#[cfg(feature = "serde")]
259impl<'de> serde::Deserialize<'de> for TlsConfiguration {
260    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
261    where
262        D: serde::Deserializer<'de>,
263    {
264        use serde::Deserialize;
265
266        #[derive(Deserialize)]
267        struct DeserializableTlsConfiguration {
268            enabled: bool,
269            root_certificates_path: Option<PathBuf>,
270            client_certificates_path: Option<PathBuf>,
271            client_private_key_path: Option<PathBuf>,
272        }
273        let c = DeserializableTlsConfiguration::deserialize(deserializer)?;
274
275        let builder = TlsConfiguration::builder().enable(c.enabled);
276        let builder = if let Some(root_certificates_path) = c.root_certificates_path {
277            builder.add_root_certificates(root_certificates_path)
278        } else {
279            builder
280        };
281        let builder = if let Some(client_certificates_path) = c.client_certificates_path {
282            builder.add_client_certificates_path(client_certificates_path)
283        } else {
284            builder
285        };
286        let builder = if let Some(client_private_key_path) = c.client_private_key_path {
287            builder.add_client_private_key_path(client_private_key_path)
288        } else {
289            builder
290        };
291
292        builder.build().map_err(serde::de::Error::custom)
293    }
294}
295
296#[derive(Clone)]
297pub struct ClientTlsConfiguration {
298    pub(crate) client_certificates_path: PathBuf,
299    pub(crate) client_private_key_path: PathBuf,
300}
301
302impl TlsConfiguration {
303    pub fn builder() -> TlsConfigurationBuilder {
304        TlsConfigurationBuilder {
305            enabled: false,
306            root_certificates_path: None,
307            client_certificates_path: None,
308            client_private_key_path: None,
309        }
310    }
311}
312
313#[derive(Default)]
314pub struct TlsConfigurationBuilder {
315    enabled: bool,
316    root_certificates_path: Option<PathBuf>,
317    client_certificates_path: Option<PathBuf>,
318    client_private_key_path: Option<PathBuf>,
319}
320
321impl TlsConfigurationBuilder {
322    pub fn enable(mut self, enabled: bool) -> TlsConfigurationBuilder {
323        self.enabled = enabled;
324        self
325    }
326
327    pub fn add_root_certificates<T>(self, root_certificates_path: T) -> TlsConfigurationBuilder
328    where
329        T: Into<PathBuf>,
330    {
331        let mut s = self.enable(true);
332        s.root_certificates_path = Some(root_certificates_path.into());
333        s
334    }
335
336    #[cfg(feature = "serde")]
337    fn add_client_certificates_path<T>(self, client_certificates_path: T) -> TlsConfigurationBuilder
338    where
339        T: Into<PathBuf>,
340    {
341        let mut s = self.enable(true);
342        s.client_certificates_path = Some(client_certificates_path.into());
343        s
344    }
345
346    #[cfg(feature = "serde")]
347    fn add_client_private_key_path<T>(self, client_private_key_path: T) -> TlsConfigurationBuilder
348    where
349        T: Into<PathBuf>,
350    {
351        let mut s = self.enable(true);
352        s.client_private_key_path = Some(client_private_key_path.into());
353        s
354    }
355
356    pub fn add_client_certificates_keys<T1, T2>(
357        self,
358        client_certificates_path: T1,
359        client_private_key_path: T2,
360    ) -> TlsConfigurationBuilder
361    where
362        T1: Into<PathBuf>,
363        T2: Into<PathBuf>,
364    {
365        let mut s = self.enable(true);
366        s.client_certificates_path = Some(client_certificates_path.into());
367        s.client_private_key_path = Some(client_private_key_path.into());
368        s
369    }
370
371    pub fn build(self) -> Result<TlsConfiguration, &'static str> {
372        if self.enabled {
373            let root_certificates_path = match self.root_certificates_path {
374                Some(root_certificates_path) => root_certificates_path,
375                None => {
376                    if self.client_certificates_path.is_some()
377                        || self.client_private_key_path.is_some()
378                    {
379                        return Err("Root certificates path is required when client certificates are provided");
380                    }
381                    return Ok(TlsConfiguration::Untrusted);
382                }
383            };
384
385            let client_certificates =
386                match (self.client_certificates_path, self.client_private_key_path) {
387                    (Some(client_certificates_path), Some(client_private_key_path)) => {
388                        Some(ClientTlsConfiguration {
389                            client_certificates_path,
390                            client_private_key_path,
391                        })
392                    }
393                    (None, None) => None,
394                    _ => return Err("Both client certificates and private key paths are required"),
395                };
396
397            Ok(TlsConfiguration::Trusted {
398                root_certificates_path,
399                client_certificates,
400            })
401        } else {
402            Ok(TlsConfiguration::Disabled)
403        }
404    }
405}
406
407fn build_client_certificates(
408    client_cert: &PathBuf,
409) -> std::io::Result<Vec<CertificateDer<'static>>> {
410    let file = std::fs::File::open(client_cert)?;
411    let mut pem = std::io::BufReader::new(file);
412    rustls_pemfile::certs(&mut pem)
413        .map(|c| c.map(CertificateDer::into_owned))
414        .collect()
415}
416
417async fn build_tls_client_configuration_untrusted() -> Result<ClientConfig, ClientError> {
418    mod danger {
419        use rustls::client::danger::HandshakeSignatureValid;
420        use rustls::client::danger::ServerCertVerified;
421        use tokio_rustls::rustls::{
422            self, client::danger::ServerCertVerifier, pki_types::ServerName,
423        };
424
425        #[derive(Debug)]
426        pub struct NoCertificateVerification {}
427
428        impl ServerCertVerifier for NoCertificateVerification {
429            fn verify_tls12_signature(
430                &self,
431                _: &[u8],
432                _: &rustls::pki_types::CertificateDer<'_>,
433                _: &rustls::DigitallySignedStruct,
434            ) -> Result<HandshakeSignatureValid, rustls::Error> {
435                Ok(HandshakeSignatureValid::assertion())
436            }
437
438            fn verify_tls13_signature(
439                &self,
440                _: &[u8],
441                _: &rustls::pki_types::CertificateDer<'_>,
442                _: &rustls::DigitallySignedStruct,
443            ) -> Result<HandshakeSignatureValid, rustls::Error> {
444                Ok(HandshakeSignatureValid::assertion())
445            }
446
447            fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
448                use rustls::SignatureScheme;
449                // I know know if this is correct
450                vec![
451                    SignatureScheme::RSA_PKCS1_SHA1,
452                    SignatureScheme::ECDSA_SHA1_Legacy,
453                    SignatureScheme::RSA_PKCS1_SHA256,
454                    SignatureScheme::ECDSA_NISTP256_SHA256,
455                    SignatureScheme::RSA_PKCS1_SHA384,
456                    SignatureScheme::ECDSA_NISTP384_SHA384,
457                    SignatureScheme::RSA_PKCS1_SHA512,
458                    SignatureScheme::ECDSA_NISTP521_SHA512,
459                    SignatureScheme::RSA_PSS_SHA256,
460                    SignatureScheme::RSA_PSS_SHA384,
461                    SignatureScheme::RSA_PSS_SHA512,
462                    SignatureScheme::ED25519,
463                    SignatureScheme::ED448,
464                ]
465            }
466
467            fn verify_server_cert(
468                &self,
469                _: &rustls::pki_types::CertificateDer<'_>,
470                _: &[rustls::pki_types::CertificateDer<'_>],
471                _: &ServerName<'_>,
472                _: &[u8],
473                _: rustls::pki_types::UnixTime,
474            ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
475                Ok(ServerCertVerified::assertion())
476            }
477        }
478    }
479
480    let config = ClientConfig::builder()
481        .dangerous()
482        .with_custom_certificate_verifier(Arc::new(danger::NoCertificateVerification {}))
483        .with_no_client_auth();
484
485    Ok(config)
486}
487
488async fn build_root_store(root_ca_cert: &PathBuf) -> std::io::Result<rustls::RootCertStore> {
489    let mut roots = rustls::RootCertStore::empty();
490    let cert_bytes = std::fs::read(root_ca_cert)?;
491
492    let root_cert_store: Result<Vec<_>, _> =
493        rustls_pemfile::certs(&mut cert_bytes.as_ref()).collect();
494    let root_cert_store = root_cert_store?;
495
496    root_cert_store
497        .into_iter()
498        .for_each(|cert| roots.add(cert).unwrap());
499    Ok(roots)
500}
501
502fn build_client_private_keys(
503    client_private_key: &PathBuf,
504) -> std::io::Result<Vec<PrivateKeyDer<'static>>> {
505    let file = std::fs::File::open(client_private_key)?;
506    let mut pem = std::io::BufReader::new(file);
507    let keys: Result<Vec<_>, _> = rustls_pemfile::pkcs8_private_keys(&mut pem).collect();
508    let keys = keys?;
509    let keys = keys.into_iter().map(PrivateKeyDer::from).collect();
510    Ok(keys)
511}
512
513#[cfg(test)]
514mod tests {
515    use super::*;
516    use std::{path::Path, sync::Arc};
517
518    #[test]
519    fn test_tls_builder() {
520        let tls = TlsConfiguration::builder().build().unwrap();
521        assert!(matches!(tls, TlsConfiguration::Disabled));
522        let tls = TlsConfiguration::builder().enable(true).build().unwrap();
523        assert!(matches!(tls, TlsConfiguration::Untrusted));
524
525        let tls = TlsConfiguration::builder()
526            .enable(true)
527            .add_root_certificates("test")
528            .build()
529            .unwrap();
530        let TlsConfiguration::Trusted {
531            root_certificates_path,
532            client_certificates,
533        } = tls
534        else {
535            panic!("Expected Trusted configuration")
536        };
537        assert_eq!(root_certificates_path.as_path(), Path::new("test"));
538        assert!(client_certificates.is_none());
539
540        let tls = TlsConfiguration::builder()
541            .enable(true)
542            .add_root_certificates("test")
543            .add_client_certificates_keys("cert", "priv")
544            .build()
545            .unwrap();
546        let TlsConfiguration::Trusted {
547            root_certificates_path,
548            client_certificates,
549        } = tls
550        else {
551            panic!("Expected Trusted configuration")
552        };
553        assert_eq!(root_certificates_path.as_path(), Path::new("test"));
554        let Some(client_certificates) = client_certificates else {
555            panic!("Expected client certificates")
556        };
557        assert_eq!(
558            client_certificates.client_certificates_path,
559            Path::new("cert")
560        );
561        assert_eq!(
562            client_certificates.client_private_key_path,
563            Path::new("priv")
564        );
565
566        let tls = TlsConfiguration::builder()
567            .enable(true)
568            .add_client_certificates_keys("cert", "priv")
569            .build();
570        assert!(tls.is_err());
571    }
572
573    #[test]
574    fn test_client_options_builder() {
575        let options = ClientOptions::builder()
576            .host("test")
577            .port(8888)
578            .user("test_user")
579            .password("test_pass")
580            .v_host("/test_vhost")
581            .heartbeat(10000)
582            .max_frame_size(1)
583            .tls(TlsConfiguration::builder().enable(true).build().unwrap())
584            .collector(Arc::new(NopMetricsCollector {}))
585            .load_balancer_mode(true)
586            .build();
587        assert_eq!(options.host, "test");
588        assert_eq!(options.port, 8888);
589        assert_eq!(options.user, "test_user");
590        assert_eq!(options.password, "test_pass");
591        assert_eq!(options.v_host, "/test_vhost");
592        assert_eq!(options.heartbeat, 10000);
593        assert_eq!(options.max_frame_size, 1);
594        assert!(matches!(options.tls, TlsConfiguration::Untrusted));
595        assert!(options.load_balancer_mode);
596    }
597
598    #[cfg(feature = "serde")]
599    mod serde {
600        use super::*;
601
602        #[test]
603        fn test_tls_builder() {
604            let config = TlsConfiguration::builder().enable(true).build();
605            assert!(matches!(config, Ok(TlsConfiguration::Untrusted)));
606
607            let config = TlsConfiguration::builder()
608                .enable(true)
609                .add_client_certificates_path("cert")
610                .build();
611            assert!(matches!(config, Err(_)));
612
613            let config = TlsConfiguration::builder()
614                .enable(true)
615                .add_client_private_key_path("priv")
616                .build();
617            assert!(matches!(config, Err(_)));
618        }
619    }
620}
621
622#[cfg(all(feature = "serde", test))]
623mod serde_test {
624    use super::*;
625    use std::path::Path;
626
627    #[test]
628    fn deserialize_client() {
629        #[derive(serde::Deserialize)]
630        struct MyConfig {
631            #[serde(default)]
632            rabbit: ClientOptions,
633        }
634        let j = r#"{}"#;
635
636        let config: MyConfig = serde_json::from_str(j).unwrap();
637        assert_eq!(config.rabbit.host, default_host());
638        assert_eq!(config.rabbit.port, default_port());
639        assert_eq!(config.rabbit.user, default_user());
640        assert_eq!(config.rabbit.password, default_password());
641        assert_eq!(config.rabbit.v_host, default_v_host());
642        assert_eq!(config.rabbit.heartbeat, default_heartbeat());
643        assert_eq!(config.rabbit.max_frame_size, default_max_frame_size());
644        assert_eq!(
645            config.rabbit.load_balancer_mode,
646            default_load_balancer_mode()
647        );
648        assert_eq!(
649            config.rabbit.client_provided_name,
650            default_client_provided_name()
651        );
652        assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
653
654        let j = r#"{ "rabbit": {} }"#;
655        let config: MyConfig = serde_json::from_str(j).unwrap();
656        assert_eq!(config.rabbit.host, default_host());
657        assert_eq!(config.rabbit.port, default_port());
658        assert_eq!(config.rabbit.user, default_user());
659        assert_eq!(config.rabbit.password, default_password());
660        assert_eq!(config.rabbit.v_host, default_v_host());
661        assert_eq!(config.rabbit.heartbeat, default_heartbeat());
662        assert_eq!(config.rabbit.max_frame_size, default_max_frame_size());
663        assert_eq!(
664            config.rabbit.load_balancer_mode,
665            default_load_balancer_mode()
666        );
667        assert_eq!(
668            config.rabbit.client_provided_name,
669            default_client_provided_name()
670        );
671        assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
672
673        let j = r#"{ "rabbit": {"host": "example.org"} }"#;
674        let config: MyConfig = serde_json::from_str(j).unwrap();
675        assert_eq!(config.rabbit.host, "example.org".to_string());
676        assert_eq!(config.rabbit.port, default_port());
677        assert_eq!(config.rabbit.user, default_user());
678        assert_eq!(config.rabbit.password, default_password());
679        assert_eq!(config.rabbit.v_host, default_v_host());
680        assert_eq!(config.rabbit.heartbeat, default_heartbeat());
681        assert_eq!(config.rabbit.max_frame_size, default_max_frame_size());
682        assert_eq!(
683            config.rabbit.load_balancer_mode,
684            default_load_balancer_mode()
685        );
686        assert_eq!(
687            config.rabbit.client_provided_name,
688            default_client_provided_name()
689        );
690        assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
691
692        let j = r#"{ "rabbit": {"host": "example.org", "port": 5354} }"#;
693        let config: MyConfig = serde_json::from_str(j).unwrap();
694        assert_eq!(config.rabbit.host, "example.org".to_string());
695        assert_eq!(config.rabbit.port, 5354);
696        assert_eq!(config.rabbit.user, default_user());
697        assert_eq!(config.rabbit.password, default_password());
698        assert_eq!(config.rabbit.v_host, default_v_host());
699        assert_eq!(config.rabbit.heartbeat, default_heartbeat());
700        assert_eq!(config.rabbit.max_frame_size, default_max_frame_size());
701        assert_eq!(
702            config.rabbit.load_balancer_mode,
703            default_load_balancer_mode()
704        );
705        assert_eq!(
706            config.rabbit.client_provided_name,
707            default_client_provided_name()
708        );
709        assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
710
711        let j = r#"{ "rabbit": { "tls": {} } }"#;
712        let config = serde_json::from_str::<MyConfig>(j);
713        assert!(config.is_err());
714
715        let j = r#"{ "rabbit": { "tls": { "enabled": false } } }"#;
716        let config = serde_json::from_str::<MyConfig>(j).unwrap();
717        assert!(matches!(config.rabbit.tls, TlsConfiguration::Disabled));
718
719        let j = r#"{ "rabbit": { "tls": { "enabled": true } } }"#;
720        let config = serde_json::from_str::<MyConfig>(j).unwrap();
721        assert!(matches!(config.rabbit.tls, TlsConfiguration::Untrusted));
722
723        let j = r#"
724{
725    "rabbit": {
726        "tls": {
727            "enabled": true,
728            "root_certificates_path": "path"
729        }
730    }
731}"#;
732        let config = serde_json::from_str::<MyConfig>(j).unwrap();
733        assert!(matches!(
734            config.rabbit.tls,
735            TlsConfiguration::Trusted { .. }
736        ));
737        let TlsConfiguration::Trusted {
738            root_certificates_path,
739            client_certificates,
740        } = config.rabbit.tls
741        else {
742            panic!("Expected Trusted configuration")
743        };
744        assert_eq!(root_certificates_path.as_path(), Path::new("path"));
745        assert!(client_certificates.is_none());
746
747        let j = r#"
748{
749    "rabbit": {
750        "tls": {
751            "enabled": true,
752            "root_certificates_path": "path",
753            "client_certificates_path": "cert",
754            "client_private_key_path": "priv"
755        }
756    }
757}"#;
758        let config = serde_json::from_str::<MyConfig>(j).unwrap();
759        assert!(matches!(
760            config.rabbit.tls,
761            TlsConfiguration::Trusted { .. }
762        ));
763        let TlsConfiguration::Trusted {
764            root_certificates_path,
765            client_certificates,
766        } = config.rabbit.tls
767        else {
768            panic!("Expected Trusted configuration")
769        };
770        assert_eq!(root_certificates_path.as_path(), Path::new("path"));
771        let client_certificates = client_certificates.expect("Expected client certificates");
772        assert_eq!(
773            client_certificates.client_certificates_path.as_path(),
774            Path::new("cert")
775        );
776        assert_eq!(
777            client_certificates.client_private_key_path.as_path(),
778            Path::new("priv")
779        );
780    }
781
782    #[test]
783    fn test_tls_config() {
784        let j = r#"
785{}"#;
786        let config = serde_json::from_str::<TlsConfiguration>(j);
787        assert!(config.is_err());
788
789        let j = r#"
790{
791    "enabled": false
792}"#;
793        let config: TlsConfiguration = serde_json::from_str(j).unwrap();
794        assert!(matches!(config, TlsConfiguration::Disabled));
795
796        let j = r#"
797{
798    "enabled": true
799}"#;
800        let config: TlsConfiguration = serde_json::from_str(j).unwrap();
801        assert!(matches!(config, TlsConfiguration::Untrusted));
802
803        let j = r#"
804{
805    "enabled": true,
806    "root_certificates_path": "test"
807}"#;
808        let config: TlsConfiguration = serde_json::from_str(j).unwrap();
809        assert!(matches!(config, TlsConfiguration::Trusted { .. }));
810        let TlsConfiguration::Trusted {
811            root_certificates_path,
812            client_certificates,
813        } = config
814        else {
815            panic!("Expected Trusted configuration")
816        };
817        assert_eq!(root_certificates_path.as_path(), Path::new("test"));
818        assert!(client_certificates.is_none());
819
820        let j = r#"
821{
822    "enabled": true,
823    "root_certificates_path": "test",
824    "client_certificates_path": "cert"
825}"#;
826        let config = serde_json::from_str::<TlsConfiguration>(j);
827        assert!(config.is_err());
828
829        let j = r#"
830{
831    "enabled": true,
832    "root_certificates_path": "test",
833    "client_certificates_path": "cert",
834    "client_private_key_path": "priv"
835}"#;
836        let config: TlsConfiguration = serde_json::from_str(j).unwrap();
837        assert!(matches!(config, TlsConfiguration::Trusted { .. }));
838        let TlsConfiguration::Trusted {
839            root_certificates_path,
840            client_certificates,
841        } = config
842        else {
843            panic!("Expected Trusted configuration")
844        };
845        assert_eq!(root_certificates_path.as_path(), Path::new("test"));
846        let client_certificates = client_certificates.expect("Expected client certificates");
847        assert_eq!(
848            client_certificates.client_certificates_path.as_path(),
849            Path::new("cert")
850        );
851        assert_eq!(
852            client_certificates.client_private_key_path.as_path(),
853            Path::new("priv")
854        );
855    }
856}